Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
move leak-check to during coherence, candidate eval
In particular, it no longer occurs during the subtyping check. This is important for enabling lazy normalization, because the subtyping check will be producing sub-obligations that could affect its results. Consider an example like for<'a> fn(<&'a as Mirror>::Item) = fn(&'b u8) where `<T as Mirror>::Item = T` for all `T`. We will wish to produce a new subobligation like <'!1 as Mirror>::Item = &'b u8 This will, after being solved, ultimately yield a constraint that `'!1 = 'b` which will fail. But with the leak-check being performed on subtyping, there is no opportunity to normalize `<'!1 as Mirror>::Item` (unless we invoke that normalization directly from within subtyping, and I would prefer that subtyping and unification are distinct operations rather than part of the trait solving stack). The reason to keep the leak check during coherence and trait evaluation is partly for backwards compatibility. The coherence change permits impls for `fn(T)` and `fn(&T)` to co-exist, and the trait evaluation change means that we can distinguish those two cases without ambiguity errors. It also avoids recreating #57639, where we were incorrectly choosing a where clause that would have failed the leak check over the impl which succeeds. The other reason to keep the leak check in those places is that I think it is actually close to the model we want. To the point, I think the trait solver ought to have the job of "breaking down" higher-ranked region obligation like ``!1: '2` into into region obligations that operate on things in the root universe, at which point they should be handed off to polonius. The leak check isn't *really* doing that -- these obligations are still handed to the region solver to process -- but if/when we do adopt that model, the decision to pass/fail would be happening in roughly this part of the code. This change had somewhat more side-effects than I anticipated. It seems like there are cases where the leak-check was not being enforced during method proving and trait selection. I haven't quite tracked this down but I think it ought to be documented, so that we know what precisely we are committing to. One surprising test was `issue-30786.rs`. The behavior there seems a bit "fishy" to me, but the problem is not related to the leak check change as far as I can tell, but more to do with the closure signature inference code and perhaps the associated type projection, which together seem to be conspiring to produce an unexpected signature. Nonetheless, it is an example of where changing the leak-check can have some unexpected consequences: we're now failing to resolve a method earlier than we were, which suggests we might change some method resolutions that would have been ambiguous to be successful. TODO: * figure out remainig test failures * add new coherence tests for the patterns we ARE disallowing
- Loading branch information
1 parent
f2cf994
commit 5a7a850
Showing
60 changed files
with
511 additions
and
576 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 15 additions & 15 deletions
30
src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
error: fatal error triggered by #[rustc_error] | ||
--> $DIR/project-fn-ret-invariant.rs:59:1 | ||
--> $DIR/project-fn-ret-invariant.rs:60:1 | ||
| | ||
LL | fn main() { } | ||
| ^^^^^^^^^^^^^ | ||
LL | fn main() {} | ||
| ^^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
14 changes: 7 additions & 7 deletions
14
src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 21 additions & 20 deletions
41
src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,61 @@ | ||
#![feature(unboxed_closures)] | ||
#![feature(rustc_attrs)] | ||
|
||
// Test for projection cache. We should be able to project distinct | ||
// lifetimes from `foo` as we reinstantiate it multiple times, but not | ||
// if we do it just once. In this variant, the region `'a` is used in | ||
// an invariant position, which affects the results. | ||
|
||
// revisions: ok oneuse transmute krisskross | ||
|
||
#![allow(dead_code, unused_variables)] | ||
|
||
use std::marker::PhantomData; | ||
|
||
struct Type<'a> { | ||
// Invariant | ||
data: PhantomData<fn(&'a u32) -> &'a u32> | ||
data: PhantomData<fn(&'a u32) -> &'a u32>, | ||
} | ||
|
||
fn foo<'a>() -> Type<'a> { loop { } } | ||
fn foo<'a>() -> Type<'a> { | ||
loop {} | ||
} | ||
|
||
fn bar<T>(t: T, x: T::Output) -> T::Output | ||
where T: FnOnce<()> | ||
where | ||
T: FnOnce<()>, | ||
{ | ||
t() | ||
} | ||
|
||
#[cfg(ok)] // two instantiations: OK | ||
fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
let a = bar(foo, x); | ||
let b = bar(foo, y); | ||
(a, b) | ||
} | ||
|
||
#[cfg(oneuse)] // one instantiation: BAD | ||
fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
let f = foo; // <-- No consistent type can be inferred for `f` here. | ||
let a = bar(f, x); | ||
let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623] | ||
(a, b) | ||
fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
let f = foo; // <-- No consistent type can be inferred for `f` here. | ||
let a = bar(f, x); | ||
let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623] | ||
(a, b) | ||
} | ||
|
||
#[cfg(transmute)] // one instantiations: BAD | ||
fn baz<'a,'b>(x: Type<'a>) -> Type<'static> { | ||
// Cannot instantiate `foo` with any lifetime other than `'a`, | ||
// since it is provided as input. | ||
fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | ||
// Cannot instantiate `foo` with any lifetime other than `'a`, | ||
// since it is provided as input. | ||
|
||
bar(foo, x) //[transmute]~ ERROR E0495 | ||
bar(foo, x) //[transmute]~ ERROR E0495 | ||
} | ||
|
||
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD | ||
fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
let a = bar(foo, y); //[krisskross]~ ERROR E0623 | ||
let b = bar(foo, x); //[krisskross]~ ERROR E0623 | ||
(a, b) | ||
fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) { | ||
let a = bar(foo, y); //[krisskross]~ ERROR E0623 | ||
let b = bar(foo, x); | ||
(a, b) //[krisskross]~ ERROR E0623 | ||
} | ||
|
||
#[rustc_error] | ||
fn main() { } | ||
fn main() {} | ||
//[ok]~^ ERROR fatal error triggered by #[rustc_error] |
26 changes: 13 additions & 13 deletions
26
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.