diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-11-16 21:05:46 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-16 21:05:46 +0100 |
| commit | a1c98ca16025c697779306a549832bbfd75d7b3b (patch) | |
| tree | bc2d2764c1b6140aa223a472e8e7d60a245b6291 /compiler/rustc_hir_analysis/src | |
| parent | 6b47c6d786df3fd5141174ee1fe04ec2fd957e3d (diff) | |
| parent | 8d871b768764f49b5c41cdb6add3b4076c89b610 (diff) | |
| download | rust-a1c98ca16025c697779306a549832bbfd75d7b3b.tar.gz rust-a1c98ca16025c697779306a549832bbfd75d7b3b.zip | |
Rollup merge of #132832 - compiler-errors:late-ty, r=cjgillot
Deny capturing late-bound ty/const params in nested opaques
First, this reverts a7f609504c92c9912b61025ae26a5404d3ee4311. I can't exactly remember why I approved this specific bit of https://github.com/rust-lang/rust/pull/132466; specifically, I don't know that the purpose of that commit is, and afaict we will never have an opaque that captures late-bound params through a const because opaques can't be used inside of anon consts. Am I missing something `@cjgillot?` Since I can't see a case where this matters, and no tests seem to fail.
The second commit adds a `deny_late_regions: bool` to distinguish `Scope::LateBoundary` which should deny *any* late-bound params or just ty/consts. Then, when resolving opaques we wrap ourselves in a `Scope::LateBoundary { deny_late_regions: false }` so that we deny late-bound ty/const, which fixes a bunch of ICEs that all vaguely look like `impl for<T> Trait<Assoc = impl OtherTrait<T>>`.
I guess this could be achieved other ways; for example, with a different scope kind, or maybe we could just reuse `Scope::Opaque`. But this seems a bit more verbose. I'm open to feedback anyways.
Fixes #131535
Fixes #131637
Fixes #132530
I opted to remove those crashes tests ^ without adding them as regular tests, since they're basically triggering uninteresting late-bound ICEs far off in the trait solver, and the reason that existing tests such as `tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs` don't ICE are kinda just coincidental (i.e. due to a missing impl block). I don't really feel motivated to add random permutations to tests just to exercise non-lifetime binders.
r? cjgillot
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cc55f57c46c..b4b3ef31f97 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -177,6 +177,7 @@ enum Scope<'a> { LateBoundary { s: ScopeRef<'a>, what: &'static str, + deny_late_regions: bool, }, Root { @@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("s", &"..") .finish(), Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), - Scope::LateBoundary { s: _, what } => { - f.debug_struct("LateBoundary").field("what", what).finish() - } + Scope::LateBoundary { s: _, what, deny_late_regions } => f + .debug_struct("LateBoundary") + .field("what", what) + .field("deny_late_regions", deny_late_regions) + .finish(), Scope::Root { opt_parent_item } => { f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish() } @@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // give, we will reverse the IndexMap after early captures. let mut late_depth = 0; let mut scope = self.scope; - let mut crossed_late_boundary = None; let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; loop { match *scope { Scope::Binder { ref bound_vars, scope_type, s, .. } => { for (&original_lifetime, &def) in bound_vars.iter().rev() { - if let ResolvedArg::LateBound(..) = def - && crossed_late_boundary.is_some() - { - continue; - } if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { let def = def.shifted(late_depth); let ident = lifetime_ident(original_lifetime); @@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { - scope = s; - } - - Scope::LateBoundary { s, what, .. } => { - crossed_late_boundary = Some(what); + | Scope::TraitRefBoundary { s, .. } + | Scope::LateBoundary { s, .. } => { scope = s; } } @@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + this.with(scope, |this| { + let scope = Scope::LateBoundary { + s: this.scope, + what: "nested `impl Trait`", + // We can capture late-bound regions; we just don't duplicate + // lifetime or const params, so we can't allow those. + deny_late_regions: false, + }; + this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) + }) }); let captures = captures.into_inner().into_iter().collect(); @@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { - self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| { - intravisit::walk_anon_const(this, c); - }); + self.with( + Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true }, + |this| { + intravisit::walk_anon_const(this, c); + }, + ); } fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { @@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { - crossed_late_boundary = Some(what); + Scope::LateBoundary { s, what, deny_late_regions } => { + if deny_late_regions { + crossed_late_boundary = Some(what); + } scope = s; } } @@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } - Scope::LateBoundary { s, what } => { + Scope::LateBoundary { s, what, deny_late_regions: _ } => { crossed_late_boundary = Some(what); scope = s; } |
