-
-
Notifications
You must be signed in to change notification settings - Fork 15k
Fix elided lifetime resolution & trait object lifetime defaulting for enum variant paths #154918
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1691,7 +1691,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | |
| // which requires object lifetime defaults. | ||
| let type_def_id = match res { | ||
| Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)), | ||
| Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)), | ||
| Res::Def(DefKind::Variant, def_id) if depth == 0 || depth == 1 => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are in a position to fix this without any bad repercussions (namely breaking user code) due to this bug being covered by the lifetime elision bug that's fixed in the first commit and which dates all the way back to 2016 (#108224 (comment)). That's because the new Of course, if we pivot to dropping object lifetime defaulting in bodies (#129543 (review)), this issue should go away automatically. |
||
| Some(self.tcx.parent(def_id)) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, after #129543, this will look something like: Res::Def(DefKind::Variant, def_id) => match rev_seg_idx {
0 => Some((self.tcx.parent(def_id), path.segments)),
1 => Some((self.tcx.parent(def_id), &path.segments[..=seg_idx])),
_ => None,
}, |
||
| } | ||
| Res::Def( | ||
| DefKind::Struct | ||
| | DefKind::Union | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // Given an enum `Enum` with lifetime parameters, we used to lower `Enum::<…>::Variant {}` to | ||
| // `Enum::<…>::Variant::<'_, …> {}`, i.e., synthesize `'_` lifetime args for enum variants | ||
| // even if generic args were already passed to the enum itself. | ||
| // Obviously, these conflicting generic arg lists were then rejected later on (by HIR ty lowering). | ||
| // | ||
| // Now we no longer do. Why do we synthesize these lifetimes for struct variant paths in the first | ||
| // place while we don't do it for unit & tuple variants? Well, we later HIR-ty-lower the former in | ||
| // "type mode" while we lower the latter in "value mode". In "type mode", we won't infer | ||
| // elided lifetimes if the generic arg lists contains non-lifetime args which is undesirable here. | ||
|
Comment on lines
+6
to
+9
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ahahah omg why is this so cursed I assume changing this to be "less weird" is just out of the question (definitely for this PR, but I mean that it's likely a big change)?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that'll likely be quite the overhaul and very much out of scope I would say. For some reason, the lowering of It's possible that the code lives in Still, there ought to be a slightly more principled way for resolving variant paths I hope. For context, for mGCA which features type-level variant paths (const exprs), we currently mirror / duplicate a lot of code of Footnotes
|
||
| // | ||
| // issue: <https://github.com/rust-lang/rust/issues/108224> | ||
| //@ check-pass | ||
|
|
||
| fn scope<'any>() { | ||
| enum Ty0<'a> { | ||
| Unit, | ||
| Tuple, | ||
| Struct {}, | ||
|
|
||
| Carry(&'a ()), | ||
| } | ||
|
|
||
| enum Ty1<'a, T: ?Sized> { | ||
| Variant, | ||
|
|
||
| Carry(&'a T), | ||
| } | ||
|
|
||
| let _ = Ty0::<'_>::Unit {}; | ||
| let _ = Ty0::<'static>::Tuple {}; | ||
| let _ = Ty0::<'any>::Struct {}; | ||
|
|
||
| let _ = Ty1::</*'_, */()>::Variant {}; | ||
| let _ = Ty1::<'any, ()>::Variant {}; | ||
| } | ||
|
|
||
| fn main() {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| //@ check-pass | ||
|
|
||
| enum Enum<'a, T: 'a + AbideBy<'a> + ?Sized> { | ||
| Variant, | ||
|
|
||
| Carry(&'a T), | ||
| } | ||
|
|
||
| fn scope<'any>() { | ||
| // We elaborate `dyn Trait` to `dyn Trait + 'any` due to bound `'a` on `T`. | ||
| let _ = Enum::Variant::<'any, dyn Trait> {}; | ||
|
|
||
| // Similarly here. | ||
| let _ = Enum::<'any, dyn Trait>::Variant {}; | ||
|
Comment on lines
+11
to
+14
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh you can just write both of these? Lol, okay. |
||
| } | ||
|
|
||
| trait Trait {} | ||
|
|
||
| // We use this to test that a given trait object lifetime bound is | ||
| // *exactly equal* to a given lifetime (not longer, not shorter). | ||
| trait AbideBy<'a> {} | ||
| impl<'a> AbideBy<'a> for dyn Trait + 'a {} | ||
|
|
||
| fn main() {} | ||
Uh oh!
There was an error while loading. Please reload this page.
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.
Once or if we stop utilizing object lifetime defaulting in bodies (cc #129543 (review)), this fix will become moot.
Admittedly, in the last paragraph of #129543 (comment) I stated that this fix would still be relevant for mGCA but I'm no longer super sure:
Indeed, trait object defaulting is generally relevant to mGCA, too (see open issue #151649), and so are enum variants in (direct) const args (which aren't backed by a body in which we could perform inference). However, I was unable to come up with a snippet where this fix is observable, at least not without "cheating" since
dyn Traitcan't be used as the type of const args (not sure if that'll change eventually?).This commit makes the following artificial (!) mGCA snippet compile but I don't think it "counts".
Uh oh!
There was an error while loading. Please reload this page.
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.
Well, I was able to replace the usage of
const_param_ty_unchecked(internal) withstructual_match(perma? unstable) but that's hardly better:I guess I could add that as a test? Hmmm
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'm not following? The bottom test only has
Uh oh!
There was an error while loading. Please reload this page.
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.
Both snippets get rejected with "lifetime arguments are not allowed on variant
V" on nightly / main (!) due to the elision bug that's fixed in the first commit of this PR.I'm sorry that I didn't make this clearer but you're meant to assume that the elision bug was already fixed // you're meant to feed it to rustc patched with commit (0) "Don't synthesize lifetime args for variant paths if generic args were passed to the enum itself already" but not yet patched with commit (1) "Make enum variant paths induce trait object lifetime defaults in the enum path segment".