Report undeclared lifetimes on AST.

This commit is contained in:
Camille GILLOT 2022-03-06 12:02:13 +01:00
parent 4cfceeabdc
commit fc9f25531a
5 changed files with 833 additions and 396 deletions

View File

@ -484,7 +484,7 @@ enum ParenthesizedGenericArgs {
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
/// everything into HIR lowering.
#[derive(Copy, Clone, Debug)]
enum AnonymousLifetimeMode {
pub enum AnonymousLifetimeMode {
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
@ -2017,16 +2017,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
let param_name = match lt.name {
hir::LifetimeName::Param(param_name) => param_name,
hir::LifetimeName::Implicit(_)
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
hir::ParamName::Plain(lt.name.ident())
}
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
self.sess.diagnostic().span_bug(
param.ident.span,
"object-lifetime-default should not occur here",
);
}
hir::LifetimeName::Error => ParamName::Error,
hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
};
let kind =
@ -2404,20 +2404,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
/// return an "error lifetime".
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
let (id, msg, label) = match id {
Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
None => (
self.resolver.next_node_id(),
"`&` without an explicit lifetime name cannot be used here",
"explicit lifetime name needed here",
),
};
let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,);
err.span_label(span, label);
err.emit();
let id = id.unwrap_or_else(|| self.resolver.next_node_id());
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
}

View File

