Advertisement
Guest User

Untitled

a guest
Oct 21st, 2019
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.85 KB | None | 0 0
  1. #[macro_export]
  2. macro_rules! assert_impl_any {
  3. ($x:ty: $($t:path),+ $(,)?) => {
  4. const _: fn() = || {
  5. use core::marker::PhantomData;
  6. use core::ops::Deref;
  7.  
  8. struct AssertAnyTraitNoTrait;
  9. let next = AssertAnyTraitNoTrait;
  10.  
  11. // Ensures that blanket traits can't impersonate the method.
  12. struct AssertAnyTraitToken;
  13. $(
  14. let next = {
  15. struct Wrapper<T, N>(PhantomData<T>, N);
  16. // If the `__static_assert__has_any_trait` method for this wrapper can't be called then
  17. // the compiler will insert a deref and try again. This forwards the compilers next
  18. // attempt to the previous wrapper.
  19. impl<T, N> Deref for Wrapper<T, N> {
  20. type Target = N;
  21. fn deref(&self) -> &Self::Target {
  22. &self.1
  23. }
  24. }
  25. // This impl has a trait bound on $x so the method can only be called if $x implements $t.
  26. impl<T: $t, N> Wrapper<T, N> {
  27. #[allow(non_snake_case)]
  28. // The `TOKEN` generic ensures that a method on a blanket trait can't be generic and therefore accept the `AssertAnyTraitToken`.
  29. fn __static_assert__has_any_trait<TOKEN>(&self, _: AssertAnyTraitToken) {}
  30. }
  31. Wrapper::<$x, _>(PhantomData, next)
  32. };
  33. )+
  34. // Attempt to find a `__static_assert__has_any_trait` method that can actually be called.
  35. next.__static_assert__has_any_trait::<()>(AssertAnyTraitToken);
  36. };
  37. };
  38. }
  39.  
  40. mod tests {
  41. #[test]
  42. fn should_compile() {
  43. assert_impl_any!((): Send, Sync);
  44. assert_impl_any!((): Send, From<u8>);
  45. }
  46.  
  47. /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  48. ///
  49. /// This tests the case with interference where the macro should normally fail. The interference still causes the macro to fail so this doesn't really matter.
  50. ///
  51. /// ```compile_fail
  52. /// use playground::assert_impl_any;
  53. ///
  54. /// trait Interfere {
  55. /// #[allow(non_snake_case)]
  56. /// fn __static_assert__has_any_trait<A>(&self, token: A) {}
  57. /// }
  58. /// impl<T> Interfere for T {}
  59. ///
  60. /// // This test would fail if this is true: These should fail to compile but the above trait interferes and causes them to actually compile anyway.
  61. /// assert_impl_any!((): From<u8>);
  62. /// assert_impl_any!((): From<u8>, From<u16>);
  63. /// ```
  64. #[allow(dead_code)]
  65. fn interference_for_fail_case() {}
  66.  
  67. /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  68. ///
  69. /// This tests the case with interference where the macro should normally succeed. The interference causes the macro to fail, this isn't really a problem since it is very unlikely that the correct trait actually exists.
  70. ///
  71. /// ```compile_fail
  72. /// use playground::assert_impl_any;
  73. ///
  74. /// trait Interfere {
  75. /// #[allow(non_snake_case)]
  76. /// fn __static_assert__has_any_trait(&self: token: ()) {}
  77. /// }
  78. /// impl<T> Interfere for T {}
  79. ///
  80. /// // These should actually compile but the above trait interferes and causes them to fail anyway.
  81. /// assert_impl_any!((): Send, Sync);
  82. /// assert_impl_any!((): Send, From<u8>);
  83. /// ```
  84. #[allow(dead_code)]
  85. fn interference_for_success_case() {}
  86.  
  87. /// A function that should fail to compile.
  88. ///
  89. /// ```compile_fail
  90. /// use playground::assert_impl_any;
  91. /// assert_impl_any!((): From<u8>);
  92. /// assert_impl_any!((): From<u8>, From<u16>);
  93. /// ```
  94. #[allow(dead_code)]
  95. fn should_fail() {}
  96. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement