-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strict region folders #110312
Strict region folders #110312
Conversation
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor |
This is insufficient, IMO. I assume most of these bug cases are going to be triggered not in good-path code, but on subtle combinations of bad-path code. Anyways, I'll take a look at this tomorrow and try to find ways of triggering some of these bugs, or at least I can leave inline comments for the ones that confidently can remain stronger assertions. |
☔ The latest upstream changes (presumably #110311) made this pull request unmergeable. Please resolve the merge conflicts. |
I argue that we should do a crater run regardless on whether we merge or not. Imo, it's always good to find where the test suite is lacking coverage. One way to do that is to, as in this PR, place constraints on the compiler that pass the test suite and test on crater. This would help two fold: one, it would directly help expand test coverage; two, it help to document the patterns that extra uses support. |
What exactly is the argument here? One argument should be that we gracefully handle "invalid" state, with the expectation that we catch it later. But a counter argument is that we should detect that state early (even if we just delay the bug). |
The argument is that I don't think that we should be unnecessarily introducing ICEs into the compiler, even on failed compilation sessions, so I don't think we should land this without more testing than just crater. I just don't want to see "Let's land this now and see what ICEs people file later". For example, a UI-test-guided approach is insufficient because this isn't exercising, e.g., every combination of parser recovery that ends up causing us to generate End users are frustrated when their already messed up code ends up ICEing due to far-too-strict assertions just like this PR is introducing, especially since the PR description above mentions that the changes here aren't even particularly compelling because there aren't general patterns in the choices of lifetimes that each fold method is supposed to support. |
A handful of these folders are happening in diagnostics code anyways, so it's not worthwhile delaying an additional bug when we're already constructing a diagnostic. Also, |
The job Click to see the possible cause of the failure (guessed by this bot)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a bunch of examples of ICEs due to the lack of handling of ReError
. Left some thoughts about some of the other assertions.
I didn't touch borrowck, maybe someone like @aliemjay can leave thoughts on those.
.unwrap_or_else(|| r.super_fold_with(self)) | ||
match *r { | ||
ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned().unwrap_or(r), | ||
ty::ReEarlyBound(_) | ty::ReStatic | ty::ReLateBound(..) => r, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably fine. If I were being defensive, I'd also include ReError
here, but whatever.
Some comment to the effect of "these are the regions that can be seen in AST" as justification.
); | ||
match re.kind() { | ||
ty::ReEarlyBound(_) => re, | ||
ty::ReLateBound(index, bv) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ICEs on ReEarlyBound
:
#![feature(return_position_impl_trait_in_trait)]
use std::ops::Deref;
trait Foo {
fn test<'a: 'a>() -> impl Deref<Target = impl Sized> { &() }
}
fn main() {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, that error is coming from somewhere else in borrowck.
@@ -1141,8 +1142,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> { | |||
self.tcx.mk_re_late_bound(self.binder_index, br) | |||
} | |||
}, | |||
|
|||
_ => r.super_fold_with(self), | |||
// Other region kinds might need the same treatment here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Canonicalization already canonicalizes all free regions for chalk. We probably shouldn't even have this folder at all.
Unrelated, but this ICEs on nightly already, lol:
// compile-flags: -Ztrait-solver=chalk
trait Trait {}
impl Trait for &() {}
fn trait_pred() where &'missing (): Trait {}
fn main() {
trait_pred();
}
@@ -1045,7 +1045,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> { | |||
ty::BrEnv => unimplemented!(), | |||
ty::BrAnon(..) => {} | |||
}, | |||
_ => (), | |||
ty::ReLateBound(..) | ty::ReStatic => (), | |||
r => bug!("unexpected region: {r:?}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably ICEs on ReError
if we do something like:
fn def<'a, T>(_: T) where T: Fn() {}
fn foo() where &'missing i32: Copy {}
fn main() {
def(foo);
}
But that's obscured by other canonicalizer+ReError bugs in chalk.
@@ -387,8 +387,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { | |||
|
|||
fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { | |||
let ty = self.tcx.fold_regions(ty, |r, _| match *r { | |||
ty::ReErased => self.tcx.lifetimes.re_static, | |||
_ => r, | |||
// This is never reached in practice. If it ever is reached, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not hit this in practice, I checked. But as far as I know, ReErased
is the only region we should see... anyways, this is fine to keep here I guess.
re | ||
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| { | ||
match re.kind() { | ||
ty::ReEarlyBound(_) | ty::ReFree(_) => re, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably need to support ReError
here, but actually, but I guess I never noticed that all the late-bound lifetimes are liberated here, so that's good news I guess. Simplifes the logic a bit.
} else { | ||
r | ||
), | ||
ty::ReEarlyBound(_) | ty::ReStatic => r, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably need to support ReError
here, but after staring at this code for the last hour or so I am starting to get exhausted providing examples 😅
_ => return region, | ||
ty::ReEarlyBound(_) | | ||
ty::ReStatic => return region, | ||
r => bug!("unexpected region: {r:?}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReError here
let ty = tcx.fold_regions(ty_erased, |r, _| { | ||
if r.is_erased() { tcx.lifetimes.re_static } else { r } | ||
let ty = tcx.fold_regions(ty_erased, |r, _| match r.kind() { | ||
ty::ReErased => tcx.lifetimes.re_static, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think ReErased
is the only kind we expect here.
Not sure if you want to work on this further or split it out into other PRs, but marking this as waiting-on-author for now. @rustbot author |
One or the other, but I have some other stuff I need to finish in the meantime. I'll get back to this eventually. Thank you for the detailed comments. |
I just created #110835, which is a massively cut down version of this, including only the changes that @compiler-errors was positive about, which wasn't many. While this was an interesting experiment, making large scale changes doesn't seem like a good idea. |
Some region folders expect certain region variants to never occur. Other region folders handle all region variants. I was wondering if we could be stricter. So I tried changing every region folder to not accept any variants, and then gradually allowed variants until the full test suite passed.
The results are less enlightening than I'd hoped. I was expecting to see some common patterns but there aren't any, there is no consistency at all. I'm ambivalent about whether this should be merged, but I figure it's worth showing others. If we do merge it, we should probably do a crater run first to flush out any edge cases not covered by the test suite.
r? @oli-obk