@@ -94,6 +94,53 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
9494}
9595```
9696
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+
97144[ DefId ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
98145[ diagnostic_items ] : https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
99146[ 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 {
102149[ symbol ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
103150[ symbol_index ] : https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
104151[ 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
105153[ 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