Advertisement
Guest User

Untitled

a guest
Oct 21st, 2019
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.96 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. assert_impl_any!((): From<u8>, From<u16>, Send);
  46. }
  47.  
  48. /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  49. ///
  50. /// 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.
  51. ///
  52. /// ```compile_fail
  53. /// use playground::assert_impl_any;
  54. ///
  55. /// trait Interfere {
  56. /// #[allow(non_snake_case)]
  57. /// fn __static_assert__has_any_trait<A>(&self, token: A) {}
  58. /// }
  59. /// impl<T> Interfere for T {}
  60. ///
  61. /// // 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.
  62. /// assert_impl_any!((): From<u8>);
  63. /// assert_impl_any!((): From<u8>, From<u16>);
  64. /// ```
  65. #[allow(dead_code)]
  66. fn interference_for_fail_case() {}
  67.  
  68. /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  69. ///
  70. /// 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.
  71. ///
  72. /// ```compile_fail
  73. /// use playground::assert_impl_any;
  74. ///
  75. /// trait Interfere {
  76. /// #[allow(non_snake_case)]
  77. /// fn __static_assert__has_any_trait(&self: token: ()) {}
  78. /// }
  79. /// impl<T> Interfere for T {}
  80. ///
  81. /// // These should actually compile but the above trait interferes and causes them to fail anyway.
  82. /// assert_impl_any!((): Send, Sync);
  83. /// assert_impl_any!((): Send, From<u8>);
  84. /// assert_impl_any!((): From<u8>, From<u16>, Send);
  85. /// ```
  86. #[allow(dead_code)]
  87. fn interference_for_success_case() {}
  88.  
  89. /// A function that should fail to compile.
  90. ///
  91. /// ```compile_fail
  92. /// use playground::assert_impl_any;
  93. /// assert_impl_any!((): From<u8>);
  94. /// assert_impl_any!((): From<u8>, From<u16>);
  95. /// ```
  96. #[allow(dead_code)]
  97. fn should_fail() {}
  98. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement