Merge pull request #2474 from BoxyUwU/ambig_unambig_ty_consts
Document Ambig vs Unambig Type/Consts
This commit is contained in:
commit
e0a39188f1
|
|
@ -121,8 +121,9 @@
|
||||||
- [Feature gate checking](./feature-gate-ck.md)
|
- [Feature gate checking](./feature-gate-ck.md)
|
||||||
- [Lang Items](./lang-items.md)
|
- [Lang Items](./lang-items.md)
|
||||||
- [The HIR (High-level IR)](./hir.md)
|
- [The HIR (High-level IR)](./hir.md)
|
||||||
- [Lowering AST to HIR](./ast-lowering.md)
|
- [Lowering AST to HIR](./hir/lowering.md)
|
||||||
- [Debugging](./hir-debugging.md)
|
- [Ambig/Unambig Types and Consts](./hir/ambig-unambig-ty-and-consts.md)
|
||||||
|
- [Debugging](./hir/debugging.md)
|
||||||
- [The THIR (Typed High-level IR)](./thir.md)
|
- [The THIR (Typed High-level IR)](./thir.md)
|
||||||
- [The MIR (Mid-level IR)](./mir/index.md)
|
- [The MIR (Mid-level IR)](./mir/index.md)
|
||||||
- [MIR construction](./mir/construction.md)
|
- [MIR construction](./mir/construction.md)
|
||||||
|
|
|
||||||
|
|
@ -553,7 +553,7 @@ compiler](#linting-early-in-the-compiler).
|
||||||
|
|
||||||
|
|
||||||
[AST nodes]: the-parser.md
|
[AST nodes]: the-parser.md
|
||||||
[AST lowering]: ast-lowering.md
|
[AST lowering]: ./hir/lowering.md
|
||||||
[HIR nodes]: hir.md
|
[HIR nodes]: hir.md
|
||||||
[MIR nodes]: mir/index.md
|
[MIR nodes]: mir/index.md
|
||||||
[macro expansion]: macro-expansion.md
|
[macro expansion]: macro-expansion.md
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
The HIR – "High-Level Intermediate Representation" – is the primary IR used
|
The HIR – "High-Level Intermediate Representation" – is the primary IR used
|
||||||
in most of rustc. It is a compiler-friendly representation of the abstract
|
in most of rustc. It is a compiler-friendly representation of the abstract
|
||||||
syntax tree (AST) that is generated after parsing, macro expansion, and name
|
syntax tree (AST) that is generated after parsing, macro expansion, and name
|
||||||
resolution (see [Lowering](./ast-lowering.html) for how the HIR is created).
|
resolution (see [Lowering](./hir/lowering.md) for how the HIR is created).
|
||||||
Many parts of HIR resemble Rust surface syntax quite closely, with
|
Many parts of HIR resemble Rust surface syntax quite closely, with
|
||||||
the exception that some of Rust's expression forms have been desugared away.
|
the exception that some of Rust's expression forms have been desugared away.
|
||||||
For example, `for` loops are converted into a `loop` and do not appear in
|
For example, `for` loops are converted into a `loop` and do not appear in
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Ambig/Unambig Types and Consts
|
||||||
|
|
||||||
|
Types and Consts args in the HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where
|
||||||
|
it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to
|
||||||
|
parse.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn func<T, const N: usize>(arg: T) {
|
||||||
|
// ^ Unambig type position
|
||||||
|
let a: _ = arg;
|
||||||
|
// ^ Unambig type position
|
||||||
|
|
||||||
|
func::<T, N>(arg);
|
||||||
|
// ^ ^
|
||||||
|
// ^^^^ Ambig position
|
||||||
|
|
||||||
|
let _: [u8; 10];
|
||||||
|
// ^^ ^^ Unambig const position
|
||||||
|
// ^^ Unambig type position
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Most types/consts in ambig positions are able to be disambiguated as either a type or const during parsing. Single segment paths are always represented as types in the AST but may get resolved to a const parameter during name resolution, then lowered to a const argument during ast-lowering. The only generic arguments which remain ambiguous after lowering are inferred generic arguments (`_`) in path segments. For example, in `Foo<_>` it is not clear whether the `_` argument is an inferred type argument, or an inferred const argument.
|
||||||
|
|
||||||
|
In unambig positions, inferred arguments are represented with [`hir::TyKind::Infer`][ty_infer] or [`hir::ConstArgKind::Infer`][const_infer] depending on whether it is a type or const position respectively.
|
||||||
|
In ambig positions, inferred arguments are represented with `hir::GenericArg::Infer`.
|
||||||
|
|
||||||
|
A naive implementation of this would result in there being potentially 5 places where you might think an inferred type/const could be found in the HIR from looking at the structure of the HIR:
|
||||||
|
1. In unambig type position as a `hir::TyKind::Infer`
|
||||||
|
2. In unambig const arg position as a `hir::ConstArgKind::Infer`
|
||||||
|
3. In an ambig position as a [`GenericArg::Type(TyKind::Infer)`][generic_arg_ty]
|
||||||
|
4. In an ambig position as a [`GenericArg::Const(ConstArgKind::Infer)`][generic_arg_const]
|
||||||
|
5. In an ambig position as a [`GenericArg::Infer`][generic_arg_infer]
|
||||||
|
|
||||||
|
Note that places 3 and 4 would never actually be possible to encounter as we always lower to `GenericArg::Infer` in generic arg position.
|
||||||
|
|
||||||
|
This has a few failure modes:
|
||||||
|
- People may write visitors which check for `GenericArg::Infer` but forget to check for `hir::TyKind/ConstArgKind::Infer`, only handling infers in ambig positions by accident.
|
||||||
|
- People may write visitors which check for `hir::TyKind/ConstArgKind::Infer` but forget to check for `GenericArg::Infer`, only handling infers in unambig positions by accident.
|
||||||
|
- People may write visitors which check for `GenerArg::Type/Const(TyKind/ConstArgKind::Infer)` and `GenerigArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Type/Const`.
|
||||||
|
- People may write visitors which check for *only* `TyKind::Infer` and not `ConstArgKind::Infer` forgetting that there are also inferred const arguments (and vice versa).
|
||||||
|
|
||||||
|
To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system:
|
||||||
|
|
||||||
|
1. We have different types in the compiler for when a type or const is in an unambig or ambig position, `hir::Ty<AmbigArg>` and `hir::Ty<()>`. [`AmbigArg`][ambig_arg] is an uninhabited type which we use in the `Infer` variant of `TyKind` and `ConstArgKind` to selectively "disable" it if we are in an ambig position.
|
||||||
|
|
||||||
|
2. The [`visit_ty`][visit_ty] and [`visit_const_arg`][visit_const_arg] methods on HIR visitors only accept the ambig position versions of types/consts. Unambig types/consts are implicitly converted to ambig types/consts during the visiting process, with the `Infer` variant handled by a dedicated [`visit_infer`][visit_infer] method.
|
||||||
|
|
||||||
|
This has a number of benefits:
|
||||||
|
- It's clear that `GenericArg::Type/Const` cannot represent inferred type/const arguments
|
||||||
|
- Implementors of `visit_ty` and `visit_const_arg` will never encounter inferred types/consts making it impossible to write a visitor that seems to work right but handles edge cases wrong
|
||||||
|
- The `visit_infer` method handles *all* cases of inferred type/consts in the HIR making it easy for visitors to handle inferred type/consts in one dedicated place and not forget cases
|
||||||
|
|
||||||
|
[ty_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.TyKind.html#variant.Infer
|
||||||
|
[const_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.ConstArgKind.html#variant.Infer
|
||||||
|
[generic_arg_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Type
|
||||||
|
[generic_arg_const]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Const
|
||||||
|
[generic_arg_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.GenericArg.html#variant.Infer
|
||||||
|
[ambig_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.AmbigArg.html
|
||||||
|
[visit_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_ty
|
||||||
|
[visit_const_arg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_const_arg
|
||||||
|
[visit_infer]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/intravisit/trait.Visitor.html#method.visit_infer
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# AST lowering
|
# AST lowering
|
||||||
|
|
||||||
The AST lowering step converts AST to [HIR](hir.html).
|
The AST lowering step converts AST to [HIR](../hir.md).
|
||||||
This means many structures are removed if they are irrelevant
|
This means many structures are removed if they are irrelevant
|
||||||
for type analysis or similar syntax agnostic analyses. Examples
|
for type analysis or similar syntax agnostic analyses. Examples
|
||||||
of such structures include but are not limited to
|
of such structures include but are not limited to
|
||||||
|
|
@ -410,7 +410,7 @@ For more details on bootstrapping, see
|
||||||
- Guide: [The HIR](hir.md)
|
- Guide: [The HIR](hir.md)
|
||||||
- Guide: [Identifiers in the HIR](hir.md#identifiers-in-the-hir)
|
- Guide: [Identifiers in the HIR](hir.md#identifiers-in-the-hir)
|
||||||
- Guide: [The `HIR` Map](hir.md#the-hir-map)
|
- Guide: [The `HIR` Map](hir.md#the-hir-map)
|
||||||
- Guide: [Lowering `AST` to `HIR`](ast-lowering.md)
|
- Guide: [Lowering `AST` to `HIR`](./hir/lowering.md)
|
||||||
- How to view `HIR` representation for your code `cargo rustc -- -Z unpretty=hir-tree`
|
- How to view `HIR` representation for your code `cargo rustc -- -Z unpretty=hir-tree`
|
||||||
- Rustc `HIR` definition: [`rustc_hir`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html)
|
- Rustc `HIR` definition: [`rustc_hir`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html)
|
||||||
- Main entry point: **TODO**
|
- Main entry point: **TODO**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue