address review comments

This commit is contained in:
Quinn Sinclair 2024-03-03 18:12:10 +01:00
parent 8c5afd496b
commit 19c2aba3e9
2 changed files with 26 additions and 16 deletions

View file

@ -102,10 +102,23 @@ we can implement `Borrow<[u8]>` for a hypothetical type `Foo`. Let's suppose
that we would like to find whether our type actually implements `Borrow<[u8]>`.
To do so, we can use the same `implements_trait` function as above, and supply
a parameter type that represents `[u8]`. Since `[u8]` is a specialization of
a type parameter that represents `[u8]`. Since `[u8]` is a specialization of
`[T]`, we can use the [`Ty::new_slice`][new_slice] method to create a type
that represents `[T]` and supply `u8` as a type parameter. The following code
demonstrates how to do this:
that represents `[T]` and supply `u8` as a type parameter.
To create a `ty::Ty` programmatically, we rely on `Ty::new_*` methods. These
methods create a `TyKind` and then wrap it in a `Ty` struct. This means we
have access to all the primitive types, such as `Ty::new_char`,
`Ty::new_bool`, `Ty::new_int`, etc. We can also create more complex types,
such as slices, tuples, and references out of these basic building blocks.
For trait checking, it is not enough to create the types, we need to convert
them into [GenericArg]. In rustc, a generic is an entity that the compiler
understands and has three kinds, type, const and lifetime. By calling
`.into()` on a constructed [Ty], we wrap the type into a generic which can
then be used by the query system to decide whether the specialized trait
is implemented.
The following code demonstrates how to do this:
```rust
@ -115,14 +128,14 @@ use rustc_span::symbol::sym;
let ty = todo!("Get the `Foo` type to check for a trait implementation");
let borrow_id = cx.tcx.get_diagnostic_item(sym::Borrow).unwrap(); // avoid unwrap in real code
let slice_bytes = Ty::new_slice(cx.tcx, cx.tcx.types.u8);
let generic_param = slice_bytes.into();
let slice_of_bytes_t = Ty::new_slice(cx.tcx, cx.tcx.types.u8);
let generic_param = slice_of_bytes_t.into();
if implements_trait(cx, ty, borrow_id, &[generic_param]) {
todo!("Rest of lint implementation")
}
```
In essence, the [`Ty`] struct allows us to create types programmatically in a
In essence, the [Ty] struct allows us to create types programmatically in a
representation that can be used by the compiler and the query engine. We then
use the `rustc_middle::Ty` of the type we are interested in, and query the
compiler to see if it indeed implements the trait we are interested in.
@ -136,6 +149,7 @@ compiler to see if it indeed implements the trait we are interested in.
[symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html
[symbol_index]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
[`Ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
[rust]: https://github.com/rust-lang/rust
[new_slice]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.new_slice
[GenericArg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.GenericArg.html

View file

@ -125,15 +125,8 @@ the [`TypeckResults::node_type()`][node_type] method inside of bodies.
## Creating Types programmatically
A common usecase for creating types programmatically is when we want to check if a type implements a trait. We have
a section on this in the [Trait Checking](trait_checking.md) chapter, but given the importance of this topic, we will
also cover it a bit here.
When we refer to "type" in this context, we refer to `ty::Ty`. To create a `ty::Ty` programmatically, we rely on
`Ty::new_*` methods. These methods create a `TyKind` and then wrap it in a `Ty` struct.
This means we have access to all the primitive types, such as `Ty::new_char`, `Ty::new_bool`, `Ty::new_int`, etc.
We can also create more complex types, such as slices, tuples, and references.
A common usecase for creating types programmatically is when we want to check if a type implements a trait (see
[Trait Checking](trait_checking.md)).
Here's an example of how to create a `Ty` for a slice of `u8`, i.e. `[u8]`
@ -143,6 +136,9 @@ use rustc_middle::ty::Ty;
let ty = Ty::new_slice(cx.tcx, Ty::new_u8());
```
In general, we rely on `Ty::new_*` methods. These methods define the basic building-blocks that the
type-system and trait-system use to define and understand the written code.
## Useful Links
Below are some useful links to further explore the concepts covered