Skip to content

Commit 82d71b1

Browse files
committed
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`
2 parents 592ea39 + 1cf6406 commit 82d71b1

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [Development](development/README.md)
1414
- [Basics](development/basics.md)
1515
- [Adding Lints](development/adding_lints.md)
16+
- [Type Checking](development/type_checking.md)
1617
- [Common Tools](development/common_tools_writing_lints.md)
1718
- [Infrastructure](development/infrastructure/README.md)
1819
- [Syncing changes between Clippy and rust-lang/rust](development/infrastructure/sync.md)

book/src/development/type_checking.md

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Type Checking
2+
3+
When we work on a new lint or improve an existing lint, we might want
4+
to retrieve the type `Ty` of an expression `Expr` for a variety of
5+
reasons. This can be achieved by utilizing the [`LateContext`][LateContext]
6+
that is available for [`LateLintPass`][LateLintPass].
7+
8+
## `LateContext` and `TypeckResults`
9+
10+
The lint context [`LateContext`][LateContext] and [`TypeckResults`][TypeckResults]
11+
(returned by `LateContext::typeck_results`) are the two most useful data structures
12+
in `LateLintPass`. They allow us to jump to type definitions and other compilation
13+
stages such as HIR.
14+
15+
> Note: `LateContext.typeck_results`'s return value is [`TypeckResults`][TypeckResults]
16+
> and is created in the type checking step, it includes useful information such as types of
17+
> expressions, ways to resolve methods and so on.
18+
19+
`TypeckResults` contains useful methods such as [`expr_ty`][expr_ty],
20+
which gives us access to the underlying structure [`Ty`][Ty] of a given expression.
21+
22+
```rust
23+
pub fn expr_ty(&self, expr: &Expr<'_>) -> Ty<'tcx>
24+
```
25+
26+
As a side note, besides `expr_ty`, [`TypeckResults`][TypeckResults] contains a
27+
[`pat_ty()`][pat_ty] method that is useful for retrieving a type from a pattern.
28+
29+
## `Ty`
30+
31+
`Ty` struct contains the type information of an expression.
32+
Let's take a look at `rustc_middle`'s [`Ty`][Ty] struct to examine this struct:
33+
34+
```rust
35+
pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
36+
```
37+
38+
At a first glance, this struct looks quite esoteric. But at a closer look,
39+
we will see that this struct contains many useful methods for type checking.
40+
41+
For instance, [`is_char`][is_char] checks if the given `Ty` struct corresponds
42+
to the primitive character type.
43+
44+
### `is_*` Usage
45+
46+
In some scenarios, all we need to do is check if the `Ty` of an expression
47+
is a specific type, such as `char` type, so we could write the following:
48+
49+
```rust
50+
impl LateLintPass<'_> for MyStructLint {
51+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
52+
// Get type of `expr`
53+
let ty = cx.typeck_results().expr_ty(expr);
54+
55+
// Check if the `Ty` of this expression is of character type
56+
if ty.is_char() {
57+
println!("Our expression is a char!");
58+
}
59+
}
60+
}
61+
```
62+
63+
Furthermore, if we examine the [source code][is_char_source] for `is_char`,
64+
we find something very interesting:
65+
66+
```rust
67+
#[inline]
68+
pub fn is_char(self) -> bool {
69+
matches!(self.kind(), Char)
70+
}
71+
```
72+
73+
Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us
74+
with [`TyKind`][TyKind] of a `Ty`.
75+
76+
## `TyKind`
77+
78+
`TyKind` defines the kinds of types in Rust's type system.
79+
Peeking into [`TyKind` documentation][TyKind], we will see that it is an
80+
enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc.
81+
82+
### `kind` Usage
83+
84+
The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind].
85+
We often use this method to perform pattern matching in Clippy.
86+
87+
For instance, if we want to check for a `struct`, we could examine if the
88+
`ty.kind` corresponds to an [`Adt`][Adt] (algebraic data type) and if its
89+
[`AdtDef`][AdtDef] is a struct:
90+
91+
```rust
92+
impl LateLintPass<'_> for MyStructLint {
93+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
94+
// Get type of `expr`
95+
let ty = cx.typeck_results().expr_ty(expr);
96+
// Match its kind to enter the type
97+
match ty.kind {
98+
ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"),
99+
_ => ()
100+
}
101+
}
102+
}
103+
```
104+
105+
## `hir::Ty` and `ty::Ty`
106+
107+
We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter
108+
is also important to understand.
109+
110+
`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more
111+
information).
112+
113+
**Example: `fn foo(x: u32) -> u32 { x }`**
114+
115+
Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns
116+
an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc...
117+
118+
you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty`
119+
120+
## Useful Links
121+
122+
Below are some useful links to further explore the concepts covered
123+
in this chapter:
124+
125+
- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation)
126+
- [Diagnostic items](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html)
127+
- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
128+
- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
129+
130+
[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt
131+
[AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html
132+
[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
133+
[is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char
134+
[is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834
135+
[kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind
136+
[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
137+
[LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
138+
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
139+
[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
140+
[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
141+
[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
142+
[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html
143+
[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html
144+
[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html

0 commit comments

Comments
 (0)