Skip to content

Commit bf38ba2

Browse files
committed
Separate AnonymousCreateParameter and ReportElidedInPath.
1 parent 237e267 commit bf38ba2

File tree

1 file changed

+93
-62
lines changed

1 file changed

+93
-62
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 93 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,14 @@ enum LifetimeRibKind {
238238
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
239239
AnonConst,
240240

241-
/// For **Modern** cases, create a new anonymous region parameter
242-
/// and reference that.
241+
/// Create a new anonymous region parameter and reference it.
243242
///
244-
/// For **Dyn Bound** cases, pass responsibility to
245-
/// `resolve_lifetime` code.
246-
///
247-
/// For **Deprecated** cases, report an error.
248-
AnonymousCreateParameter(NodeId),
243+
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
244+
/// ```ignore
245+
/// struct Foo<'a> { .. }
246+
/// fn foo(x: Foo) {}
247+
/// ```
248+
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
249249

250250
/// Give a hard error when either `&` or `'_` is written. Used to
251251
/// 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> {
764764
// return type.
765765
this.with_lifetime_rib(
766766
if async_node_id.is_some() {
767-
LifetimeRibKind::AnonymousCreateParameter(fn_id)
767+
LifetimeRibKind::AnonymousCreateParameter {
768+
binder: fn_id,
769+
report_in_path: true,
770+
}
768771
} else {
769772
LifetimeRibKind::AnonymousPassThrough(fn_id, false)
770773
},
@@ -791,7 +794,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
791794
);
792795
match rib.kind {
793796
LifetimeRibKind::Item => break,
794-
LifetimeRibKind::AnonymousCreateParameter(binder) => {
797+
LifetimeRibKind::AnonymousCreateParameter {
798+
binder, ..
799+
} => {
795800
if let Some(earlier_fresh) =
796801
this.r.extra_lifetime_params_map.get(&binder)
797802
{
@@ -1295,7 +1300,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12951300
}
12961301
// An anonymous lifetime is legal here, go ahead.
12971302
LifetimeRibKind::AnonymousPassThrough(_, false)
1298-
| LifetimeRibKind::AnonymousCreateParameter(_) => {
1303+
| LifetimeRibKind::AnonymousCreateParameter { .. } => {
12991304
Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
13001305
}
13011306
_ => None,
@@ -1350,8 +1355,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
13501355
for i in (0..self.lifetime_ribs.len()).rev() {
13511356
let rib = &mut self.lifetime_ribs[i];
13521357
match rib.kind {
1353-
LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
1354-
self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
1358+
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
1359+
let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
1360+
self.record_lifetime_res(lifetime.id, res);
13551361
return;
13561362
}
13571363
LifetimeRibKind::AnonymousReportError => {
@@ -1408,7 +1414,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14081414
}
14091415

14101416
#[tracing::instrument(level = "debug", skip(self))]
1411-
fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
1417+
fn create_fresh_lifetime(
1418+
&mut self,
1419+
id: NodeId,
1420+
ident: Ident,
1421+
item_node_id: NodeId,
1422+
) -> LifetimeRes {
14121423
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
14131424
debug!(?ident.span);
14141425
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> {
14231434
debug!(?def_id);
14241435

14251436
let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
1426-
self.record_lifetime_res(id, region);
14271437
self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
14281438
ident,
14291439
def_node_id,
14301440
region,
14311441
));
1442+
region
14321443
}
14331444

14341445
#[tracing::instrument(level = "debug", skip(self))]
@@ -1471,14 +1482,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14711482
continue;
14721483
}
14731484

1474-
let missing = match source {
1485+
let mut should_lint = match source {
14751486
PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
14761487
PathSource::Expr(..)
14771488
| PathSource::Pat
14781489
| PathSource::Struct
14791490
| PathSource::TupleStruct(..) => false,
14801491
};
1481-
let mut res = LifetimeRes::Error;
1492+
1493+
let elided_lifetime_span = if segment.has_generic_args {
1494+
// If there are brackets, but not generic arguments, then use the opening bracket
1495+
segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
1496+
} else {
1497+
// If there are no brackets, use the identifier span.
1498+
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
1499+
// originating from macros, since the segment's span might be from a macro arg.
1500+
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
1501+
};
1502+
let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
1503+
1504+
let node_ids = self.r.next_node_ids(expected_lifetimes);
1505+
self.record_lifetime_res(
1506+
segment_id,
1507+
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
1508+
);
1509+
14821510
for rib in self.lifetime_ribs.iter().rev() {
14831511
match rib.kind {
14841512
// In create-parameter mode we error here because we don't want to support
@@ -1487,7 +1515,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14871515
//
14881516
// impl Foo for std::cell::Ref<u32> // note lack of '_
14891517
// async fn foo(_: std::cell::Ref<u32>) { ... }
1490-
LifetimeRibKind::AnonymousCreateParameter(_) => {
1518+
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
1519+
let sess = self.r.session;
1520+
let mut err = rustc_errors::struct_span_err!(
1521+
sess,
1522+
path_span,
1523+
E0726,
1524+
"implicit elided lifetime not allowed here"
1525+
);
1526+
rustc_errors::add_elided_lifetime_in_path_suggestion(
1527+
sess.source_map(),
1528+
&mut err,
1529+
expected_lifetimes,
1530+
path_span,
1531+
!segment.has_generic_args,
1532+
elided_lifetime_span,
1533+
);
1534+
err.note("assuming a `'static` lifetime...");
1535+
err.emit();
1536+
should_lint = false;
1537+
for i in 0..expected_lifetimes {
1538+
let id = node_ids.start.plus(i);
1539+
self.record_lifetime_res(id, LifetimeRes::Error);
1540+
}
1541+
break;
1542+
}
1543+
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
1544+
let res = self.create_fresh_lifetime(node_ids.start, ident, binder);
1545+
self.record_lifetime_res(node_ids.start, res);
1546+
for i in 1..expected_lifetimes {
1547+
let id = node_ids.start.plus(i);
1548+
let res = self.create_fresh_lifetime(id, ident, binder);
1549+
self.record_lifetime_res(id, res);
1550+
}
14911551
break;
14921552
}
14931553
// `PassThrough` is the normal case.
@@ -1497,62 +1557,30 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14971557
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
14981558
// later, at which point a suitable error will be emitted.
14991559
LifetimeRibKind::AnonymousPassThrough(binder, _) => {
1500-
res = LifetimeRes::Anonymous { binder, elided: true };
1560+
let res = LifetimeRes::Anonymous { binder, elided: true };
1561+
self.record_lifetime_res(node_ids.start, res);
1562+
for i in 1..expected_lifetimes {
1563+
let id = node_ids.start.plus(i);
1564+
self.record_lifetime_res(id, res);
1565+
}
15011566
break;
15021567
}
15031568
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
15041569
// FIXME(cjgillot) This resolution is wrong, but this does not matter
15051570
// since these cases are erroneous anyway. Lifetime resolution should
15061571
// emit a "missing lifetime specifier" diagnostic.
1507-
res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
1572+
let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
1573+
for i in 0..expected_lifetimes {
1574+
let id = node_ids.start.plus(i);
1575+
self.record_lifetime_res(id, res);
1576+
}
15081577
break;
15091578
}
15101579
_ => {}
15111580
}
15121581
}
15131582

1514-
let node_ids = self.r.next_node_ids(expected_lifetimes);
1515-
self.record_lifetime_res(
1516-
segment_id,
1517-
LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
1518-
);
1519-
for i in 0..expected_lifetimes {
1520-
let id = node_ids.start.plus(i);
1521-
self.record_lifetime_res(id, res);
1522-
}
1523-
1524-
if !missing {
1525-
continue;
1526-
}
1527-
1528-
let elided_lifetime_span = if segment.has_generic_args {
1529-
// If there are brackets, but not generic arguments, then use the opening bracket
1530-
segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
1531-
} else {
1532-
// If there are no brackets, use the identifier span.
1533-
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
1534-
// originating from macros, since the segment's span might be from a macro arg.
1535-
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
1536-
};
1537-
if let LifetimeRes::Error = res {
1538-
let sess = self.r.session;
1539-
let mut err = rustc_errors::struct_span_err!(
1540-
sess,
1541-
path_span,
1542-
E0726,
1543-
"implicit elided lifetime not allowed here"
1544-
);
1545-
rustc_errors::add_elided_lifetime_in_path_suggestion(
1546-
sess.source_map(),
1547-
&mut err,
1548-
expected_lifetimes,
1549-
path_span,
1550-
!segment.has_generic_args,
1551-
elided_lifetime_span,
1552-
);
1553-
err.note("assuming a `'static` lifetime...");
1554-
err.emit();
1555-
} else {
1583+
if should_lint {
15561584
self.r.lint_buffer.buffer_lint_with_diagnostic(
15571585
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
15581586
segment_id,
@@ -2155,7 +2183,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
21552183
// Dummy self type for better errors if `Self` is used in the trait path.
21562184
this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
21572185
this.with_lifetime_rib(
2158-
LifetimeRibKind::AnonymousCreateParameter(item_id),
2186+
LifetimeRibKind::AnonymousCreateParameter {
2187+
binder: item_id,
2188+
report_in_path: true
2189+
},
21592190
|this| {
21602191
// Resolve the trait reference, if necessary.
21612192
this.with_optional_trait_ref(

0 commit comments

Comments
 (0)