@@ -94,6 +94,53 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
94
94
}
95
95
```
96
96
97
+ ## Creating Types Programmatically
98
+
99
+ Traits are often generic over a type parameter, e.g. ` Borrow<T> ` is generic
100
+ over ` T ` . Rust allows us to implement a trait for a specific type. For example,
101
+ we can implement ` Borrow<[u8]> ` for a hypothetical type ` Foo ` . Let's suppose
102
+ that we would like to find whether our type actually implements ` Borrow<[u8]> ` .
103
+
104
+ To do so, we can use the same ` implements_trait ` function as above, and supply
105
+ a type parameter that represents ` [u8] ` . Since ` [u8] ` is a specialization of
106
+ ` [T] ` , we can use the [ ` Ty::new_slice ` ] [ new_slice ] method to create a type
107
+ that represents ` [T] ` and supply ` u8 ` as a type parameter.
108
+ To create a ` ty::Ty ` programmatically, we rely on ` Ty::new_* ` methods. These
109
+ methods create a ` TyKind ` and then wrap it in a ` Ty ` struct. This means we
110
+ have access to all the primitive types, such as ` Ty::new_char ` ,
111
+ ` Ty::new_bool ` , ` Ty::new_int ` , etc. We can also create more complex types,
112
+ such as slices, tuples, and references out of these basic building blocks.
113
+
114
+ For trait checking, it is not enough to create the types, we need to convert
115
+ them into [ GenericArg] . In rustc, a generic is an entity that the compiler
116
+ understands and has three kinds, type, const and lifetime. By calling
117
+ ` .into() ` on a constructed [ Ty] , we wrap the type into a generic which can
118
+ then be used by the query system to decide whether the specialized trait
119
+ is implemented.
120
+
121
+ The following code demonstrates how to do this:
122
+
123
+ ``` rust
124
+
125
+ use rustc_middle :: ty :: Ty ;
126
+ use clippy_utils :: ty :: implements_trait;
127
+ use rustc_span :: symbol :: sym;
128
+
129
+ let ty = todo! (" Get the `Foo` type to check for a trait implementation" );
130
+ let borrow_id = cx . tcx. get_diagnostic_item (sym :: Borrow ). unwrap (); // avoid unwrap in real code
131
+ let slice_of_bytes_t = Ty :: new_slice (cx . tcx, cx . tcx. types. u8 );
132
+ let generic_param = slice_of_bytes_t . into ();
133
+ if implements_trait (cx , ty , borrow_id , & [generic_param ]) {
134
+ todo! (" Rest of lint implementation" )
135
+ }
136
+ ```
137
+
138
+ In essence, the [ Ty] struct allows us to create types programmatically in a
139
+ representation that can be used by the compiler and the query engine. We then
140
+ use the ` rustc_middle::Ty ` of the type we are interested in, and query the
141
+ compiler to see if it indeed implements the trait we are interested in.
142
+
143
+
97
144
[ DefId ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
98
145
[ diagnostic_items ] : https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
99
146
[ lang_items ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/lang_items/struct.LanguageItems.html
@@ -102,4 +149,7 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
102
149
[ symbol ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
103
150
[ symbol_index ] : https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
104
151
[ TyCtxt ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
152
+ [ Ty ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
105
153
[ rust ] : https://github.com/rust-lang/rust
154
+ [ new_slice ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.new_slice
155
+ [ GenericArg ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.GenericArg.html
0 commit comments