Report undeclared lifetimes on AST.
This commit is contained in:
parent
4cfceeabdc
commit
fc9f25531a
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 ¶m.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 ¶m.bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
}
|
||||
GenericParamKind::Type { ref default } => {
|
||||
for bound in ¶m.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(<, 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> {
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user