@@ -434,87 +434,11 @@ attached to the `ParameterEnvironment` and the global cache attached
434434to the `tcx`. We use the local cache whenever the result might depend
435435on the where clauses that are in scope. The determination of which
436436cache to use is done by the method `pick_candidate_cache` in
437- `select.rs`.
438-
439- There are two cases where we currently use the local cache. The
440- current rules are probably more conservative than necessary.
441-
442- ### Trait references that involve parameter types
443-
444- The most obvious case where you need the local environment is
445- when the trait reference includes parameter types. For example,
446- consider the following function:
447-
448- impl<T> Vec<T> {
449- fn foo(x: T)
450- where T : Foo
451- { ... }
452-
453- fn bar(x: T)
454- { ... }
455- }
456-
457- If there is an obligation `T : Foo`, or `int : Bar<T>`, or whatever,
458- clearly the results from `foo` and `bar` are potentially different,
459- since the set of where clauses in scope are different.
460-
461- ### Trait references with unbound variables when where clauses are in scope
462-
463- There is another less obvious interaction which involves unbound variables
464- where *only* where clauses are in scope (no impls). This manifested as
465- issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider
466- this snippet:
467-
468- ```
469- pub trait Foo {
470- fn load_from() -> Box<Self>;
471- fn load() -> Box<Self> {
472- Foo::load_from()
473- }
474- }
475- ```
476-
477- The default method will incur an obligation `$0 : Foo` from the call
478- to `load_from`. If there are no impls, this can be eagerly resolved to
479- `VtableParam(Self : Foo)` and cached. Because the trait reference
480- doesn't involve any parameters types (only the resolution does), this
481- result was stored in the global cache, causing later calls to
482- `Foo::load_from()` to get nonsense.
483-
484- To fix this, we always use the local cache if there are unbound
485- variables and where clauses in scope. This is more conservative than
486- necessary as far as I can tell. However, it still seems to be a simple
487- rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt
488- us in particular.
489-
490- Here is an example of the kind of subtle case that I would be worried
491- about with a more complex rule (although this particular case works
492- out ok). Imagine the trait reference doesn't directly reference a
493- where clause, but the where clause plays a role in the winnowing
494- phase. Something like this:
495-
496- ```
497- pub trait Foo<T> { ... }
498- pub trait Bar { ... }
499- impl<U,T:Bar> Foo<U> for T { ... } // Impl A
500- impl Foo<char> for uint { ... } // Impl B
501- ```
502-
503- Now, in some function, we have no where clauses in scope, and we have
504- an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char`
505- and `$1=uint`: this is because for impl A to apply, `uint:Bar` would
506- have to hold, and we know it does not or else the coherence check
507- would have failed. So we might enter into our global cache: `$1 :
508- Foo<$0> => Impl B`. Then we come along in a different scope, where a
509- generic type `A` is around with the bound `A:Bar`. Now suddenly the
510- impl is viable.
511-
512- The flaw in this imaginary DOOMSDAY SCENARIO is that we would not
513- currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and
514- `$1 == char`, even though it is true that (absent type parameters)
515- there is no other type the user could enter. However, it is not
516- *completely* implausible that we *could* draw this conclusion in the
517- future; we wouldn't have to guess types, in particular, we could be
518- led by the impls.
437+ `select.rs`. At the moment, we use a very simple, conservative rule:
438+ if there are any where-clauses in scope, then we use the local cache.
439+ We used to try and draw finer-grained distinctions, but that led to a
440+ serious of annoying and weird bugs like #22019 and #18290. This simple
441+ rule seems to be pretty clearly safe and also still retains a very
442+ high hit rate (~95% when compiling rustc).
519443
520444*/
0 commit comments