@ -188,6 +188,68 @@ impl<'a, R> Rib<'a, R> {
}
}
#[derive(Copy, Clone, Debug)]
enum LifetimeRibKind {
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
Item,
/// This rib declares generic parameters.
Generics { span: Span, kind: LifetimeBinderKind },
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
/// For **Dyn Bound** cases, pass responsibility to
/// `resolve_lifetime` code.
///
/// For **Deprecated** cases, report an error.
AnonymousCreateParameter,
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
/// error on default object bounds (e.g., `Box<dyn Foo>`).
AnonymousReportError,
/// Pass responsibility to `resolve_lifetime` code for all cases.
AnonymousPassThrough,
}
#[derive(Copy, Clone, Debug)]
enum LifetimeBinderKind {
BareFnType,
PolyTrait,
WhereBound,
Item,
Function,
ImplBlock,
}
impl LifetimeBinderKind {
fn descr(self) -> &'static str {
use LifetimeBinderKind::*;
match self {
BareFnType => "type",
PolyTrait => "bound",
WhereBound => "bound",
Item => "item",
ImplBlock => "impl block",
Function => "function",
}
}
}
#[derive(Debug)]
struct LifetimeRib {
kind: LifetimeRibKind,
bindings: IdentMap<()>,
}
impl LifetimeRib {
fn new(kind: LifetimeRibKind) -> LifetimeRib {
LifetimeRib { bindings: Default::default(), kind }
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum AliasPossibility {
No,
@ -422,6 +484,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
/// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a, NodeId>>,
/// The current set of local scopes for lifetimes.
lifetime_ribs: Vec<LifetimeRib>,
/// The trait that the current context can refer to.
current_trait_ref: Option<(Module<'a>, TraitRef)>,
@ -446,7 +511,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
// Always report errors in items we just entered.
let old_ignore = replace(&mut self.in_func_body, false);
self.resolve_item(item);
self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item));
self.in_func_body = old_ignore;
self.diagnostic_metadata.current_item = prev;
}
@ -481,6 +546,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
match ty.kind {
TyKind::Rptr(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
self.resolve_elided_lifetime(ty.id, span);
}
TyKind::Path(ref qself, ref path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@ -500,36 +571,86 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
TyKind::TraitObject(ref bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
}
TyKind::BareFn(ref bare_fn) => {
let span = if bare_fn.generic_params.is_empty() {
ty.span.shrink_to_lo()
} else {
ty.span
};
self.with_generic_param_rib(
&bare_fn.generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
|this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
this.visit_generic_param_vec(&bare_fn.generic_params, false);
visit::walk_fn_decl(this, &bare_fn.decl);
});
},
);
self.diagnostic_metadata.current_trait_object = prev;
return;
}
_ => (),
}
visit::walk_ty(self, ty);
self.diagnostic_metadata.current_trait_object = prev;
self.diagnostic_metadata.current_type_path = prev_ty;
}
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
self.smart_resolve_path(
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
let span =
if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
self.with_generic_param_rib(
&tref.bound_generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
|this| {
this.visit_generic_param_vec(&tref.bound_generic_params, false);
this.smart_resolve_path(
tref.trait_ref.ref_id,
None,
&tref.trait_ref.path,
PathSource::Trait(AliasPossibility::Maybe),
);
visit::walk_poly_trait_ref(self, tref, m);
this.visit_trait_ref(&tref.trait_ref);
},
);
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
ForeignItemKind::Fn(box Fn { ref generics, .. })
| ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
this.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Item,
span: generics.span,
},
|this| visit::walk_foreign_item(this, foreign_item),
)
});
}
ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
this.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Function,
span: generics.span,
},
|this| visit::walk_foreign_item(this, foreign_item),
)
});
}
ForeignItemKind::Static(..) => {
self.with_item_rib(HasGenericParams::No, |this| {
self.with_item_rib(|this| {
visit::walk_foreign_item(this, foreign_item);
});
}
ForeignItemKind::MacCall(..) => {
visit::walk_foreign_item(self, foreign_item);
panic!("unexpanded macro in resolve!")
}
}
}
@ -539,11 +660,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// a body, or if there's no body for some other reason.
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
| FnKind::Fn(_, _, sig, _, generics, None) => {
self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
// We don't need to deal with patterns in parameters, because
// they are not possible for foreign or bodiless functions.
self.visit_fn_header(&sig.header);
self.visit_generics(generics);
visit::walk_fn_decl(self, &sig.decl);
this.visit_fn_header(&sig.header);
this.visit_generics(generics);
visit::walk_fn_decl(this, &sig.decl);
});
return;
}
FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
@ -561,23 +684,44 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.with_rib(ValueNS, rib_kind, |this| {
// Create a label rib for the function.
this.with_label_rib(rib_kind, |this| {
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
this.visit_generics(generics);
}
if async_node_id.is_some() {
// In `async fn`, argument-position elided lifetimes
// must be transformed into fresh generic parameters so that
// they can be applied to the opaque `impl Trait` return type.
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
// Add each argument to the rib.
this.resolve_params(&declaration.inputs)
});
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
visit::walk_fn_ret_ty(this, &declaration.output)
});
} else {
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
// Add each argument to the rib.
this.resolve_params(&declaration.inputs);
visit::walk_fn_ret_ty(this, &declaration.output);
});
};
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
match fn_kind {
this.with_lifetime_rib(
LifetimeRibKind::AnonymousPassThrough,
|this| match fn_kind {
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
FnKind::Closure(_, body) => this.visit_expr(body),
};
},
);
debug!("(resolving function) leaving function");
this.in_func_body = previous_state;
@ -585,89 +729,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
});
self.diagnostic_metadata.current_function = previous_value;
}
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
self.resolve_lifetime(lifetime)
}
fn visit_generics(&mut self, generics: &'ast Generics) {
// For type parameter defaults, we have to ban access
// to following type parameters, as the InternalSubsts can only
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
for param in generics.params.iter() {
match param.kind {
GenericParamKind::Type { .. } => {
forward_ty_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
GenericParamKind::Const { .. } => {
forward_const_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
GenericParamKind::Lifetime => {}
}
}
// rust-lang/rust#61631: The type `Self` is essentially
// another type parameter. For ADTs, we consider it
// well-defined only after all of the ADT type parameters have
// been provided. Therefore, we do not allow use of `Self`
// anywhere in ADT type parameter defaults.
//
// (We however cannot ban `Self` for defaults on *all* generic
// lists; e.g. trait generics can usefully refer to `Self`,
// such as in the case of `trait Add<Rhs = Self>`.)
if self.diagnostic_metadata.current_self_item.is_some() {
// (`Some` if + only if we are in ADT's generics.)
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
}
for param in &generics.params {
match param.kind {
GenericParamKind::Lifetime => self.visit_generic_param(param),
GenericParamKind::Type { ref default } => {
for bound in &param.bounds {
self.visit_param_bound(bound);
}
if let Some(ref ty) = default {
self.ribs[TypeNS].push(forward_ty_ban_rib);
self.ribs[ValueNS].push(forward_const_ban_rib);
self.visit_ty(ty);
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this type parameter.
forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
// Const parameters can't have param bounds.
assert!(param.bounds.is_empty());
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
self.visit_ty(ty);
self.ribs[TypeNS].pop().unwrap();
self.ribs[ValueNS].pop().unwrap();
if let Some(ref expr) = default {
self.ribs[TypeNS].push(forward_ty_ban_rib);
self.ribs[ValueNS].push(forward_const_ban_rib);
self.visit_anon_const(expr);
forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this const parameter.
forward_const_ban_rib
.bindings
.remove(&Ident::with_dummy_span(param.ident.name));
}
}
}
self.visit_generic_param_vec(
&generics.params,
self.diagnostic_metadata.current_self_item.is_some(),
);
for p in &generics.where_clause.predicates {
self.visit_where_predicate(p);
}
@ -726,11 +796,52 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.diagnostic_metadata.currently_processing_generics = prev;
}
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
if let Some(ref args) = path_segment.args {
match &**args {
GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
GenericArgs::Parenthesized(..) => self
.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
visit::walk_generic_args(this, path_span, args)
}),
}
}
}
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
debug!("visit_where_predicate {:?}", p);
let previous_value =
replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
visit::walk_where_predicate(self, p);
self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
ref bounded_ty,
ref bounds,
ref bound_generic_params,
span: predicate_span,
..
}) = p
{
let span = if bound_generic_params.is_empty() {
predicate_span.shrink_to_lo()
} else {
*predicate_span
};
this.with_generic_param_rib(
&bound_generic_params,
NormalRibKind,
LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
|this| {
this.visit_generic_param_vec(&bound_generic_params, false);
this.visit_ty(bounded_ty);
for bound in bounds {
this.visit_param_bound(bound)
}
},
);
} else {
visit::walk_where_predicate(this, p);
}
});
self.diagnostic_metadata.current_where_predicate = previous_value;
}
@ -768,6 +879,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
macro_ns: vec![Rib::new(start_rib_kind)],
},
label_ribs: Vec::new(),
lifetime_ribs: Vec::new(),
current_trait_ref: None,
diagnostic_metadata: DiagnosticMetadata::default(),
// errors at module scope should always be reported
@ -870,6 +982,191 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_upper: bool) {
// For type parameter defaults, we have to ban access
// to following type parameters, as the InternalSubsts can only
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
for param in params.iter() {
match param.kind {
GenericParamKind::Type { .. } => {
forward_ty_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
GenericParamKind::Const { .. } => {
forward_const_ban_rib
.bindings
.insert(Ident::with_dummy_span(param.ident.name), Res::Err);
}
GenericParamKind::Lifetime => {}
}
}
// rust-lang/rust#61631: The type `Self` is essentially
// another type parameter. For ADTs, we consider it
// well-defined only after all of the ADT type parameters have
// been provided. Therefore, we do not allow use of `Self`
// anywhere in ADT type parameter defaults.
//
// (We however cannot ban `Self` for defaults on *all* generic
// lists; e.g. trait generics can usefully refer to `Self`,
// such as in the case of `trait Add<Rhs = Self>`.)
if add_self_upper {
// (`Some` if + only if we are in ADT's generics.)
forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
}
self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
for param in params {
match param.kind {
GenericParamKind::Lifetime => {
for bound in &param.bounds {
this.visit_param_bound(bound);
}
}
GenericParamKind::Type { ref default } => {
for bound in &param.bounds {
this.visit_param_bound(bound);
}
if let Some(ref ty) = default {
this.ribs[TypeNS].push(forward_ty_ban_rib);
this.ribs[ValueNS].push(forward_const_ban_rib);
this.visit_ty(ty);
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this type parameter.
forward_ty_ban_rib
.bindings
.remove(&Ident::with_dummy_span(param.ident.name));
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
// Const parameters can't have param bounds.
assert!(param.bounds.is_empty());
this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
this.visit_ty(ty);
this.ribs[TypeNS].pop().unwrap();
this.ribs[ValueNS].pop().unwrap();
if let Some(ref expr) = default {
this.ribs[TypeNS].push(forward_ty_ban_rib);
this.ribs[ValueNS].push(forward_const_ban_rib);
this.visit_anon_const(expr);
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
}
// Allow all following defaults to refer to this const parameter.
forward_const_ban_rib
.bindings
.remove(&Ident::with_dummy_span(param.ident.name));
}
}
}
})
}
#[tracing::instrument(level = "debug", skip(self, work))]
fn with_lifetime_rib<T>(
&mut self,
kind: LifetimeRibKind,
work: impl FnOnce(&mut Self) -> T,
) -> T {
self.lifetime_ribs.push(LifetimeRib::new(kind));
let ret = work(self);
self.lifetime_ribs.pop();
ret
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
let ident = lifetime.ident;
if ident.name == kw::StaticLifetime {
return;
}
if ident.name == kw::UnderscoreLifetime {
return self.resolve_anonymous_lifetime(lifetime, false);
}
let mut indices = (0..self.lifetime_ribs.len()).rev();
for i in &mut indices {
let rib = &self.lifetime_ribs[i];
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
return;
}
if let LifetimeRibKind::Item = rib.kind {
break;
}
}
let mut outer_res = None;
for i in indices {
let rib = &self.lifetime_ribs[i];
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
outer_res = Some(outer);
break;
}
}
self.emit_undeclared_lifetime_error(lifetime, outer_res);
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
for i in (0..self.lifetime_ribs.len()).rev() {
let rib = &mut self.lifetime_ribs[i];
match rib.kind {
LifetimeRibKind::AnonymousReportError => {
let (msg, note) = if elided {
(
"`&` without an explicit lifetime name cannot be used here",
"explicit lifetime name needed here",
)
} else {
("`'_` cannot be used here", "`'_` is a reserved lifetime name")
};
rustc_errors::struct_span_err!(
self.r.session,
lifetime.ident.span,
E0637,
"{}",
msg,
)
.span_label(lifetime.ident.span, note)
.emit();
return;
}
LifetimeRibKind::AnonymousCreateParameter
| LifetimeRibKind::AnonymousPassThrough
| LifetimeRibKind::Item => return,
_ => {}
}
}
}
#[tracing::instrument(level = "debug", skip(self))]
fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
let id = self.r.next_node_id();
let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
self.resolve_anonymous_lifetime(&lt, true);
}
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable.
fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
@ -950,7 +1247,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
debug!("resolve_adt");
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
this.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
|this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(
Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
@ -958,7 +1259,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
visit::walk_item(this, item);
},
);
});
},
);
});
}
@ -1010,11 +1312,28 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
ItemKind::TyAlias(box TyAlias { ref generics, .. })
| ItemKind::Fn(box Fn { ref generics, .. }) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
});
ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Item,
span: generics.span,
},
|this| visit::walk_item(this, item),
);
}
ItemKind::Fn(box Fn { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Function,
span: generics.span,
},
|this| visit::walk_item(this, item),
);
}
ItemKind::Enum(_, ref generics)
@ -1035,16 +1354,34 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let def = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
self.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Item,
span: generics.span,
},
|this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(
Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
let walk_assoc_item = |this: &mut Self, generics, item| {
this.with_generic_param_rib(generics, AssocItemRibKind, |this| {
let walk_assoc_item =
|this: &mut Self,
generics: &Generics,
kind,
item: &'ast AssocItem| {
this.with_generic_param_rib(
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind },
|this| {
visit::walk_assoc_item(this, item, AssocCtxt::Trait)
});
},
);
};
this.with_trait_items(items, |this| {
@ -1069,10 +1406,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(this, generics, item);
walk_assoc_item(
this,
generics,
LifetimeBinderKind::Function,
item,
);
}
AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
walk_assoc_item(this, generics, item);
AssocItemKind::TyAlias(box TyAlias {
generics,
..
}) => {
walk_assoc_item(
this,
generics,
LifetimeBinderKind::Item,
item,
);
}
AssocItemKind::MacCall(_) => {
panic!("unexpanded macro in resolve!")
@ -1080,19 +1430,32 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
};
}
});
});
});
},
);
},
);
}
ItemKind::TraitAlias(ref generics, ref bounds) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let def = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
self.with_generic_param_rib(
&generics.params,
ItemRibKind(HasGenericParams::Yes),
LifetimeRibKind::Generics {
kind: LifetimeBinderKind::Item,
span: generics.span,
},
|this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(
Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds);
});
});
},
);
},
);
}
ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
@ -1102,7 +1465,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
self.with_item_rib(HasGenericParams::No, |this| {
self.with_item_rib(|this| {
this.visit_ty(ty);
if let Some(expr) = expr {
let constant_item_kind = match item.kind {
@ -1138,13 +1501,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
where
fn with_generic_param_rib<'c, F>(
&'c mut self,
params: &'c Vec<GenericParam>,
kind: RibKind<'a>,
lifetime_kind: LifetimeRibKind,
f: F,
) where
F: FnOnce(&mut Self),
{
debug!("with_generic_param_rib");
let mut function_type_rib = Rib::new(kind);
let mut function_value_rib = Rib::new(kind);
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
let mut seen_bindings = FxHashMap::default();
// We also can't shadow bindings from the parent item
@ -1161,11 +1530,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
add_bindings_for_ns(TypeNS);
}
for param in &generics.params {
if let GenericParamKind::Lifetime = param.kind {
continue;
}
for param in params {
let ident = param.ident.normalize_to_macros_2_0();
debug!("with_generic_param_rib: {}", param.id);
@ -1173,24 +1538,57 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
Entry::Occupied(entry) => {
let span = *entry.get();
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
if !matches!(param.kind, GenericParamKind::Lifetime) {
self.report_error(param.ident.span, err);
}
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
}
}
if param.ident.name == kw::UnderscoreLifetime {
rustc_errors::struct_span_err!(
self.r.session,
param.ident.span,
E0637,
"`'_` cannot be used here"
)
.span_label(param.ident.span, "`'_` is a reserved lifetime name")
.emit();
continue;
}
if param.ident.name == kw::StaticLifetime {
rustc_errors::struct_span_err!(
self.r.session,
param.ident.span,
E0262,
"invalid lifetime parameter name: `{}`",
param.ident,
)
.span_label(param.ident.span, format!("'static is a reserved lifetime name"))
.emit();
continue;
}
let def_id = self.r.local_def_id(param.id);
// Plain insert (no renaming).
let (rib, def_kind) = match param.kind {
GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
_ => unreachable!(),
GenericParamKind::Lifetime => {
function_lifetime_rib.bindings.insert(ident, ());
continue;
}
};
let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
let res = Res::Def(def_kind, def_id.to_def_id());
self.r.record_partial_res(param.id, PartialRes::new(res));
rib.bindings.insert(ident, res);
}
self.lifetime_ribs.push(function_lifetime_rib);
self.ribs[ValueNS].push(function_value_rib);
self.ribs[TypeNS].push(function_type_rib);
@ -1198,6 +1596,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.ribs[TypeNS].pop();
self.ribs[ValueNS].pop();
self.lifetime_ribs.pop();
}
fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
@ -1206,9 +1605,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.label_ribs.pop();
}
fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
let kind = ItemRibKind(has_generic_params);
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
let kind = ItemRibKind(HasGenericParams::No);
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
})
}
// HACK(min_const_generics,const_evaluatable_unchecked): We
@ -1319,9 +1720,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
) {
debug!("resolve_implementation");
// If applicable, create a rib for the type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
// Dummy self type for better errors if `Self` is used in the trait path.
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
let item_def_id = this.r.local_def_id(item_id);
@ -1343,7 +1745,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.visit_ty(self_type);
// Resolve the generic parameters.
this.visit_generics(generics);
// Resolve the items within the impl.
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
|this| {
this.with_current_self_type(self_type, |this| {
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
@ -1385,8 +1790,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
generics,
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
|this| {
// If this is a trait impl, ensure the method
// exists in trait
@ -1413,8 +1819,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("resolve_implementation AssocItemKind::TyAlias");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
generics,
&generics.params,
AssocItemRibKind,
LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item },
|this| {
// If this is a trait impl, ensure the type
// exists in trait
@ -1442,6 +1849,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
});
});
},
);
});
});
});
});

