Separate AnonymousCreateParameter
and ReportElidedInPath
.
This commit is contained in:
parent
237e267b80
commit
bf38ba260d
1 changed files with 112 additions and 81 deletions
|
@ -238,14 +238,14 @@ enum LifetimeRibKind {
|
||||||
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
|
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
|
||||||
AnonConst,
|
AnonConst,
|
||||||
|
|
||||||
/// For **Modern** cases, create a new anonymous region parameter
|
/// Create a new anonymous region parameter and reference it.
|
||||||
/// and reference that.
|
|
||||||
///
|
///
|
||||||
/// For **Dyn Bound** cases, pass responsibility to
|
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
|
||||||
/// `resolve_lifetime` code.
|
/// ```ignore
|
||||||
///
|
/// struct Foo<'a> { .. }
|
||||||
/// For **Deprecated** cases, report an error.
|
/// fn foo(x: Foo) {}
|
||||||
AnonymousCreateParameter(NodeId),
|
/// ```
|
||||||
|
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
|
||||||
|
|
||||||
/// Give a hard error when either `&` or `'_` is written. Used to
|
/// Give a hard error when either `&` or `'_` is written. Used to
|
||||||
/// rule out things like `where T: Foo<'_>`. Does not imply an
|
/// rule out things like `where T: Foo<'_>`. Does not imply an
|
||||||
|
@ -764,7 +764,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
// return type.
|
// return type.
|
||||||
this.with_lifetime_rib(
|
this.with_lifetime_rib(
|
||||||
if async_node_id.is_some() {
|
if async_node_id.is_some() {
|
||||||
LifetimeRibKind::AnonymousCreateParameter(fn_id)
|
LifetimeRibKind::AnonymousCreateParameter {
|
||||||
|
binder: fn_id,
|
||||||
|
report_in_path: true,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LifetimeRibKind::AnonymousPassThrough(fn_id, false)
|
LifetimeRibKind::AnonymousPassThrough(fn_id, false)
|
||||||
},
|
},
|
||||||
|
@ -791,7 +794,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
);
|
);
|
||||||
match rib.kind {
|
match rib.kind {
|
||||||
LifetimeRibKind::Item => break,
|
LifetimeRibKind::Item => break,
|
||||||
LifetimeRibKind::AnonymousCreateParameter(binder) => {
|
LifetimeRibKind::AnonymousCreateParameter {
|
||||||
|
binder, ..
|
||||||
|
} => {
|
||||||
if let Some(earlier_fresh) =
|
if let Some(earlier_fresh) =
|
||||||
this.r.extra_lifetime_params_map.get(&binder)
|
this.r.extra_lifetime_params_map.get(&binder)
|
||||||
{
|
{
|
||||||
|
@ -1295,7 +1300,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
// An anonymous lifetime is legal here, go ahead.
|
// An anonymous lifetime is legal here, go ahead.
|
||||||
LifetimeRibKind::AnonymousPassThrough(_, false)
|
LifetimeRibKind::AnonymousPassThrough(_, false)
|
||||||
| LifetimeRibKind::AnonymousCreateParameter(_) => {
|
| LifetimeRibKind::AnonymousCreateParameter { .. } => {
|
||||||
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
|
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -1350,8 +1355,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
for i in (0..self.lifetime_ribs.len()).rev() {
|
for i in (0..self.lifetime_ribs.len()).rev() {
|
||||||
let rib = &mut self.lifetime_ribs[i];
|
let rib = &mut self.lifetime_ribs[i];
|
||||||
match rib.kind {
|
match rib.kind {
|
||||||
LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
|
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||||
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
|
let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
|
||||||
|
self.record_lifetime_res(lifetime.id, res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LifetimeRibKind::AnonymousReportError => {
|
LifetimeRibKind::AnonymousReportError => {
|
||||||
|
@ -1408,7 +1414,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
|
fn create_fresh_lifetime(
|
||||||
|
&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
ident: Ident,
|
||||||
|
item_node_id: NodeId,
|
||||||
|
) -> LifetimeRes {
|
||||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||||
debug!(?ident.span);
|
debug!(?ident.span);
|
||||||
let item_def_id = self.r.local_def_id(item_node_id);
|
let item_def_id = self.r.local_def_id(item_node_id);
|
||||||
|
@ -1423,12 +1434,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
debug!(?def_id);
|
debug!(?def_id);
|
||||||
|
|
||||||
let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
|
let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
|
||||||
self.record_lifetime_res(id, region);
|
|
||||||
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
|
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
|
||||||
ident,
|
ident,
|
||||||
def_node_id,
|
def_node_id,
|
||||||
region,
|
region,
|
||||||
));
|
));
|
||||||
|
region
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
|
@ -1471,59 +1482,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let missing = match source {
|
let mut should_lint = match source {
|
||||||
PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
|
PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
|
||||||
PathSource::Expr(..)
|
PathSource::Expr(..)
|
||||||
| PathSource::Pat
|
| PathSource::Pat
|
||||||
| PathSource::Struct
|
| PathSource::Struct
|
||||||
| PathSource::TupleStruct(..) => false,
|
| PathSource::TupleStruct(..) => false,
|
||||||
};
|
};
|
||||||
let mut res = LifetimeRes::Error;
|
|
||||||
for rib in self.lifetime_ribs.iter().rev() {
|
|
||||||
match rib.kind {
|
|
||||||
// In create-parameter mode we error here because we don't want to support
|
|
||||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
|
||||||
// both of which work using the `CreateParameter` mode:
|
|
||||||
//
|
|
||||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
|
||||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
|
||||||
LifetimeRibKind::AnonymousCreateParameter(_) => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// `PassThrough` is the normal case.
|
|
||||||
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
|
|
||||||
// is unsuitable here, as these can occur from missing lifetime parameters in a
|
|
||||||
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
|
|
||||||
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
|
|
||||||
// later, at which point a suitable error will be emitted.
|
|
||||||
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
|
|
||||||
res = LifetimeRes::Anonymous { binder, elided: true };
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let node_ids = self.r.next_node_ids(expected_lifetimes);
|
|
||||||
self.record_lifetime_res(
|
|
||||||
segment_id,
|
|
||||||
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
|
|
||||||
);
|
|
||||||
for i in 0..expected_lifetimes {
|
|
||||||
let id = node_ids.start.plus(i);
|
|
||||||
self.record_lifetime_res(id, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !missing {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let elided_lifetime_span = if segment.has_generic_args {
|
let elided_lifetime_span = if segment.has_generic_args {
|
||||||
// If there are brackets, but not generic arguments, then use the opening bracket
|
// If there are brackets, but not generic arguments, then use the opening bracket
|
||||||
|
@ -1534,25 +1499,88 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// originating from macros, since the segment's span might be from a macro arg.
|
// originating from macros, since the segment's span might be from a macro arg.
|
||||||
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
|
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
|
||||||
};
|
};
|
||||||
if let LifetimeRes::Error = res {
|
let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
|
||||||
let sess = self.r.session;
|
|
||||||
let mut err = rustc_errors::struct_span_err!(
|
let node_ids = self.r.next_node_ids(expected_lifetimes);
|
||||||
sess,
|
self.record_lifetime_res(
|
||||||
path_span,
|
segment_id,
|
||||||
E0726,
|
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
|
||||||
"implicit elided lifetime not allowed here"
|
);
|
||||||
);
|
|
||||||
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
for rib in self.lifetime_ribs.iter().rev() {
|
||||||
sess.source_map(),
|
match rib.kind {
|
||||||
&mut err,
|
// In create-parameter mode we error here because we don't want to support
|
||||||
expected_lifetimes,
|
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||||
path_span,
|
// both of which work using the `CreateParameter` mode:
|
||||||
!segment.has_generic_args,
|
//
|
||||||
elided_lifetime_span,
|
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||||
);
|
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||||
err.note("assuming a `'static` lifetime...");
|
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
|
||||||
err.emit();
|
let sess = self.r.session;
|
||||||
} else {
|
let mut err = rustc_errors::struct_span_err!(
|
||||||
|
sess,
|
||||||
|
path_span,
|
||||||
|
E0726,
|
||||||
|
"implicit elided lifetime not allowed here"
|
||||||
|
);
|
||||||
|
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
||||||
|
sess.source_map(),
|
||||||
|
&mut err,
|
||||||
|
expected_lifetimes,
|
||||||
|
path_span,
|
||||||
|
!segment.has_generic_args,
|
||||||
|
elided_lifetime_span,
|
||||||
|
);
|
||||||
|
err.note("assuming a `'static` lifetime...");
|
||||||
|
err.emit();
|
||||||
|
should_lint = false;
|
||||||
|
for i in 0..expected_lifetimes {
|
||||||
|
let id = node_ids.start.plus(i);
|
||||||
|
self.record_lifetime_res(id, LifetimeRes::Error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
|
||||||
|
let res = self.create_fresh_lifetime(node_ids.start, ident, binder);
|
||||||
|
self.record_lifetime_res(node_ids.start, res);
|
||||||
|
for i in 1..expected_lifetimes {
|
||||||
|
let id = node_ids.start.plus(i);
|
||||||
|
let res = self.create_fresh_lifetime(id, ident, binder);
|
||||||
|
self.record_lifetime_res(id, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// `PassThrough` is the normal case.
|
||||||
|
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
|
||||||
|
// is unsuitable here, as these can occur from missing lifetime parameters in a
|
||||||
|
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
|
||||||
|
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
|
||||||
|
// later, at which point a suitable error will be emitted.
|
||||||
|
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
|
||||||
|
let res = LifetimeRes::Anonymous { binder, elided: true };
|
||||||
|
self.record_lifetime_res(node_ids.start, res);
|
||||||
|
for i in 1..expected_lifetimes {
|
||||||
|
let id = node_ids.start.plus(i);
|
||||||
|
self.record_lifetime_res(id, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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 i in 0..expected_lifetimes {
|
||||||
|
let id = node_ids.start.plus(i);
|
||||||
|
self.record_lifetime_res(id, res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_lint {
|
||||||
self.r.lint_buffer.buffer_lint_with_diagnostic(
|
self.r.lint_buffer.buffer_lint_with_diagnostic(
|
||||||
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
|
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
|
||||||
segment_id,
|
segment_id,
|
||||||
|
@ -2155,7 +2183,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||||
// Dummy self type for better errors if `Self` is used in the trait path.
|
// 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_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
|
||||||
this.with_lifetime_rib(
|
this.with_lifetime_rib(
|
||||||
LifetimeRibKind::AnonymousCreateParameter(item_id),
|
LifetimeRibKind::AnonymousCreateParameter {
|
||||||
|
binder: item_id,
|
||||||
|
report_in_path: true
|
||||||
|
},
|
||||||
|this| {
|
|this| {
|
||||||
// Resolve the trait reference, if necessary.
|
// Resolve the trait reference, if necessary.
|
||||||
this.with_optional_trait_ref(
|
this.with_optional_trait_ref(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue