Skip to content

Commit 77deeae

Browse files
committed
Write chapter on Unambig vs Ambig Types/Consts
1 parent 68124e5 commit 77deeae

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed
Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
1-
# Ambig/Unambig Types and Consts
1+
# Ambig/Unambig Types and Consts
2+
3+
Types and Consts args in the HIR can be in two kinds of positions "ambig" or "unambig". Ambig positions are where
4+
it would be valid to parse either a type or a const, unambig positions are where only one kind would be valid to
5+
parse.
6+
7+
```rust
8+
fn func<T, const N: usize,>(arg: T) {
9+
// ^ Unambig type position
10+
let a: _ = arg;
11+
// ^ Unambig type position
12+
13+
func::<T, N>(arg);
14+
// ^ ^
15+
// ^^^^ Ambig position
16+
17+
let _: [u8; 10];
18+
// ^^ ^^ Unambig const position
19+
// ^^ Unambig type position
20+
}
21+
22+
```
23+
24+
Most types/consts in ambig positions are able to be disambiguated as either a type or const during either parsing or ast-lowering.
25+
Currently the only exception to this is inferred generic arguments in path segments. In `Foo<_>` it is not clear whether the `_` argument is an
26+
inferred type argument, or an inferred const argument.
27+
28+
In unambig positions, inferred arguments are represented with `hir::TyKind::Infer` or `hir::ConstArgKind::Infer` depending on whether it is a type or const position respectively.
29+
In ambig positions, inferred arguments are represented with `hir::GenericArg::Infer`.
30+
31+
A naive implementation of this structure would result in there being potentially 5 places where an inferred type/const could be found in the HIR if you just looked at the types:
32+
- In unambig type position as a `hir::TyKind::Infer`
33+
- In unambig const arg position as a `hir::ConstArgKind::Infer`
34+
- In an ambig position as a `GenericArg::Ty(TyKind::Infer)`
35+
- In an ambig position as a `GenericArg::Const(ConstArgKind::Infer)`
36+
- In an ambig position as a `GenericArg::Infer`
37+
38+
This has a few failure modes:
39+
- 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.
40+
- 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.
41+
- People may write visitors which check for `GenerArg::Ty/Const(TyKind/ConstArgKind::Infer)` and `GenerigArg::Infer`, not realising that we never represent inferred types/consts in ambig positions as a `GenericArg::Ty/Const`.
42+
- 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).
43+
44+
To make writing HIR visitors less error prone when caring about inferred types/consts we have a relatively complex system:
45+
46+
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` 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.
47+
48+
2. The `visit_ty` and `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` method.
49+
50+
This has a number of benefits:
51+
- It's clear that `GenericArg::Ty/Const` cannot represent inferred type/const arguments
52+
- 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
53+
- 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

0 commit comments

Comments
 (0)