View File

@ -1,6 +1,7 @@
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
use crate::late::{LifetimeBinderKind, LifetimeRibKind};
use crate::path_names_to_string;
use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
@ -1793,6 +1794,102 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
(*ident, within_scope)
})
}
crate fn emit_undeclared_lifetime_error(
&self,
lifetime_ref: &ast::Lifetime,
outer_lifetime_ref: Option<Ident>,
) {
debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
let mut err = if let Some(outer) = outer_lifetime_ref {
let mut err = struct_span_err!(
self.r.session,
lifetime_ref.ident.span,
E0401,
"can't use generic parameters from outer item",
);
err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
err.span_label(outer.span, "lifetime parameter from outer item");
err
} else {
let mut err = struct_span_err!(
self.r.session,
lifetime_ref.ident.span,
E0261,
"use of undeclared lifetime name `{}`",
lifetime_ref.ident
);
err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
err
};
let mut suggest_note = true;
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
LifetimeRibKind::Generics { span, kind } => {
if !span.can_be_used_for_suggestions() && suggest_note {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(
span,
&format!(
"lifetime `{}` is missing in item created through this procedural macro",
lifetime_ref.ident,
),
);
continue;
}
let higher_ranked = matches!(
kind,
LifetimeBinderKind::BareFnType
| LifetimeBinderKind::PolyTrait
| LifetimeBinderKind::WhereBound
);
let (span, sugg) = if span.is_empty() {
let sugg = format!(
"{}<{}>{}",
if higher_ranked { "for" } else { "" },
lifetime_ref.ident,
if higher_ranked { " " } else { "" },
);
(span, sugg)
} else {
let span =
self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
let sugg = format!("{}, ", lifetime_ref.ident);
(span, sugg)
};
if higher_ranked {
err.span_suggestion(
span,
&format!(
"consider making the {} lifetime-generic with a new `{}` lifetime",
kind.descr(),
lifetime_ref
),
sugg,
Applicability::MaybeIncorrect,
);
err.note_once(
"for more information on higher-ranked polymorphism, visit \
https://doc.rust-lang.org/nomicon/hrtb.html",
);
} else {
err.span_suggestion(
span,
&format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
sugg,
Applicability::MaybeIncorrect,
);
}
}
LifetimeRibKind::Item => break,
_ => {}
}
}
err.emit();
}
}
impl<'tcx> LifetimeContext<'_, 'tcx> {
@ -1810,67 +1907,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
)
}
crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
let mut err = struct_span_err!(
self.tcx.sess,
lifetime_ref.span,
E0261,
"use of undeclared lifetime name `{}`",
lifetime_ref
);
err.span_label(lifetime_ref.span, "undeclared lifetime");
let mut suggested_spans = vec![];
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
!matches!(
p.kind,
hir::GenericParamKind::Type { synthetic: true, .. }
| hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Elided,
}
)
}) {
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
} else {
(generics.span, format!("<{}>", lifetime_ref))
};
if suggested_spans.contains(&span) {
continue;
}
suggested_spans.push(span);
if span.can_be_used_for_suggestions() {
err.span_suggestion(
span,
&format!("consider introducing lifetime `{}` here", lifetime_ref),
sugg,
Applicability::MaybeIncorrect,
);
}
}
MissingLifetimeSpot::HigherRanked { span, span_type } => {
err.span_suggestion(
*span,
&format!(
"consider making the {} lifetime-generic with a new `{}` lifetime",
span_type.descr(),
lifetime_ref
),
span_type.suggestion(&lifetime_ref.to_string()),
Applicability::MaybeIncorrect,
);
err.note(
"for more information on higher-ranked polymorphism, visit \
https://doc.rust-lang.org/nomicon/hrtb.html",
);
}
_ => {}
}
}
err.emit();
}
/// Returns whether to add `'static` lifetime to the suggested lifetime list.
crate fn report_elision_failure(
&mut self,

View File

@ -2312,7 +2312,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.insert_lifetime(lifetime_ref, def);
} else {
self.emit_undeclared_lifetime_error(lifetime_ref);
self.tcx.sess.delay_span_bug(
lifetime_ref.span,
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
);
}
}
@ -3119,18 +3122,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if let hir::ParamName::Plain(_) = lifetime_i_name {
let name = lifetime_i_name.ident().name;
if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
let mut err = struct_span_err!(
self.tcx.sess,
self.tcx.sess.delay_span_bug(
lifetime_i.span,
E0262,
"invalid lifetime parameter name: `{}`",
lifetime_i.name.ident(),
&format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
);
err.span_label(
lifetime_i.span,
format!("{} is a reserved lifetime name", name),
);
err.emit();
}
}

View File

@ -11,6 +11,7 @@
#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(never_type)]
@ -1358,9 +1359,17 @@ impl<'a> Resolver<'a> {
}
pub fn next_node_id(&mut self) -> NodeId {
let next =
self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
let start = self.next_node_id;
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
self.next_node_id = ast::NodeId::from_u32(next);
start
}
pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
let start = self.next_node_id;
let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
self.next_node_id = ast::NodeId::from_usize(end);
start..self.next_node_id
}
pub fn lint_buffer(&mut self) -> &mut LintBuffer {