Report elision failures on the AST.
This commit is contained in:
@@ -21,6 +21,7 @@ use rustc_hir::def::Namespace::{self, *};
|
||||
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::{PrimTy, TraitCandidate};
|
||||
use rustc_middle::middle::resolve_lifetime::Set1;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
@@ -43,6 +44,10 @@ type IdentMap<T> = FxHashMap<Ident, T>;
|
||||
/// Map from the name in a pattern to its binding mode.
|
||||
type BindingMap = IdentMap<BindingInfo>;
|
||||
|
||||
use diagnostics::{
|
||||
ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct BindingInfo {
|
||||
span: Span,
|
||||
@@ -258,10 +263,13 @@ enum LifetimeRibKind {
|
||||
AnonymousReportError,
|
||||
|
||||
/// Pass responsibility to `resolve_lifetime` code for all cases.
|
||||
AnonymousPassThrough(NodeId, /* in_fn_return */ bool),
|
||||
AnonymousPassThrough(NodeId),
|
||||
|
||||
/// Replace all anonymous lifetimes by provided lifetime.
|
||||
Elided(LifetimeRes),
|
||||
|
||||
/// Signal we cannot find which should be the anonymous lifetime.
|
||||
ElisionFailure,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -525,6 +533,10 @@ struct DiagnosticMetadata<'ast> {
|
||||
|
||||
/// When processing impl trait
|
||||
currently_processing_impl_trait: Option<(TraitRef, Ty)>,
|
||||
|
||||
/// Accumulate the errors due to missed lifetime elision,
|
||||
/// and report them all at once for each function.
|
||||
current_elision_failures: Vec<MissingLifetime>,
|
||||
}
|
||||
|
||||
struct LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
@@ -543,6 +555,13 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
/// The current set of local scopes for lifetimes.
|
||||
lifetime_ribs: Vec<LifetimeRib>,
|
||||
|
||||
/// We are looking for lifetimes in an elision context.
|
||||
/// The set contains all the resolutions that we encountered so far.
|
||||
/// They will be used to determine the correct lifetime for the fn return type.
|
||||
/// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
|
||||
/// lifetimes.
|
||||
lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
|
||||
|
||||
/// The trait that the current context can refer to.
|
||||
current_trait_ref: Option<(Module<'a>, TraitRef)>,
|
||||
|
||||
@@ -612,8 +631,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
TyKind::Rptr(None, _) => {
|
||||
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
|
||||
// NodeId `ty.id`.
|
||||
// This span will be used in case of elision failure.
|
||||
let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
|
||||
self.resolve_elided_lifetime(ty.id, span);
|
||||
visit::walk_ty(self, ty);
|
||||
}
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
self.diagnostic_metadata.current_type_path = Some(ty);
|
||||
@@ -639,8 +660,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
},
|
||||
|this| this.visit_path(&path, ty.id),
|
||||
);
|
||||
self.diagnostic_metadata.current_type_path = prev_ty;
|
||||
return;
|
||||
} else {
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
TyKind::ImplicitSelf => {
|
||||
@@ -654,9 +675,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
)
|
||||
.map_or(Res::Err, |d| d.res());
|
||||
self.r.record_partial_res(ty.id, PartialRes::new(res));
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
TyKind::ImplTrait(..) => {
|
||||
let candidates = self.lifetime_elision_candidates.take();
|
||||
visit::walk_ty(self, ty);
|
||||
self.lifetime_elision_candidates = candidates;
|
||||
}
|
||||
TyKind::TraitObject(ref bounds, ..) => {
|
||||
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
TyKind::BareFn(ref bare_fn) => {
|
||||
let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
|
||||
@@ -670,25 +698,20 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
},
|
||||
|this| {
|
||||
this.visit_generic_params(&bare_fn.generic_params, false);
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: ty.id,
|
||||
report_in_path: false,
|
||||
},
|
||||
|this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
|
||||
);
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(ty.id, true),
|
||||
|this| this.visit_fn_ret_ty(&bare_fn.decl.output),
|
||||
this.resolve_fn_signature(
|
||||
ty.id,
|
||||
None,
|
||||
false,
|
||||
// We don't need to deal with patterns in parameters, because
|
||||
// they are not possible for foreign or bodiless functions.
|
||||
bare_fn.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
|
||||
&bare_fn.decl.output,
|
||||
);
|
||||
},
|
||||
);
|
||||
self.diagnostic_metadata.current_trait_object = prev;
|
||||
return;
|
||||
)
|
||||
}
|
||||
_ => (),
|
||||
_ => visit::walk_ty(self, ty),
|
||||
}
|
||||
visit::walk_ty(self, ty);
|
||||
self.diagnostic_metadata.current_trait_object = prev;
|
||||
self.diagnostic_metadata.current_type_path = prev_ty;
|
||||
}
|
||||
@@ -762,18 +785,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
| FnKind::Fn(_, _, sig, _, generics, None) => {
|
||||
self.visit_fn_header(&sig.header);
|
||||
self.visit_generics(generics);
|
||||
// We don't need to deal with patterns in parameters, because
|
||||
// they are not possible for foreign or bodiless functions.
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: fn_id,
|
||||
report_in_path: false,
|
||||
},
|
||||
|this| walk_list!(this, visit_param, &sig.decl.inputs),
|
||||
);
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, true),
|
||||
|this| this.visit_fn_ret_ty(&sig.decl.output),
|
||||
self.resolve_fn_signature(
|
||||
fn_id,
|
||||
None,
|
||||
sig.decl.has_self(),
|
||||
sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
|
||||
&sig.decl.output,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -798,19 +815,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
let declaration = &sig.decl;
|
||||
let async_node_id = sig.header.asyncness.opt_return_id();
|
||||
|
||||
// Argument-position elided lifetimes must be transformed into fresh
|
||||
// generic parameters. This is especially useful for `async fn`, where
|
||||
// these fresh generic parameters can be applied to the opaque `impl Trait`
|
||||
// return type.
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: fn_id,
|
||||
// Only emit a hard error for `async fn`, since this kind of
|
||||
// elision has always been allowed in regular `fn`s.
|
||||
report_in_path: async_node_id.is_some(),
|
||||
},
|
||||
// Add each argument to the rib.
|
||||
|this| this.resolve_params(&declaration.inputs),
|
||||
this.resolve_fn_signature(
|
||||
fn_id,
|
||||
async_node_id,
|
||||
declaration.has_self(),
|
||||
declaration
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
|
||||
&declaration.output,
|
||||
);
|
||||
|
||||
// Construct the list of in-scope lifetime parameters for async lowering.
|
||||
@@ -849,23 +862,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
.insert(async_node_id, extra_lifetime_params);
|
||||
}
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(
|
||||
// For async fn, the return type appears inside a custom
|
||||
// `impl Future` RPIT, so we override the binder's id.
|
||||
async_node_id.unwrap_or(fn_id),
|
||||
true,
|
||||
),
|
||||
|this| visit::walk_fn_ret_ty(this, &declaration.output),
|
||||
);
|
||||
|
||||
if let Some(body) = body {
|
||||
// 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
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id),
|
||||
|this| this.visit_block(body),
|
||||
);
|
||||
|
||||
@@ -893,7 +896,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
this.with_lifetime_rib(
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, true)
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id)
|
||||
}
|
||||
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
|
||||
},
|
||||
@@ -905,7 +908,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
let previous_state = replace(&mut this.in_func_body, true);
|
||||
// Resolve the function body, potentially inside the body of an async closure
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id, false),
|
||||
LifetimeRibKind::AnonymousPassThrough(fn_id),
|
||||
|this| this.visit_expr(body),
|
||||
);
|
||||
|
||||
@@ -1035,16 +1038,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
kind: LifetimeBinderKind::PolyTrait,
|
||||
..
|
||||
} => {
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder,
|
||||
report_in_path: false,
|
||||
},
|
||||
|this| walk_list!(this, visit_ty, &p_args.inputs),
|
||||
);
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(binder, true),
|
||||
|this| visit::walk_fn_ret_ty(this, &p_args.output),
|
||||
self.resolve_fn_signature(
|
||||
binder,
|
||||
None,
|
||||
false,
|
||||
p_args.inputs.iter().map(|ty| (None, &**ty)),
|
||||
&p_args.output,
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -1058,6 +1057,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
| LifetimeRibKind::AnonymousCreateParameter { .. }
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::Elided(_)
|
||||
| LifetimeRibKind::ElisionFailure
|
||||
| LifetimeRibKind::AnonConst
|
||||
| LifetimeRibKind::ConstGeneric => {}
|
||||
}
|
||||
@@ -1162,6 +1162,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
},
|
||||
label_ribs: Vec::new(),
|
||||
lifetime_ribs: Vec::new(),
|
||||
lifetime_elision_candidates: None,
|
||||
current_trait_ref: None,
|
||||
diagnostic_metadata: Box::new(DiagnosticMetadata::default()),
|
||||
// errors at module scope should always be reported
|
||||
@@ -1368,7 +1369,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
work: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
self.lifetime_ribs.push(LifetimeRib::new(kind));
|
||||
let outer_elision_candidates = self.lifetime_elision_candidates.take();
|
||||
let ret = work(self);
|
||||
self.lifetime_elision_candidates = outer_elision_candidates;
|
||||
self.lifetime_ribs.pop();
|
||||
ret
|
||||
}
|
||||
@@ -1378,7 +1381,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
let ident = lifetime.ident;
|
||||
|
||||
if ident.name == kw::StaticLifetime {
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Static,
|
||||
LifetimeElisionCandidate::Named,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1391,7 +1398,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
let rib = &self.lifetime_ribs[i];
|
||||
let normalized_ident = ident.normalize_to_macros_2_0();
|
||||
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
|
||||
self.record_lifetime_res(lifetime.id, res);
|
||||
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
|
||||
|
||||
if let LifetimeRes::Param { param, .. } = res {
|
||||
match self.lifetime_uses.entry(param) {
|
||||
@@ -1405,12 +1412,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
// Do not suggest eliding a lifetime where an anonymous
|
||||
// lifetime would be illegal.
|
||||
LifetimeRibKind::Item
|
||||
| LifetimeRibKind::AnonymousPassThrough(_, true)
|
||||
| LifetimeRibKind::AnonymousReportError => {
|
||||
Some(LifetimeUseSet::Many)
|
||||
}
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
|
||||
// An anonymous lifetime is legal here, go ahead.
|
||||
LifetimeRibKind::AnonymousPassThrough(_, false)
|
||||
LifetimeRibKind::AnonymousPassThrough(_)
|
||||
| LifetimeRibKind::AnonymousCreateParameter { .. } => {
|
||||
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
|
||||
}
|
||||
@@ -1442,12 +1447,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
LifetimeRibKind::Item => break,
|
||||
LifetimeRibKind::ConstGeneric => {
|
||||
self.emit_non_static_lt_in_const_generic_error(lifetime);
|
||||
self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Error,
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::AnonConst => {
|
||||
self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
|
||||
self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Error,
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
@@ -1465,19 +1478,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
}
|
||||
|
||||
self.emit_undeclared_lifetime_error(lifetime, outer_res);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
|
||||
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
|
||||
|
||||
let missing_lifetime = MissingLifetime {
|
||||
id: lifetime.id,
|
||||
span: lifetime.ident.span,
|
||||
kind: if elided {
|
||||
MissingLifetimeKind::Ampersand
|
||||
} else {
|
||||
MissingLifetimeKind::Underscore
|
||||
},
|
||||
count: 1,
|
||||
};
|
||||
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||
for i in (0..self.lifetime_ribs.len()).rev() {
|
||||
let rib = &mut self.lifetime_ribs[i];
|
||||
debug!(?rib.kind);
|
||||
match rib.kind {
|
||||
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||
let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
|
||||
self.record_lifetime_res(lifetime.id, res);
|
||||
self.record_lifetime_res(lifetime.id, res, elision_candidate);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::AnonymousReportError => {
|
||||
@@ -1499,18 +1524,24 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
.span_label(lifetime.ident.span, note)
|
||||
.emit();
|
||||
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::AnonymousPassThrough(node_id, _) => {
|
||||
LifetimeRibKind::AnonymousPassThrough(node_id) => {
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Anonymous { binder: node_id, elided },
|
||||
elision_candidate,
|
||||
);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::Elided(res) => {
|
||||
self.record_lifetime_res(lifetime.id, res);
|
||||
self.record_lifetime_res(lifetime.id, res, elision_candidate);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::ElisionFailure => {
|
||||
self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
||||
return;
|
||||
}
|
||||
LifetimeRibKind::Item => break,
|
||||
@@ -1519,23 +1550,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
| LifetimeRibKind::AnonConst => {}
|
||||
}
|
||||
}
|
||||
// This resolution is wrong, it passes the work to HIR lifetime resolution.
|
||||
// We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
|
||||
);
|
||||
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
|
||||
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
|
||||
}
|
||||
|
||||
#[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.record_lifetime_res(
|
||||
anchor_id,
|
||||
LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
|
||||
let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
|
||||
self.resolve_anonymous_lifetime(<, true);
|
||||
}
|
||||
|
||||
@@ -1620,16 +1648,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
self.record_lifetime_res(
|
||||
segment_id,
|
||||
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
|
||||
if !missing {
|
||||
// Do not create a parameter for patterns and expressions.
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
|
||||
LifetimeRibKind::AnonymousPassThrough(binder) => {
|
||||
let res = LifetimeRes::Anonymous { binder, elided: true };
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1644,12 +1673,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
let res =
|
||||
LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
|
||||
}
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::AnonymousCreateParameter { .. }
|
||||
| LifetimeRibKind::Elided(_)
|
||||
| LifetimeRibKind::ElisionFailure
|
||||
| LifetimeRibKind::Generics { .. }
|
||||
| LifetimeRibKind::ConstGeneric
|
||||
| LifetimeRibKind::AnonConst => {}
|
||||
@@ -1658,6 +1688,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let missing_lifetime = MissingLifetime {
|
||||
id: node_ids.start,
|
||||
span: elided_lifetime_span,
|
||||
kind: if segment.has_generic_args {
|
||||
MissingLifetimeKind::Comma
|
||||
} else {
|
||||
MissingLifetimeKind::Brackets
|
||||
},
|
||||
count: expected_lifetimes,
|
||||
};
|
||||
let mut should_lint = true;
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
@@ -1688,29 +1728,60 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
should_lint = false;
|
||||
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, LifetimeRes::Error);
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
LifetimeRes::Error,
|
||||
LifetimeElisionCandidate::Named,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Do not create a parameter for patterns and expressions.
|
||||
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||
// Group all suggestions into the first record.
|
||||
let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||
for id in node_ids {
|
||||
let res = self.create_fresh_lifetime(id, ident, binder);
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
res,
|
||||
replace(&mut candidate, LifetimeElisionCandidate::Named),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// `PassThrough` is the normal case.
|
||||
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
|
||||
LifetimeRibKind::AnonymousPassThrough(binder) => {
|
||||
let res = LifetimeRes::Anonymous { binder, elided: true };
|
||||
let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
res,
|
||||
replace(&mut candidate, LifetimeElisionCandidate::Ignore),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::Elided(res) => {
|
||||
let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
res,
|
||||
replace(&mut candidate, LifetimeElisionCandidate::Ignore),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::ElisionFailure => {
|
||||
self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
LifetimeRes::Error,
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1719,13 +1790,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
// we simply resolve to an implicit lifetime, which will be checked later, at
|
||||
// which point a suitable error will be emitted.
|
||||
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
|
||||
// FIXME(cjgillot) This resolution is wrong, but this does not matter
|
||||
// since these cases are erroneous anyway. Lifetime resolution should
|
||||
// emit a "missing lifetime specifier" diagnostic.
|
||||
let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
|
||||
for id in node_ids {
|
||||
self.record_lifetime_res(id, res);
|
||||
self.record_lifetime_res(
|
||||
id,
|
||||
LifetimeRes::Error,
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
}
|
||||
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
|
||||
break;
|
||||
}
|
||||
LifetimeRibKind::Generics { .. }
|
||||
@@ -1752,13 +1824,223 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
|
||||
fn record_lifetime_res(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
res: LifetimeRes,
|
||||
candidate: LifetimeElisionCandidate,
|
||||
) {
|
||||
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
|
||||
panic!(
|
||||
"lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
|
||||
id, prev_res, res
|
||||
)
|
||||
}
|
||||
match res {
|
||||
LifetimeRes::Param { .. }
|
||||
| LifetimeRes::Fresh { .. }
|
||||
| LifetimeRes::Anonymous { .. }
|
||||
| LifetimeRes::Static => {
|
||||
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
|
||||
candidates.insert(res, candidate);
|
||||
}
|
||||
}
|
||||
LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
|
||||
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
|
||||
panic!(
|
||||
"lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
|
||||
id, prev_res, res
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform resolution of a function signature, accounting for lifetime elision.
|
||||
#[tracing::instrument(level = "debug", skip(self, inputs))]
|
||||
fn resolve_fn_signature(
|
||||
&mut self,
|
||||
fn_id: NodeId,
|
||||
async_node_id: Option<NodeId>,
|
||||
has_self: bool,
|
||||
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
|
||||
output_ty: &'ast FnRetTy,
|
||||
) {
|
||||
// Add each argument to the rib.
|
||||
let parameter_rib = LifetimeRibKind::AnonymousCreateParameter {
|
||||
binder: fn_id,
|
||||
report_in_path: async_node_id.is_some(),
|
||||
};
|
||||
let elision_lifetime =
|
||||
self.with_lifetime_rib(parameter_rib, |this| this.resolve_fn_params(has_self, inputs));
|
||||
debug!(?elision_lifetime);
|
||||
|
||||
let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
|
||||
let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
|
||||
LifetimeRibKind::Elided(*res)
|
||||
} else {
|
||||
LifetimeRibKind::ElisionFailure
|
||||
};
|
||||
self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty));
|
||||
let elision_failures =
|
||||
replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures);
|
||||
if !elision_failures.is_empty() {
|
||||
let Err(failure_info) = elision_lifetime else { bug!() };
|
||||
self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve inside function parameters and parameter types.
|
||||
/// Returns the lifetime for elision in fn return type,
|
||||
/// or diagnostic information in case of elision failure.
|
||||
fn resolve_fn_params(
|
||||
&mut self,
|
||||
has_self: bool,
|
||||
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
|
||||
) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
|
||||
let outer_candidates =
|
||||
replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
|
||||
|
||||
let mut elision_lifetime = None;
|
||||
let mut lifetime_count = 0;
|
||||
let mut parameter_info = Vec::new();
|
||||
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
for (index, (pat, ty)) in inputs.enumerate() {
|
||||
debug!(?pat, ?ty);
|
||||
if let Some(pat) = pat {
|
||||
self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
|
||||
}
|
||||
self.visit_ty(ty);
|
||||
|
||||
if let Some(ref candidates) = self.lifetime_elision_candidates {
|
||||
let new_count = candidates.len();
|
||||
let local_count = new_count - lifetime_count;
|
||||
if local_count != 0 {
|
||||
parameter_info.push(ElisionFnParameter {
|
||||
index,
|
||||
ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
|
||||
Some(ident)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
lifetime_count: local_count,
|
||||
span: ty.span,
|
||||
});
|
||||
}
|
||||
lifetime_count = new_count;
|
||||
}
|
||||
|
||||
// Handle `self` specially.
|
||||
if index == 0 && has_self {
|
||||
let self_lifetime = self.find_lifetime_for_self(ty);
|
||||
if let Set1::One(lifetime) = self_lifetime {
|
||||
elision_lifetime = Some(lifetime);
|
||||
self.lifetime_elision_candidates = None;
|
||||
} else {
|
||||
self.lifetime_elision_candidates = Some(Default::default());
|
||||
lifetime_count = 0;
|
||||
}
|
||||
}
|
||||
debug!("(resolving function / closure) recorded parameter");
|
||||
}
|
||||
|
||||
let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
|
||||
debug!(?all_candidates);
|
||||
|
||||
if let Some(res) = elision_lifetime {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
// We do not have a `self` candidate, look at the full list.
|
||||
let all_candidates = all_candidates.unwrap();
|
||||
if all_candidates.len() == 1 {
|
||||
Ok(*all_candidates.first().unwrap().0)
|
||||
} else {
|
||||
let all_candidates = all_candidates
|
||||
.into_iter()
|
||||
.filter_map(|(_, candidate)| match candidate {
|
||||
LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
|
||||
LifetimeElisionCandidate::Missing(missing) => Some(missing),
|
||||
})
|
||||
.collect();
|
||||
Err((all_candidates, parameter_info))
|
||||
}
|
||||
}
|
||||
|
||||
/// List all the lifetimes that appear in the provided type.
|
||||
fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
|
||||
struct SelfVisitor<'r, 'a> {
|
||||
r: &'r Resolver<'a>,
|
||||
impl_self: Option<Res>,
|
||||
lifetime: Set1<LifetimeRes>,
|
||||
}
|
||||
|
||||
impl SelfVisitor<'_, '_> {
|
||||
// Look for `self: &'a Self` - also desugared from `&'a self`,
|
||||
// and if that matches, use it for elision and return early.
|
||||
fn is_self_ty(&self, ty: &Ty) -> bool {
|
||||
match ty.kind {
|
||||
TyKind::ImplicitSelf => true,
|
||||
TyKind::Path(None, _) => {
|
||||
let path_res = self.r.partial_res_map[&ty.id].base_res();
|
||||
if let Res::SelfTy { .. } = path_res {
|
||||
return true;
|
||||
}
|
||||
Some(path_res) == self.impl_self
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
trace!("SelfVisitor considering ty={:?}", ty);
|
||||
if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
|
||||
let lt_id = if let Some(lt) = lt {
|
||||
lt.id
|
||||
} else {
|
||||
let res = self.r.lifetimes_res_map[&ty.id];
|
||||
let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
|
||||
start
|
||||
};
|
||||
let lt_res = self.r.lifetimes_res_map[<_id];
|
||||
trace!("SelfVisitor inserting res={:?}", lt_res);
|
||||
self.lifetime.insert(lt_res);
|
||||
}
|
||||
visit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
let impl_self = self
|
||||
.diagnostic_metadata
|
||||
.current_self_type
|
||||
.as_ref()
|
||||
.and_then(|ty| {
|
||||
if let TyKind::Path(None, _) = ty.kind {
|
||||
self.r.partial_res_map.get(&ty.id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|res| res.base_res())
|
||||
.filter(|res| {
|
||||
// Permit the types that unambiguously always
|
||||
// result in the same type constructor being used
|
||||
// (it can't differ between `Self` and `self`).
|
||||
matches!(
|
||||
res,
|
||||
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
|
||||
)
|
||||
});
|
||||
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
|
||||
visitor.visit_ty(ty);
|
||||
trace!("SelfVisitor found={:?}", visitor.lifetime);
|
||||
visitor.lifetime
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
|
||||
@@ -1983,22 +2265,29 @@ 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(|this| {
|
||||
this.visit_ty(ty);
|
||||
if let Some(expr) = expr {
|
||||
let constant_item_kind = match item.kind {
|
||||
ItemKind::Const(..) => ConstantItemKind::Const,
|
||||
ItemKind::Static(..) => ConstantItemKind::Static,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
HasGenericParams::Yes,
|
||||
Some((item.ident, constant_item_kind)),
|
||||
|this| this.visit_expr(expr),
|
||||
);
|
||||
}
|
||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(item.id),
|
||||
|this| {
|
||||
if let Some(expr) = expr {
|
||||
let constant_item_kind = match item.kind {
|
||||
ItemKind::Const(..) => ConstantItemKind::Const,
|
||||
ItemKind::Static(..) => ConstantItemKind::Static,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
HasGenericParams::Yes,
|
||||
Some((item.ident, constant_item_kind)),
|
||||
|this| this.visit_expr(expr),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2069,7 +2358,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
{
|
||||
diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_res(param.id, LifetimeRes::Error);
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2080,7 +2369,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
self.report_error(param.ident.span, err);
|
||||
if let GenericParamKind::Lifetime = param.kind {
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_res(param.id, LifetimeRes::Error);
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2099,7 +2388,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
.span_label(param.ident.span, "`'_` is a reserved lifetime name")
|
||||
.emit();
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_res(param.id, LifetimeRes::Error);
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2114,7 +2403,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
.span_label(param.ident.span, "'static is a reserved lifetime name")
|
||||
.emit();
|
||||
// Record lifetime res, so lowering knows there is something fishy.
|
||||
self.record_lifetime_res(param.id, LifetimeRes::Error);
|
||||
self.record_lifetime_param(param.id, LifetimeRes::Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2126,7 +2415,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
|
||||
GenericParamKind::Lifetime => {
|
||||
let res = LifetimeRes::Param { param: def_id, binder };
|
||||
self.record_lifetime_res(param.id, res);
|
||||
self.record_lifetime_param(param.id, res);
|
||||
function_lifetime_rib.bindings.insert(ident, (param.id, res));
|
||||
continue;
|
||||
}
|
||||
@@ -2149,7 +2438,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
self.ribs[TypeNS].pop();
|
||||
self.ribs[ValueNS].pop();
|
||||
self.lifetime_ribs.pop();
|
||||
let function_lifetime_rib = self.lifetime_ribs.pop().unwrap();
|
||||
|
||||
// Do not account for the parameters we just bound for function lifetime elision.
|
||||
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
|
||||
for (_, res) in function_lifetime_rib.bindings.values() {
|
||||
candidates.remove(res);
|
||||
}
|
||||
}
|
||||
|
||||
if let LifetimeBinderKind::BareFnType
|
||||
| LifetimeBinderKind::WhereBound
|
||||
@@ -2247,20 +2543,26 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
self.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
HasGenericParams::Yes,
|
||||
None,
|
||||
|this| this.visit_expr(expr),
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(item.id),
|
||||
|this| {
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
HasGenericParams::Yes,
|
||||
None,
|
||||
|this| this.visit_expr(expr),
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { generics, .. }) => {
|
||||
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
|
||||
walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self
|
||||
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
||||
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
|
||||
}),
|
||||
AssocItemKind::MacCall(_) => {
|
||||
panic!("unexpanded macro in resolve!")
|
||||
}
|
||||
@@ -2331,7 +2633,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
LifetimeRibKind::Generics {
|
||||
span: generics.span,
|
||||
binder: item_id,
|
||||
kind: LifetimeBinderKind::ImplBlock
|
||||
kind: LifetimeBinderKind::ImplBlock,
|
||||
},
|
||||
|this| {
|
||||
// Dummy self type for better errors if `Self` is used in the trait path.
|
||||
@@ -2351,7 +2653,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
// Register the trait definitions from here.
|
||||
if let Some(trait_id) = trait_id {
|
||||
this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
|
||||
this.r
|
||||
.trait_impls
|
||||
.entry(trait_id)
|
||||
.or_default()
|
||||
.push(item_def_id);
|
||||
}
|
||||
|
||||
let item_def_id = item_def_id.to_def_id();
|
||||
@@ -2370,21 +2676,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
this.visit_generics(generics);
|
||||
|
||||
// Resolve the items within the impl.
|
||||
this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
|
||||
|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, ...)");
|
||||
for item in impl_items {
|
||||
this.resolve_impl_item(&**item);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
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, ...)");
|
||||
for item in impl_items {
|
||||
this.resolve_impl_item(&**item);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
)
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -2415,9 +2717,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
|
||||
this.visit_expr(expr)
|
||||
});
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousPassThrough(item.id),
|
||||
|this| {
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
HasGenericParams::Yes,
|
||||
None,
|
||||
|this| this.visit_expr(expr),
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { generics, .. }) => {
|
||||
@@ -2459,18 +2769,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
kind: LifetimeBinderKind::Item,
|
||||
},
|
||||
|this| {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(
|
||||
item.id,
|
||||
item.ident,
|
||||
&item.kind,
|
||||
TypeNS,
|
||||
item.span,
|
||||
|i, s, c| TypeNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
|
||||
// If this is a trait impl, ensure the type
|
||||
// exists in trait
|
||||
this.check_trait_item(
|
||||
item.id,
|
||||
item.ident,
|
||||
&item.kind,
|
||||
TypeNS,
|
||||
item.span,
|
||||
|i, s, c| TypeNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
|
||||
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user