Auto merge of #98462 - cjgillot:no-apit-hrtb-beta, r=Mark-Simulacrum
[beta] Fail gracefully when encountering an HRTB in APIT. Backport of https://github.com/rust-lang/rust/pull/97683 The diagnostic is a bit worse, but still better than an ICE. r? `@ehuss`
This commit is contained in:
commit
747075d9c0
4 changed files with 82 additions and 8 deletions
|
|
@ -721,7 +721,7 @@ impl<'hir> WherePredicate<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
|
||||
pub enum PredicateOrigin {
|
||||
WhereClause,
|
||||
GenericParam,
|
||||
|
|
|
|||
|
|
@ -230,6 +230,13 @@ enum Scope<'a> {
|
|||
/// In some cases not allowing late bounds allows us to avoid ICEs.
|
||||
/// This is almost ways set to true.
|
||||
allow_late_bound: bool,
|
||||
|
||||
/// If this binder comes from a where clause, specify how it was created.
|
||||
/// This is used to diagnose inaccessible lifetimes in APIT:
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
|
||||
/// ```
|
||||
where_bound_origin: Option<hir::PredicateOrigin>,
|
||||
},
|
||||
|
||||
/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
|
||||
|
|
@ -301,8 +308,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
|||
opaque_type_parent,
|
||||
scope_type,
|
||||
hir_id,
|
||||
s: _,
|
||||
allow_late_bound,
|
||||
where_bound_origin,
|
||||
s: _,
|
||||
} => f
|
||||
.debug_struct("Binder")
|
||||
.field("lifetimes", lifetimes)
|
||||
|
|
@ -311,8 +319,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
|||
.field("opaque_type_parent", opaque_type_parent)
|
||||
.field("scope_type", scope_type)
|
||||
.field("hir_id", hir_id)
|
||||
.field("s", &"..")
|
||||
.field("allow_late_bound", allow_late_bound)
|
||||
.field("where_bound_origin", where_bound_origin)
|
||||
.field("s", &"..")
|
||||
.finish(),
|
||||
Scope::Body { id, s: _ } => {
|
||||
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
|
||||
|
|
@ -701,6 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, move |_old_scope, this| {
|
||||
intravisit::walk_fn(this, fk, fd, b, s, hir_id)
|
||||
|
|
@ -829,6 +839,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
scope_type: BinderScopeType::Normal,
|
||||
s: ROOT_SCOPE,
|
||||
allow_late_bound: false,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &generics.params);
|
||||
|
|
@ -896,6 +907,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
// a bare fn has no bounds, so everything
|
||||
|
|
@ -1091,6 +1103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: false,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
this.with(scope, |_old_scope, this| {
|
||||
this.visit_generics(generics);
|
||||
|
|
@ -1112,6 +1125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: false,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |_old_scope, this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
|
|
@ -1172,6 +1186,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: true,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: false,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &generics.params);
|
||||
|
|
@ -1242,6 +1257,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: true,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &generics.params);
|
||||
|
|
@ -1356,6 +1372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
ref bounded_ty,
|
||||
bounds,
|
||||
ref bound_generic_params,
|
||||
origin,
|
||||
..
|
||||
}) => {
|
||||
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
|
||||
|
|
@ -1387,6 +1404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: Some(origin),
|
||||
};
|
||||
this.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &bound_generic_params);
|
||||
|
|
@ -1461,6 +1479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |_, this| {
|
||||
intravisit::walk_param_bound(this, bound);
|
||||
|
|
@ -1514,6 +1533,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
opaque_type_parent: false,
|
||||
scope_type,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
|
||||
|
|
@ -2207,6 +2227,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
track_lifetime_uses: false,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
allow_late_bound: true,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, move |old_scope, this| {
|
||||
this.check_lifetime_params(old_scope, &generics.params);
|
||||
|
|
@ -2321,12 +2342,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.insert_lifetime(lifetime_ref, def);
|
||||
} else {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
lifetime_ref.span,
|
||||
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// We may fail to resolve higher-ranked lifetimes that are mentionned by APIT.
|
||||
// AST-based resolution does not care for impl-trait desugaring, which are the
|
||||
// responibility of lowering. This may create a mismatch between the resolution
|
||||
// AST found (`region_def_id`) which points to HRTB, and what HIR allows.
|
||||
// ```
|
||||
// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
|
||||
// ```
|
||||
//
|
||||
// In such case, walk back the binders to diagnose it properly.
|
||||
let mut scope = self.scope;
|
||||
loop {
|
||||
match *scope {
|
||||
Scope::Binder {
|
||||
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
|
||||
} => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
lifetime_ref.span,
|
||||
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
Scope::Root => break,
|
||||
Scope::Binder { s, .. }
|
||||
| Scope::Body { s, .. }
|
||||
| Scope::Elision { s, .. }
|
||||
| Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
| Scope::TraitRefBoundary { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tcx.sess.delay_span_bug(
|
||||
lifetime_ref.span,
|
||||
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_segment_args(
|
||||
|
|
|
|||
8
src/test/ui/impl-trait/universal_wrong_hrtb.rs
Normal file
8
src/test/ui/impl-trait/universal_wrong_hrtb.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
trait Trait<'a> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
|
||||
//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level
|
||||
|
||||
fn main() {}
|
||||
8
src/test/ui/impl-trait/universal_wrong_hrtb.stderr
Normal file
8
src/test/ui/impl-trait/universal_wrong_hrtb.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: `impl Trait` can only mention lifetimes bound at the fn or impl level
|
||||
--> $DIR/universal_wrong_hrtb.rs:5:73
|
||||
|
|
||||
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue