From 48b013ee6c942820e84e7da200dd6f6320663568 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:05:07 +0100 Subject: [PATCH 01/12] empty file --- src/analysis/hir-tyck.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/analysis/hir-tyck.md diff --git a/src/analysis/hir-tyck.md b/src/analysis/hir-tyck.md new file mode 100644 index 0000000000..e69de29bb2 From e996b384ed8fdad5a960499dac1c7d6adc483b4a Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:13:03 +0100 Subject: [PATCH 02/12] Some expectations writeup --- src/analysis/hir-tyck.md | 0 src/hir-typeck/expectations.md | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+) delete mode 100644 src/analysis/hir-tyck.md create mode 100644 src/hir-typeck/expectations.md diff --git a/src/analysis/hir-tyck.md b/src/analysis/hir-tyck.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md new file mode 100644 index 0000000000..d4be2d83a7 --- /dev/null +++ b/src/hir-typeck/expectations.md @@ -0,0 +1,23 @@ +# Expectations + +In an ideal world, we would only perform type inference at one point in the compiler: once all constraints have been collected. + +In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end." + +`Expectations` are a piece of type-checking state we maintain for the cases where we need to eagerly infer the types of expressions rather than leave them to the end. + +The main subjects of "eager type inference" are: + +- Method calls +- Closures (their signatures could be higher-ranked) +- Coercions +- fields +- indexing (because of weird dereferencing stuff this isn't just a Method Call) + + +## Closures and Higher-Ranked Variables + +Closures need to have type inference eagerly applied to them because [reasons]. + +Papers: +- [This one](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file From 0dbb79a718e92d5ab0fd7cb48ac01f78df67a49f Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:18:28 +0100 Subject: [PATCH 03/12] Some assertions, mostly blank space --- src/hir-typeck/expectations.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md index d4be2d83a7..e0515aba5a 100644 --- a/src/hir-typeck/expectations.md +++ b/src/hir-typeck/expectations.md @@ -2,22 +2,27 @@ In an ideal world, we would only perform type inference at one point in the compiler: once all constraints have been collected. -In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end." +In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end" when those constraints have been collected. `Expectations` are a piece of type-checking state we maintain for the cases where we need to eagerly infer the types of expressions rather than leave them to the end. -The main subjects of "eager type inference" are: +## Eager Type Checking / Inference. -- Method calls -- Closures (their signatures could be higher-ranked) -- Coercions -- fields -- indexing (because of weird dereferencing stuff this isn't just a Method Call) + +### Closures and Higher-Ranked Variables -## Closures and Higher-Ranked Variables +Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn (what_that_is: T, what_it_isnt: Y) -> bool {/* */}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]} `. -Closures need to have type inference eagerly applied to them because [reasons]. +Eager, Higher-Ranked type inference happens in closures because closures can introduce Higher-Ranked Lifetimes. `for<'a> T<'a>` is the only style of higher-ranked bound in Rust, and these can appear in the types of closures. + +### Method calls + +### Coercions + +### Fields + +### Indexing Papers: - [This one](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file From b5dafa7a758fff09f64d5f5c504cedc64b542384 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:39:50 +0100 Subject: [PATCH 04/12] More sketching --- src/hir-typeck/eager-inference.md | 1 + src/hir-typeck/expectations.md | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/hir-typeck/eager-inference.md diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md new file mode 100644 index 0000000000..894af9e527 --- /dev/null +++ b/src/hir-typeck/eager-inference.md @@ -0,0 +1 @@ +## Eager Type Inference \ No newline at end of file diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md index e0515aba5a..ada16e28eb 100644 --- a/src/hir-typeck/expectations.md +++ b/src/hir-typeck/expectations.md @@ -4,7 +4,7 @@ In an ideal world, we would only perform type inference at one point in the comp In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end" when those constraints have been collected. -`Expectations` are a piece of type-checking state we maintain for the cases where we need to eagerly infer the types of expressions rather than leave them to the end. +`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. ## Eager Type Checking / Inference. @@ -16,13 +16,22 @@ Closures need to have type inference eagerly applied to them because they are fu Eager, Higher-Ranked type inference happens in closures because closures can introduce Higher-Ranked Lifetimes. `for<'a> T<'a>` is the only style of higher-ranked bound in Rust, and these can appear in the types of closures. -### Method calls ### Coercions -### Fields +Actually yes does use expectations. + +### Method calls? + +Maybe Not. Maybe just point to [method lookup](./method-lookup.md). + +### Fields? + +Maybe Not ### Indexing +lcnr said so. + Papers: - [This one](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file From 5a7be9da4dafa4689e825223a8c60f59d2915522 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:59:55 +0100 Subject: [PATCH 05/12] Add a bunch of wrong stuff to check later --- src/hir-typeck/expectations.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md index ada16e28eb..81a082cdcd 100644 --- a/src/hir-typeck/expectations.md +++ b/src/hir-typeck/expectations.md @@ -1,4 +1,4 @@ -# Expectations +# Expectations and Eager Type Inference In an ideal world, we would only perform type inference at one point in the compiler: once all constraints have been collected. @@ -6,32 +6,42 @@ In reality, we perform it (at least) twice: First, at eager evaluation points, a `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. -## Eager Type Checking / Inference. +## Eager Type Inference +Eager evaluation of the type of a term (type inference) is required at some specific points to either make type inference more consistent or make it even possible, in the case of higher-ranked bounds / Higher Ranked Lifetime bounds. + +Eager evaluation is when we do type inference earlier than we otherwise would. To do this, we bring in Expectations. + ### Closures and Higher-Ranked Variables Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn (what_that_is: T, what_it_isnt: Y) -> bool {/* */}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]} `. Eager, Higher-Ranked type inference happens in closures because closures can introduce Higher-Ranked Lifetimes. `for<'a> T<'a>` is the only style of higher-ranked bound in Rust, and these can appear in the types of closures. +The above is only slightly true. Let's be wrong about it in more interesting ways. ### Coercions -Actually yes does use expectations. +? [Coercions](https://doc.rust-lang.org/reference/type-coercions.html) engage in eager type inference as we need to know the type of a coerced type as early as possible for some reason idk. Maybe this is fail-early stuff? Need to engage in investigation. ### Method calls? Maybe Not. Maybe just point to [method lookup](./method-lookup.md). +? Method calls engage in Coercion and therefore need to engage in Eager Type Inference. + ### Fields? -Maybe Not +? Fields engage in corcion and therefore need to engage in eager type inference. ### Indexing +? Indexing engages in coercion and therefore needs to engage in eager type inference. + lcnr said so. Papers: -- [This one](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file +- [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)] \ No newline at end of file From 5e8bfe68db912a446a23b012c5deec1b34675eb2 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:40:35 +0100 Subject: [PATCH 06/12] Can't keep fussing over this --- src/hir-typeck/expectations.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md index 81a082cdcd..560a3ded9f 100644 --- a/src/hir-typeck/expectations.md +++ b/src/hir-typeck/expectations.md @@ -4,7 +4,7 @@ In an ideal world, we would only perform type inference at one point in the comp In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end" when those constraints have been collected. -`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. +`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?" ## Eager Type Inference @@ -16,15 +16,15 @@ Eager evaluation is when we do type inference earlier than we otherwise would. T ### Closures and Higher-Ranked Variables -Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn (what_that_is: T, what_it_isnt: Y) -> bool {/* */}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]} `. +Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn is_even(number: i32) -> bool {number % 2 == 0}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]}`. -Eager, Higher-Ranked type inference happens in closures because closures can introduce Higher-Ranked Lifetimes. `for<'a> T<'a>` is the only style of higher-ranked bound in Rust, and these can appear in the types of closures. +If we didn't do eager type inference we would instead have closures whose types were filled with inference variables. This would be able to solve 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. The above is only slightly true. Let's be wrong about it in more interesting ways. -### Coercions +### Coercions -? [Coercions](https://doc.rust-lang.org/reference/type-coercions.html) engage in eager type inference as we need to know the type of a coerced type as early as possible for some reason idk. Maybe this is fail-early stuff? Need to engage in investigation. +[Coercions](./coercions.md) can happen in many places, and so we check for them and perform them when able. 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. ### Method calls? @@ -34,7 +34,9 @@ Maybe Not. Maybe just point to [method lookup](./method-lookup.md). ### Fields? -? Fields engage in corcion and therefore need to engage in eager type inference. +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 @@ -44,4 +46,6 @@ lcnr said so. 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)] \ No newline at end of file +- [Local type inference (referenced in PTIfART)] + +[^higher-ranked-inference]: \ No newline at end of file From 8eaa58595673add432d4e5da3b5e683049d32261 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:51:02 +0100 Subject: [PATCH 07/12] Link to HRIV --- src/hir-typeck/expectations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md index 560a3ded9f..db513f4b59 100644 --- a/src/hir-typeck/expectations.md +++ b/src/hir-typeck/expectations.md @@ -48,4 +48,4 @@ 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]: \ No newline at end of file +[^higher-ranked-inference]: https://github.com/rust-lang/types-team/issues/131 \ No newline at end of file From 7c2f09806291df134b1a44c6363fdb3a0952fc0f Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:17:53 +0100 Subject: [PATCH 08/12] Re-frame around eager type inference rather than expectations specifically --- src/SUMMARY.md | 1 + src/hir-typeck/eager-inference.md | 50 +++++++++++++++++++++++++++++- src/hir-typeck/expectations.md | 51 ------------------------------- 3 files changed, 50 insertions(+), 52 deletions(-) delete mode 100644 src/hir-typeck/expectations.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index bf2de84575..e68b44d373 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md index 894af9e527..43bbf407cc 100644 --- a/src/hir-typeck/eager-inference.md +++ b/src/hir-typeck/eager-inference.md @@ -1 +1,49 @@ -## Eager Type Inference \ No newline at end of file +# 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. + +Eager evaluation of the type of a term (type inference) is required at some specific points to either make later type inference more consistent or (in the case of higher-ranked bounds / Higher Ranked Lifetime bounds) make it even possible. + +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. + +### Closures and Higher-Ranked Variables + +Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn is_even(number: i32) -> bool {number % 2 == 0}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]}`. + +If we didn't do eager type inference we would instead have closures whose types were filled with inference variables. This would be able to solve 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. + +The above is only slightly true. Let's be wrong about it in more interesting ways. + +### Coercions + +[Coercions](./coercions.md) can happen in many places, and so we check for them and perform them when able. 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. + +## 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?" + +### Method calls, Fields, and Indexes. + +These are areas which technically take expectations, but in practice use them for + +Maybe Not. Maybe just point to [method lookup](./method-lookup.md). + +? Method calls engage in Coercion and therefore need to engage in Eager Type Inference. + +### Fields? + +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. + +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 \ No newline at end of file diff --git a/src/hir-typeck/expectations.md b/src/hir-typeck/expectations.md deleted file mode 100644 index db513f4b59..0000000000 --- a/src/hir-typeck/expectations.md +++ /dev/null @@ -1,51 +0,0 @@ -# Expectations and Eager Type Inference - -In an ideal world, we would only perform type inference at one point in the compiler: once all constraints have been collected. - -In reality, we perform it (at least) twice: First, at eager evaluation points, and secondly "at the end" when those constraints have been collected. - -`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?" - -## Eager Type Inference - - - -Eager evaluation of the type of a term (type inference) is required at some specific points to either make type inference more consistent or make it even possible, in the case of higher-ranked bounds / Higher Ranked Lifetime bounds. - -Eager evaluation is when we do type inference earlier than we otherwise would. To do this, we bring in Expectations. - -### Closures and Higher-Ranked Variables - -Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn is_even(number: i32) -> bool {number % 2 == 0}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]}`. - -If we didn't do eager type inference we would instead have closures whose types were filled with inference variables. This would be able to solve 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. - -The above is only slightly true. Let's be wrong about it in more interesting ways. - -### Coercions - -[Coercions](./coercions.md) can happen in many places, and so we check for them and perform them when able. 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. - -### Method calls? - -Maybe Not. Maybe just point to [method lookup](./method-lookup.md). - -? Method calls engage in Coercion and therefore need to engage in Eager Type Inference. - -### Fields? - -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. - -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 \ No newline at end of file From 63acfd011e6a98bcb8668f3181d11a71a0185a56 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Wed, 29 Jul 2026 09:14:06 +0100 Subject: [PATCH 09/12] Some rewording --- src/hir-typeck/eager-inference.md | 39 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md index 43bbf407cc..b4efa30b0e 100644 --- a/src/hir-typeck/eager-inference.md +++ b/src/hir-typeck/eager-inference.md @@ -8,40 +8,59 @@ Eager type inference is when we do type inference earlier than we otherwise woul ### Closures and Higher-Ranked Variables -Closures need to have type inference eagerly applied to them because they are functions that are rarely fully annotated. Top-level functions i.e. `fn is_even(number: i32) -> bool {number % 2 == 0}` have their input / output types fully defined (opaque types still being an explicit annotation) but closures tend to have most/all of their type annotations missing, like `|a, b| if a < b {vec![1, 2, 3]} else {vec![6, 7, 8]}`. +Top-level functions, such as the following, have their types fully annotated at their definition site: -If we didn't do eager type inference we would instead have closures whose types were filled with inference variables. This would be able to solve 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. +```rust +fn is_even(number: i32) -> bool { + number % 2 == 0 +} +``` -The above is only slightly true. Let's be wrong about it in more interesting ways. +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`. -### Coercions +_Closures_ need to have type inference eagerly applied to them because they are functions that are rarely fully annotated: -[Coercions](./coercions.md) can happen in many places, and so we check for them and perform them when able. 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. +```rust +let closure = |a, b| if a < b {vec![1, 2, 3]} else {vec![5, 6, 7]}; +``` -## Expectations +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). -`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?" +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. + +### 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. ### Method calls, Fields, and Indexes. -These are areas which technically take expectations, but in practice use them for +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). ? Method calls engage in Coercion and therefore need to engage in Eager Type Inference. -### Fields? +#### Fields? 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 ? 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)] From 40263ec7555a1e9f7189bcdf7a034ccd9ca86ea6 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:42:12 +0100 Subject: [PATCH 10/12] Pushing for review purposes --- src/hir-typeck/eager-inference.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md index b4efa30b0e..a550b428dc 100644 --- a/src/hir-typeck/eager-inference.md +++ b/src/hir-typeck/eager-inference.md @@ -2,7 +2,9 @@ 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. -Eager evaluation of the type of a term (type inference) is required at some specific points to either make later type inference more consistent or (in the case of higher-ranked bounds / Higher Ranked Lifetime bounds) make it even possible. +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. @@ -24,18 +26,30 @@ _Closures_ need to have type inference eagerly applied to them because they are 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). +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. +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. +? 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. +? This bucket of stuff should be changed. + These are areas which technically take expectations, but in practice use them for diagnostics only. #### Methods From a5d0f0d793854fac04d9f162caf6c4a3e77d3ff8 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Fri, 28 Aug 2026 17:50:05 +0100 Subject: [PATCH 11/12] Current state of inference structure etc. --- src/hir-typeck/eager-inference.md | 83 ++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 7 deletions(-) diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md index a550b428dc..2b6b56924c 100644 --- a/src/hir-typeck/eager-inference.md +++ b/src/hir-typeck/eager-inference.md @@ -2,12 +2,70 @@ 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. +Depending on the Current State of Inference means _we pay attention to the set of constraints we currently have_ even if we've not finished finding all constraints yet. See: ["Current State of Inference"](#current-state-of-inference). 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. +## Current State of Inference + +The "Current State of Inference" is a set of ongoing context state that may not yet be "complete." This is a set of information we care about while performing type inference and checking. + +### Inference Variables + +Knowledge about what inference variables are currently resolved to. When we first introduce a variable, we give it an inference variable. + +```rust +let x = ...; +--- +// At initialization. +x: ?a; +?a = not known; +// Maybe later? +?a = Vec; +// And later still +?a = Vec; +``` + +Each time we look up `?a` we are accessing this part of the current state of inference. + +### Expectations + +We _expect_ that a subject will have a given type, but we have not yet assigned this to its inference variables. + +We may have knowledge about what an expression's type _should_ be before we further constrain the inference variable associated with it. Consider the following: + +```rust +// fn(u32) -> bool +fn north(a: u32) -> bool { + a > 2000 +} + +// Has the type ?a, an inference variable. +let x = ...; +// Introduces "x: u32" and "result: bool" as expectations. +let result = north(x); +--- +x: ?a; +result: ?b; +// These have not yet been assigned to ?a ?b respectively. But we do know we +// will need to reconcile these with ?a and ?b in the short term. +expect x: u32; +expect result: bool; +// Then we type check and infer +``` + +These pieces of information have not yet been canonized as "things an inference variable _is_" the same way we might be able to look up what `?x` currently maps to in the current state of inference. + +### Constraints + +This is the set of constraints that need to be solved. We collect these constraints as we move through the codebase being type checked. + +## Places Where Eager Inference Happens + +Eager inference is very common. + ### Closures and Higher-Ranked Variables Top-level functions, such as the following, have their types fully annotated at their definition site: @@ -16,6 +74,9 @@ Top-level functions, such as the following, have their types fully annotated at fn is_even(number: i32) -> bool { number % 2 == 0 } +--- +// We don't have to infer this, it's annotated. +is_even: fn(i32) -> bool ``` 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`. @@ -24,15 +85,19 @@ _Closures_ need to have type inference eagerly applied to them because they are ```rust let closure = |a, b| if a < b {vec![1, 2, 3]} else {vec![5, 6, 7]}; +--- +// Doesn't capture any information so it's a bare function pointer +// but we still don't know much about it. +closure: fn(?x, ?y) -> ?z ``` -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). +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) (like the `?x, ?y, ?z` variables above). -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. +Eagerly inferring the type of `closure` here serves a couple of purposes. Firstly, it's a decent heuristic that if we define a closure we'll use it later and having its type be known will mean a less intense inference solve. Having eagerly inferred the type of a closure lets us establish [Expectations](#expectations) that don't have inference variables in them. -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. +Secondly, functions can introduce Higher-Ranked Bounds for lifetimes. Inferring the types for a closure that uses higher-ranked bounds **requires** us to do work earlier, as part of the bidirectional () type checking algorithm we use. -? TODO: higher-ranked inference, but more. Go over notes. +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. ### Coercions @@ -44,7 +109,7 @@ When we successfully find a coercion, we need to eagerly perform type inference/ ### Trait Solving -Trait solving happens in a +Trait solving can be run on a [`TyKind`][tykind] during at any point. Failure is recoverable, so we can repeat this operation, but if at the end of an Item we can't establish if a type implements a trait then we error. ### Method calls, Fields, and Indexes. @@ -79,4 +144,8 @@ 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 \ No newline at end of file +--- + +[tykind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/type.TyKind.html +[^higher-ranked-inference]: https://github.com/rust-lang/types-team/issues/131 +[^practical]: [Practical Type Inference for Arbitrary-Rank Types, Jones et al 2007](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file From 855f60cbf682b7b7edba3ed86111c9fedef2e01b Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:15:55 +0100 Subject: [PATCH 12/12] Major editing pass --- src/hir-typeck/eager-inference.md | 67 +++++++++++-------------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/src/hir-typeck/eager-inference.md b/src/hir-typeck/eager-inference.md index 2b6b56924c..665c05baf4 100644 --- a/src/hir-typeck/eager-inference.md +++ b/src/hir-typeck/eager-inference.md @@ -1,6 +1,6 @@ # 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. +There are places during type checking where we need to depend on the "current state of inference." This means we need to establish the type of a term earlier than we otherwise would, making it _eager_ inference. Depending on the Current State of Inference means _we pay attention to the set of constraints we currently have_ even if we've not finished finding all constraints yet. See: ["Current State of Inference"](#current-state-of-inference). @@ -12,9 +12,11 @@ Eager type inference is when we do type inference earlier than we otherwise woul The "Current State of Inference" is a set of ongoing context state that may not yet be "complete." This is a set of information we care about while performing type inference and checking. +In practical terms, accessing the current state of inference usually means accessing [`InferCtxtInner`][inferctxtinner] + ### Inference Variables -Knowledge about what inference variables are currently resolved to. When we first introduce a variable, we give it an inference variable. +Knowledge about what inference variables are currently resolved to. When we first introduce a variable, we give it an inference variable. This is a number of fields of [`InferCtxtInner`][inferctxtinner], but in the general case it's [`InferCtxtInner::type_variable_storage`][inferctxtinner-tyvars]. ```rust let x = ...; @@ -28,11 +30,11 @@ x: ?a; ?a = Vec; ``` -Each time we look up `?a` we are accessing this part of the current state of inference. +Each time we look up what `?a` currently is we are accessing this part of the Current State of Inference. ### Expectations -We _expect_ that a subject will have a given type, but we have not yet assigned this to its inference variables. +[Expectations][expectation] are an additional piece of typing context that shows we _expect_ that a subject will have a given type, but we have not yet assigned applied this to the inference variables for that subject. We may have knowledge about what an expression's type _should_ be before we further constrain the inference variable associated with it. Consider the following: @@ -47,6 +49,7 @@ let x = ...; // Introduces "x: u32" and "result: bool" as expectations. let result = north(x); --- +// Regular inference variables x: ?a; result: ?b; // These have not yet been assigned to ?a ?b respectively. But we do know we @@ -95,57 +98,33 @@ If we didn't do eager type inference we would instead have closures whose types Eagerly inferring the type of `closure` here serves a couple of purposes. Firstly, it's a decent heuristic that if we define a closure we'll use it later and having its type be known will mean a less intense inference solve. Having eagerly inferred the type of a closure lets us establish [Expectations](#expectations) that don't have inference variables in them. -Secondly, functions can introduce Higher-Ranked Bounds for lifetimes. Inferring the types for a closure that uses higher-ranked bounds **requires** us to do work earlier, as part of the bidirectional () type checking algorithm we use. +Secondly, functions can introduce Higher-Ranked Bounds for lifetimes. Inferring the types for a closure that uses higher-ranked bounds **requires** us to do work earlier, as part of the bidirectional[^jonesetal2007] type checking algorithm we use. 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. -### 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. - -? TODO: Coercions are found by eager inference, this is the other way round to what is currently written. - ### Trait Solving -Trait solving can be run on a [`TyKind`][tykind] during at any point. Failure is recoverable, so we can repeat this operation, but if at the end of an Item we can't establish if a type implements a trait then we error. - -### Method calls, Fields, and Indexes. - -? 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). - -? Method calls engage in Coercion and therefore need to engage in Eager Type Inference. - -#### Fields? - -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. +Trait solving can be run on a [`TyKind`][tykind] at any point. Failure is recoverable, so we can repeat this operation, but if at the end of an Item we can't establish if a type implements a trait then we error. +### Coercions -## Expectations +[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. -`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?" +TODO: Stub, relationship to eager inference is not well established. -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)] +TODO: Following are stubs, need to determine if these are relevant to bring up. +- **Methods**: + - See: [method lookup](./method-lookup.md) +- **Fields**: + - 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. +- **Indexes**: + Indexing engages in coercion and therefore needs to engage in eager type inference. --- +[expectation]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_hir_typeck/expectation/enum.Expectation.html +[inferctxtinner]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_infer/infer/struct.InferCtxtInner.html +[inferctxtinner-tyvars]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_infer/infer/struct.InferCtxtInner.html#structfield.type_variable_storage [tykind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/type.TyKind.html [^higher-ranked-inference]: https://github.com/rust-lang/types-team/issues/131 -[^practical]: [Practical Type Inference for Arbitrary-Rank Types, Jones et al 2007](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file +[^jonesetal2007]: [Practical Type Inference for Arbitrary-Rank Types, Jones et al 2007](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/putting.pdf) \ No newline at end of file