Skip to content

Commit 295be8b

Browse files
committed
More detail on the fallback algorithm, solve unresolved question
1 parent 92b7dd9 commit 295be8b

File tree

1 file changed

+14
-8
lines changed

1 file changed

+14
-8
lines changed

text/0000-default-type-parameter-fallback-take-two.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ This would currently result in inference failures when trying to do `assert_ne!(
176176

177177
# Guide-level explanation
178178

179-
When writing Rust code, you may find that you'd like to make a functionality more generic. But that does not always play well with inference, leading to an error like "type annotations needed" or "the type of this value must be known in this context". Say you have the following function that prints the path to a file, if it was provided:
179+
When writing Rust code, you may find that you'd like to make a functionality more generic. But that does not always play well with inference, leading to an error like "type annotations needed". Say you have the following function that prints the path to a file, if it was provided:
180180

181181
```rust
182182
use std::path::Path;
@@ -229,7 +229,7 @@ Which tells inference to use `String` as backup choice if dosen't have enough in
229229

230230
A big use case for type parameter defaults is to help evolve a library while maintaing backwards compatibility. However there are cases where defaults may break inference.
231231

232-
The bad news is that adding a default to an existing type parameter or changing a default may break inference for your users because that may create conflicts among defaults. The good news is that you can add a new type parameter along with a default in the declaration of a type or trait without breaking inference, and the compiler will guide you on how to update your fns, methods and impls through lints and a simple syntax called _default elision_.
232+
The bad news is that adding a default to an existing type parameter or changing a default may break inference for your users because that may create conflicts among defaults. The good news is that you can add a new type parameter along with a default in the declaration of a type or trait without breaking inference, and the compiler will guide you on how to update your fns, methods and impls through lints and a simple syntax called _default elision_.
233233

234234
For an example, let's say an UI library has the following type for text:
235235

@@ -287,7 +287,17 @@ The behaviour of partially supplied parameter lists is as per RFC 213, omited pa
287287

288288
## Defaults as fallbacks for inference
289289

290-
A key part of this proposal is that inference is now aware of defaults. When we would otherwise error due to an uninferred type we instead try using the default. This is called inference fallback which is our final attempt at inference.
290+
A key part of this proposal is that inference is now aware of defaults. When we would otherwise error due to an uninferred type we instead try using the default. This is called inference fallback which is our final attempt at inference. The algorithm for doing this is essentialy the one detailed in RFC 213, with a few considerations:
291+
292+
- The interaction with literal fallback may change, see "Unresolved Questions".
293+
294+
- The algorithm did not specify what happens in eager type resolution such as the `structurally_resolve_type` method, notably used to resolve method receivers. To prevent being a hazard to a future where no longer need to eagerly resolve types, we specify that eager type resolution will not do fallback.
295+
296+
- The algorithm ran obligation selection and fallback in a loop to allow solving edge cases where fallbacks generates new obligations and those obligations generate new fallbacks. This is complex and difficult to reason about, since none of the motivations require this behaviour we propose leaving it as future extension, eliminating the loop and running fallback only once.
297+
298+
### Error messages
299+
300+
Instead of having specific error messages detailing which defaults are in conflict as RFC 213 proposes, we will instead emit generic "type annotations needed" error messages if fallback fails. Specifying which defaults are conflicting can be complicated because the number of possible conflicts is quadratic in the number of defaults being applied and because it requires doing some sort of ad-hoc type equality which is a fishy thing to try considering that dependent defaults would require full inference to detect conflicts. Most users won't be able to act on this information anyways since conflicts are likely to come from separate crates. Thefore we detect and rollback failed fallbacks so that the error emitted is the same as if there were no fallback at all. This can be revisted later as we gain experience with the feature and learn what information would be most helpful.
291301

292302
### Conflicts among defaults
293303

@@ -546,7 +556,7 @@ There are multiple alternatives of what to do about the interaction of user fall
546556

547557
And now a fifth option proposed by this RFC:
548558

549-
5. Error on conflicting numericals, whenever DWIM would prefer a user fallback we instead error.
559+
5. Error on conflicting numericals, whenever DWIM would prefer a user fallback we instead error.
550560

551561
The two following examples show the consequences of each alternative, example 1:
552562

@@ -578,10 +588,6 @@ Option 3 gives the best results, but it may change the behaviour of existing cod
578588

579589
Is there a better name for default elision? Default propagation? Default inheritance? Is there a better syntax than `A=_`?
580590

581-
### Hazard to improvements to type checking
582-
583-
Applying fallback seems natural when it's run at the very end of type checking, where you would get the error "type annotation needed". However type checking sometimes needs eagerly resolve a type, infamously in method calls, leading to the error "type must be known in this context". Applying fallback there maybe a hazard to a future where no longer need to eagerly resolve types.
584-
585591
### Interaction with specialization
586592

587593
Consider the example that shows the behaviour of the current implemetation:

0 commit comments

Comments
 (0)