-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #10605 - blyxyas:book-type_checking, r=llogiq
Clippy Book Chapter Updates Reborn: Type Checking This PR adds a new chapter to the book: "Type Checking", it hasn't changed a lot from the source mainly because there wasn't many reviews on it and I haven't see a lot of things that needed a change. ## Notes - I have some doubts about the whole "`is_*` Usage" section, what do you think about it. - For discussion about the whole project, please use the tracking issue for the project #10597 (It also contains a timeline, discussions, and more information) changelog: Add a new "Type Checking" chapter to the book r? `@flip1995`
- Loading branch information
Showing
2 changed files
with
145 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
# Type Checking | ||
|
||
When we work on a new lint or improve an existing lint, we might want | ||
to retrieve the type `Ty` of an expression `Expr` for a variety of | ||
reasons. This can be achieved by utilizing the [`LateContext`][LateContext] | ||
that is available for [`LateLintPass`][LateLintPass]. | ||
|
||
## `LateContext` and `TypeckResults` | ||
|
||
The lint context [`LateContext`][LateContext] and [`TypeckResults`][TypeckResults] | ||
(returned by `LateContext::typeck_results`) are the two most useful data structures | ||
in `LateLintPass`. They allow us to jump to type definitions and other compilation | ||
stages such as HIR. | ||
|
||
> Note: `LateContext.typeck_results`'s return value is [`TypeckResults`][TypeckResults] | ||
> and is created in the type checking step, it includes useful information such as types of | ||
> expressions, ways to resolve methods and so on. | ||
`TypeckResults` contains useful methods such as [`expr_ty`][expr_ty], | ||
which gives us access to the underlying structure [`Ty`][Ty] of a given expression. | ||
|
||
```rust | ||
pub fn expr_ty(&self, expr: &Expr<'_>) -> Ty<'tcx> | ||
``` | ||
|
||
As a side note, besides `expr_ty`, [`TypeckResults`][TypeckResults] contains a | ||
[`pat_ty()`][pat_ty] method that is useful for retrieving a type from a pattern. | ||
|
||
## `Ty` | ||
|
||
`Ty` struct contains the type information of an expression. | ||
Let's take a look at `rustc_middle`'s [`Ty`][Ty] struct to examine this struct: | ||
|
||
```rust | ||
pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>); | ||
``` | ||
|
||
At a first glance, this struct looks quite esoteric. But at a closer look, | ||
we will see that this struct contains many useful methods for type checking. | ||
|
||
For instance, [`is_char`][is_char] checks if the given `Ty` struct corresponds | ||
to the primitive character type. | ||
|
||
### `is_*` Usage | ||
|
||
In some scenarios, all we need to do is check if the `Ty` of an expression | ||
is a specific type, such as `char` type, so we could write the following: | ||
|
||
```rust | ||
impl LateLintPass<'_> for MyStructLint { | ||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | ||
// Get type of `expr` | ||
let ty = cx.typeck_results().expr_ty(expr); | ||
|
||
// Check if the `Ty` of this expression is of character type | ||
if ty.is_char() { | ||
println!("Our expression is a char!"); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Furthermore, if we examine the [source code][is_char_source] for `is_char`, | ||
we find something very interesting: | ||
|
||
```rust | ||
#[inline] | ||
pub fn is_char(self) -> bool { | ||
matches!(self.kind(), Char) | ||
} | ||
``` | ||
|
||
Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us | ||
with [`TyKind`][TyKind] of a `Ty`. | ||
|
||
## `TyKind` | ||
|
||
`TyKind` defines the kinds of types in Rust's type system. | ||
Peeking into [`TyKind` documentation][TyKind], we will see that it is an | ||
enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc. | ||
|
||
### `kind` Usage | ||
|
||
The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind]. | ||
We often use this method to perform pattern matching in Clippy. | ||
|
||
For instance, if we want to check for a `struct`, we could examine if the | ||
`ty.kind` corresponds to an [`Adt`][Adt] (algebraic data type) and if its | ||
[`AdtDef`][AdtDef] is a struct: | ||
|
||
```rust | ||
impl LateLintPass<'_> for MyStructLint { | ||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | ||
// Get type of `expr` | ||
let ty = cx.typeck_results().expr_ty(expr); | ||
// Match its kind to enter the type | ||
match ty.kind { | ||
ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), | ||
_ => () | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## `hir::Ty` and `ty::Ty` | ||
|
||
We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter | ||
is also important to understand. | ||
|
||
`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more | ||
information). | ||
|
||
**Example: `fn foo(x: u32) -> u32 { x }`** | ||
|
||
Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns | ||
an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... | ||
|
||
you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty` | ||
|
||
## Useful Links | ||
|
||
Below are some useful links to further explore the concepts covered | ||
in this chapter: | ||
|
||
- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation) | ||
- [Diagnostic items](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html) | ||
- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) | ||
- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) | ||
|
||
[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt | ||
[AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html | ||
[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty | ||
[is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char | ||
[is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834 | ||
[kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind | ||
[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html | ||
[LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html | ||
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty | ||
[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html | ||
[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html | ||
[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html | ||
[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html | ||
[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html | ||
[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html |