Skip to content
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
- [Coherence checking](./coherence.md)
- [HIR Type checking](./hir-typeck/summary.md)
- [Coercions](./hir-typeck/coercions.md)
- [Eager Inference](./hir-typeck/eager-inference.md)
- [Method lookup](./hir-typeck/method-lookup.md)
- [Const Generics](./const-generics.md)
- [Opaque types](./opaque-types-type-alias-impl-trait.md)
Expand Down
82 changes: 82 additions & 0 deletions src/hir-typeck/eager-inference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Eager Type Inference

There are places during compilation where we need to depend on the current state of inference. This means we need to establish the type of a {term, item, etc, figure out exact wording in review} earlier than we otherwise would.

Depending on the current state of inference means _we pay attention to the set constraints we currently have_ even if we've not finished finding all constraints yet.

Eager evaluation of the type of a term (type inference) is required at specific points either to make later type inference more consistent or (in the case of higher-ranked bounds / Higher Ranked Lifetime bounds) make it possible at all.

Eager type inference is when we do type inference earlier than we otherwise would. To do this, we bring in Expectations as an additional piece of context.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general structural thing I think it would be nice to talk about like "the ways we can handle places that care about the current inference state" and sort of talk abstractly about:

  • we can defer it to arbitrary points during type inference (trait solving works like this)
  • we can eagerly error on inference variables
  • we can defer it to the end of typeck after everything has been inferred (array repeat expr checks do this)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • re: trait solver doing this: Does this behave differently between the current and next trait solver? And is that a relevant thing for me to bring up :p

### Closures and Higher-Ranked Variables

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i kind of want to add trait solving to the list of "eager inference points" in that they're still part of the general "sometimes we do things which cares about the current inference state" its just that "trait" solving is how we handle that correctly instead of jankily


Top-level functions, such as the following, have their types fully annotated at their definition site:

```rust
fn is_even(number: i32) -> bool {
number % 2 == 0
}
```

This makes inference at points where they're used relatively easy. We know it's a `fn(i32) -> bool`, so when we give it an `i32` we know the expression is a `bool`.

_Closures_ need to have type inference eagerly applied to them because they are functions that are rarely fully annotated:

```rust
let closure = |a, b| if a < b {vec![1, 2, 3]} else {vec![5, 6, 7]};
```

If we didn't do eager type inference we would instead have closures whose types were filled with [inference variables](../appendix/glossary.md#inf-var).

This would be able to be solved in some situations, but because we do not have Higher-Ranked Inference Variables[^higher-ranked-inference] this would make the higher-ranked bounds for lifetimes that rust can have unusable without more annotation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the other reason we care about this is that if you have fn(?x) -> ?y as your closure signature then you can't do field accesses/method calls/etc on ?x which is a quite common thing to want to do

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think more generally we want to talk about how inferring higher ranked things is eager, and there are two main places this happens:

  • inferring higher ranked closure signatures
  • subtyping of higher ranked types


Another reason we infer eagerly for closures is that it's a good heuristic: We will need to know the types of the closure if it's used anywhere, so it is best to figure out what it is sooner.

? TODO: higher-ranked inference, but more. Go over notes.

### Coercions

[Coercions](./coercions.md) can happen in many places. We check to see if a coercion can happen, and if it can we perform the coercion.

When we successfully find a coercion, we need to eagerly perform type inference/checking on it as future inference will require or benefit from this information to be known ahead of time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know what this sentence is saying 🤔 it also feels a bit backwards to me because once we've "successfully found a coercion" then we've already done "eager type inference" because finding a coercion is the thing that cares about the current state of inference :3


? TODO: Coercions are found by eager inference, this is the other way round to what is currently written.

### Trait Solving

Trait solving happens in a

### Method calls, Fields, and Indexes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

structuring this as

  • Closures
  • Coercions
  • Other stuff

feels slightly off to me as I feel like it places too much importance on the expectation vs non expectation distinction between cases of eager type inference

I feel like I would prefer just a flat list of all the places that are eager type inference spots


? This bucket of stuff should be changed.

These are areas which technically take expectations, but in practice use them for diagnostics only.

#### Methods

Maybe Not. Maybe just point to [method lookup](./method-lookup.md).

@BoxyUwU BoxyUwU Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely want to talk about methods :3

I think for each item (e.g. coercions, closures, fields, etc) here we want to cover:

  • Why it is an eager inference spot
  • How we handle it being an eager inference spot (we would probably talk about "hey we use expectations" here if we do)
  • Why we handle it the way we do

for methods this is probably:

  • method lookup is an eager inference spot because we need to look at the type of the receiver to determine what methods exist
  • we handle this by erroring if there are inference variables which prevent us from figuring out all the methods we might be able to call
  • we could move this into the trait solver but it'd complicate things quite a lot and hasn't really been necessary to do so (so mostly historical reasons).


? Method calls engage in Coercion and therefore need to engage in Eager Type Inference.

#### Fields?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely want to talk about field accesses :3 its mostly the same reasoning as methods


Field access is inherently typed, so when we are doing field access we want to be able to know what a type is as early as possible.

? There might be something about deref here idk.

#### Indexing

? Indexing engages in coercion and therefore needs to engage in eager type inference.

lcnr said so.


## Expectations

`Expectations` are a piece of type inference state we maintain for the cases where we need to eagerly infer the types of expressions rather than leave them to the end. They allow us to "ask questions" of the form "hey, we're expecting this term to have this type, is this true?"

Papers:
- [Practical Type Inference for Arbitrary-Rank Types, Jones ](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf)
- [Local type inference (referenced in PTIfART)]

[^higher-ranked-inference]: https://github.com/rust-lang/types-team/issues/131
Loading