use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc_ast::walk_list;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
-use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
+use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(param.hir_id);
- let origin = LifetimeDefOrigin::from_param(param);
debug!("Region::early: index={} def_id={:?}", i, def_id);
- (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin))
+ (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id()))
}
fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
let depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(param.hir_id);
- let origin = LifetimeDefOrigin::from_param(param);
debug!(
- "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}",
- idx, param, depth, def_id, origin,
+ "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
+ idx, param, depth, def_id,
);
- (
- param.name.normalize_to_macros_2_0(),
- Region::LateBound(depth, idx, def_id.to_def_id(), origin),
- )
+ (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id()))
}
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
match *self {
Region::Static | Region::LateBoundAnon(..) => None,
- Region::EarlyBound(_, id, _) | Region::LateBound(_, _, id, _) | Region::Free(_, id) => {
+ Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => {
Some(id)
}
}
fn shifted(self, amount: u32) -> Region {
match self {
- Region::LateBound(debruijn, idx, id, origin) => {
- Region::LateBound(debruijn.shifted_in(amount), idx, id, origin)
+ Region::LateBound(debruijn, idx, id) => {
+ Region::LateBound(debruijn.shifted_in(amount), idx, id)
}
Region::LateBoundAnon(debruijn, index, anon_index) => {
Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index)
fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
match self {
- Region::LateBound(debruijn, index, id, origin) => {
- Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id, origin)
+ Region::LateBound(debruijn, index, id) => {
+ Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id)
}
Region::LateBoundAnon(debruijn, index, anon_index) => {
Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index)
where
L: Iterator<Item = &'a hir::Lifetime>,
{
- if let Region::EarlyBound(index, _, _) = self {
+ if let Region::EarlyBound(index, _) = self {
params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned())
} else {
Some(self)
hir_id: hir::HirId,
s: ScopeRef<'a>,
+
+ /// In some cases not allowing late bounds allows us to avoid ICEs.
+ /// This is almost ways set to true.
+ allow_late_bound: bool,
},
/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
s: ScopeRef<'a>,
},
- /// When we have nested trait refs, we concanetate late bound vars for inner
+ /// When we have nested trait refs, we concatenate late bound vars for inner
/// trait refs from outer ones. But we also need to include any HRTB
/// lifetimes encountered when identifying the trait that an associated type
/// is declared on.
/// Any non-concatenating binder scopes.
Normal,
/// Within a syntactic trait ref, there may be multiple poly trait refs that
- /// are nested (under the `associcated_type_bounds` feature). The binders of
- /// the innner poly trait refs are extended from the outer poly trait refs
+ /// are nested (under the `associated_type_bounds` feature). The binders of
+ /// the inner poly trait refs are extended from the outer poly trait refs
/// and don't increase the late bound depth. If you had
/// `T: for<'a> Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope
/// would be `Concatenating`. This also used in trait refs in where clauses
scope_type,
hir_id,
s: _,
+ allow_late_bound,
} => f
.debug_struct("Binder")
.field("lifetimes", lifetimes)
.field("scope_type", scope_type)
.field("hir_id", hir_id)
.field("s", &"..")
+ .field("allow_late_bound", allow_late_bound)
.finish(),
Scope::Body { id, s: _ } => {
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
match region {
- Region::LateBound(_, _, def_id, _) => {
+ Region::LateBound(_, _, def_id) => {
let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
}
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: true,
};
self.with(scope, move |_old_scope, this| {
intravisit::walk_fn(this, fk, fd, b, s, hir_id)
track_lifetime_uses,
scope_type: BinderScopeType::Normal,
s: ROOT_SCOPE,
+ allow_late_bound: false,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: true,
};
self.with(scope, |old_scope, this| {
// a bare fn has no bounds, so everything
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).cloned();
- let Some(Region::LateBound(_, _, def_id, _)) = def else {
+ let Some(Region::LateBound(_, _, def_id)) = def else {
continue
};
let Some(def_id) = def_id.as_local() else {
}
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
}
+ if let hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::OpaqueTy { .. }, ..
+ }) = self.tcx.hir().get(parent_id)
+ {
+ if !self.trait_definition_only {
+ let mut err = self.tcx.sess.struct_span_err(
+ lifetime.span,
+ "higher kinded lifetime bounds on nested opaque types are not supported yet",
+ );
+ err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
+ err.emit();
+ }
+ self.uninsert_lifetime_on_error(lifetime, def.unwrap());
+ }
}
// We want to start our early-bound indices at the end of the parent scope,
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
- let Region::EarlyBound(_, def_id, _) = reg else {
+ let Region::EarlyBound(_, def_id) = reg else {
bug!();
};
// We cannot predict what lifetimes are unused in opaque type.
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: false,
};
this.with(scope, |_old_scope, this| {
this.visit_generics(generics);
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: false,
};
self.with(scope, |_old_scope, this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
track_lifetime_uses: true,
opaque_type_parent: true,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: false,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
track_lifetime_uses: true,
opaque_type_parent: true,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: true,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
}
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
- if !self.trait_definition_only {
- check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params);
- }
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
for param in generics.params {
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: true,
};
this.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type,
+ allow_late_bound: true,
};
self.with(scope, |_, this| {
intravisit::walk_param_bound(this, bound);
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type,
+ allow_late_bound: true,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
}
}
-fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) {
- let lifetime_params: Vec<_> = params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)),
- _ => None,
- })
- .collect();
- let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit);
- let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand);
-
- if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) {
- struct_span_err!(
- tcx.sess,
- *in_band_span,
- E0688,
- "cannot mix in-band and explicit lifetime definitions"
- )
- .span_label(*in_band_span, "in-band lifetime definition here")
- .span_label(*explicit_span, "explicit lifetime definition here")
- .emit();
- }
-}
-
fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
// lifetime/lifetime shadowing is an error
name,
orig.kind.desc()
)
+ .forget_guarantee()
} else {
// shadowing involving a label is only a warning, due to issues with
// labels and lifetimes not being macro-hygienic.
.map(|set| match *set {
Set1::Empty => "BaseDefault".into(),
Set1::One(Region::Static) => "'static".into(),
- Set1::One(Region::EarlyBound(mut i, _, _)) => generics
+ Set1::One(Region::EarlyBound(mut i, _)) => generics
.params
.iter()
.find_map(|param| match param.kind {
let param_def_id = tcx.hir().local_def_id(param.hir_id);
for predicate in generics.where_clause.predicates {
// Look for `type: ...` where clauses.
- let data = match *predicate {
- hir::WherePredicate::BoundPredicate(ref data) => data,
- _ => continue,
- };
+ let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue };
// Ignore `for<'a> type: ...` as they can change what
// lifetimes mean (although we could "just" handle it).
.params
.iter()
.filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some((
- param.hir_id,
- hir::LifetimeName::Param(param.name),
- LifetimeDefOrigin::from_param(param),
- )),
+ GenericParamKind::Lifetime { .. } => {
+ Some((param.hir_id, hir::LifetimeName::Param(param.name)))
+ }
_ => None,
})
.enumerate()
- .find(|&(_, (_, lt_name, _))| lt_name == name)
- .map_or(Set1::Many, |(i, (id, _, origin))| {
+ .find(|&(_, (_, lt_name))| lt_name == name)
+ .map_or(Set1::Many, |(i, (id, _))| {
let def_id = tcx.hir().local_def_id(id);
- Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id(), origin))
+ Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
})
}
}
fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> {
generics.params.iter().enumerate().find_map(|(i, param)| {
if param.name.ident() == name {
- let in_band = matches!(
- param.kind,
- hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand }
- );
- if in_band {
- Some(param.span)
- } else if generics.params.len() == 1 {
+ if generics.params.len() == 1 {
// if sole lifetime, remove the entire `<>` brackets
Some(generics.span)
} else {
// or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)`
fn suggest_eliding_single_use_lifetime(
&self,
- err: &mut DiagnosticBuilder<'_>,
+ err: &mut Diagnostic,
def_id: DefId,
lifetime: &hir::Lifetime,
) {
}
fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
- let defined_by = match self.scope {
- Scope::Binder { lifetimes, .. } => lifetimes,
- _ => {
- debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
- return;
- }
+ let Scope::Binder { lifetimes: defined_by, .. } = self.scope else {
+ debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+ return;
};
let def_ids: Vec<_> = defined_by
.values()
.flat_map(|region| match region {
- Region::EarlyBound(_, def_id, _)
- | Region::LateBound(_, _, def_id, _)
+ Region::EarlyBound(_, def_id)
+ | Region::LateBound(_, _, def_id)
| Region::Free(_, def_id) => Some(*def_id),
Region::LateBoundAnon(..) | Region::Static => None,
if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
continue 'lifetimes;
}
- // We want to do this only if the liftime identifier is already defined
+ // We want to do this only if the lifetime identifier is already defined
// in the async function that generated this. Otherwise it could be
// an opaque type defined by the developer and we still want this
// lint to fail compilation
opaque_type_parent: true,
track_lifetime_uses: false,
scope_type: BinderScopeType::Normal,
+ allow_late_bound: true,
};
self.with(scope, move |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
}
}
- // Check for fn-syntax conflicts with in-band lifetime definitions
- if !self.trait_definition_only && self.is_in_fn_syntax {
- match def {
- Region::EarlyBound(_, _, LifetimeDefOrigin::InBand)
- | Region::LateBound(_, _, _, LifetimeDefOrigin::InBand) => {
- struct_span_err!(
- self.tcx.sess,
- lifetime_ref.span,
- E0687,
- "lifetimes used in `fn` or `Fn` syntax must be \
- explicitly declared using `<...>` binders"
- )
- .span_label(lifetime_ref.span, "in-band lifetime definition")
- .emit();
- }
-
- Region::Static
- | Region::EarlyBound(
- _,
- _,
- LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error,
- )
- | Region::LateBound(
- _,
- _,
- _,
- LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error,
- )
- | Region::LateBoundAnon(..)
- | Region::Free(..) => {}
- }
- }
-
self.insert_lifetime(lifetime_ref, def);
} else {
self.emit_undeclared_lifetime_error(lifetime_ref);
smallvec![(def_id, smallvec![])];
let mut visited: FxHashSet<DefId> = FxHashSet::default();
loop {
- let (def_id, bound_vars) = match stack.pop() {
- Some(next) => next,
- None => break None,
+ let Some((def_id, bound_vars)) = stack.pop() else {
+ break None;
};
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
// there being no supertrait HRTBs.
let mut scope = &*self.scope;
let hir_id = loop {
match scope {
- Scope::Binder { hir_id, .. } => {
+ Scope::Binder { hir_id, allow_late_bound: true, .. } => {
break *hir_id;
}
Scope::ObjectLifetimeDefault { ref s, .. }
| Scope::TraitRefBoundary { ref s, .. } => {
scope = *s;
}
- Scope::Root | Scope::Body { .. } => {
+ Scope::Root
+ | Scope::Body { .. }
+ | Scope::Binder { allow_late_bound: false, .. } => {
// See issues #83907 and #83693. Just bail out from looking inside.
+ // See the issue #95023 for not allowing late bound
self.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
"In fn_like_elision without appropriate scope above",
}
});
- let output = match output {
- Some(ty) => ty,
- None => return,
- };
+ let Some(output) = output else { return };
debug!("determine output");
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
match lifetime {
- Region::LateBound(debruijn, _, _, _)
+ Region::LateBound(debruijn, _, _)
| Region::LateBoundAnon(debruijn, _, _)
if debruijn < self.outer_index =>
{
path_span: Span,
generic_args: &'v hir::GenericArgs<'v>,
) {
- // parenthesized args enter a new elison scope
+ // parenthesized args enter a new elision scope
if generic_args.parenthesized {
return;
}
for bound in lifetime_i.bounds {
match bound {
hir::GenericBound::Outlives(ref lt) => match lt.name {
- hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug(
- lt.span,
- "use of `'_` in illegal place, but not caught by lowering",
- ),
+ hir::LifetimeName::Underscore => {
+ self.tcx.sess.delay_span_bug(
+ lt.span,
+ "use of `'_` in illegal place, but not caught by lowering",
+ );
+ }
hir::LifetimeName::Static => {
self.insert_lifetime(lt, Region::Static);
self.tcx
lt.span,
"lowering generated `ImplicitObjectLifetimeDefault` \
outside of an object type",
- )
+ );
}
hir::LifetimeName::Error => {
// No need to do anything, error already reported.
}
Region::Free(_, def_id)
- | Region::LateBound(_, _, def_id, _)
- | Region::EarlyBound(_, def_id, _) => {
+ | Region::LateBound(_, _, def_id)
+ | Region::EarlyBound(_, def_id) => {
// A lifetime declared by the user.
let track_lifetime_uses = self.track_lifetime_uses();
debug!(?track_lifetime_uses);