diff options
| author | Camille GILLOT <gillot.camille@gmail.com> | 2022-05-11 22:49:39 +0200 |
|---|---|---|
| committer | Camille GILLOT <gillot.camille@gmail.com> | 2022-06-21 21:13:41 +0200 |
| commit | 32af719b07217ff89e61a2031500cee138599baa (patch) | |
| tree | fef7781b316b4f2fd06655f2892f689032e7b297 /compiler/rustc_resolve | |
| parent | 4b79b8bfa139ca5f991aa08b405003f748d3caf6 (diff) | |
| download | rust-32af719b07217ff89e61a2031500cee138599baa.tar.gz rust-32af719b07217ff89e61a2031500cee138599baa.zip | |
Always create parameters for functions-like types.
Diffstat (limited to 'compiler/rustc_resolve')
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 193 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/lifetimes.rs | 4 |
3 files changed, 155 insertions, 57 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index abccb94a906..08d6134237a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,7 +21,6 @@ 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_index::vec::Idx; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -240,9 +239,16 @@ enum LifetimeRibKind { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: - /// ```ignore - /// struct Foo<'a> { .. } - /// fn foo(x: Foo) {} + /// ```compile_fail + /// struct Foo<'a> { x: &'a () } + /// async fn foo(x: Foo) {} + /// ``` + /// + /// Note: the error should not trigger when the elided lifetime is in a pattern or + /// expression-position path: + /// ``` + /// struct Foo<'a> { x: &'a () } + /// async fn foo(Foo { x: _ }: Foo<'_>) {} /// ``` AnonymousCreateParameter { binder: NodeId, report_in_path: bool }, @@ -634,7 +640,10 @@ 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::AnonymousPassThrough(ty.id, false), + LifetimeRibKind::AnonymousCreateParameter { + binder: ty.id, + report_in_path: false, + }, |this| walk_list!(this, visit_param, &bare_fn.decl.inputs), ); this.with_lifetime_rib( @@ -720,15 +729,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.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::AnonymousPassThrough(fn_id, false), - |this| { - this.visit_fn_header(&sig.header); - this.visit_generics(generics); - walk_list!(this, visit_param, &sig.decl.inputs); - }, + |this| walk_list!(this, visit_param, &sig.decl.inputs), ); self.with_lifetime_rib( LifetimeRibKind::AnonymousPassThrough(fn_id, true), @@ -761,15 +768,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // generic parameters. This is especially useful for `async fn`, where // these fresh generic parameters can be applied to the opaque `impl Trait` // return type. + let rib = if async_node_id.is_some() { + // Only emit a hard error for `async fn`, since this kind of + // elision has always been allowed in regular `fn`s. + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: true, + } + } else { + LifetimeRibKind::AnonymousPassThrough(fn_id, false) + }; this.with_lifetime_rib( - if async_node_id.is_some() { - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: true, - } - } else { - LifetimeRibKind::AnonymousPassThrough(fn_id, false) - }, + rib, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); @@ -937,19 +947,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.currently_processing_generics = prev; } + fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) { + self.visit_ident(constraint.ident); + if let Some(ref gen_args) = constraint.gen_args { + // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided. + self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + this.visit_generic_args(gen_args.span(), gen_args) + }); + } + match constraint.kind { + AssocConstraintKind::Equality { ref term } => match term { + Term::Ty(ty) => self.visit_ty(ty), + Term::Const(c) => self.visit_anon_const(c), + }, + AssocConstraintKind::Bound { ref bounds } => { + walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); + } + } + } + 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(ref data) => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, false), - |this| walk_list!(this, visit_ty, &data.inputs), - ); - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, true), - |this| visit::walk_fn_ret_ty(this, &data.output), - ) + GenericArgs::Parenthesized(p_args) => { + // Probe the lifetime ribs to know how to behave. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // We are inside a `PolyTraitRef`. The lifetimes are + // to be intoduced in that (maybe implicit) `for<>` binder. + LifetimeRibKind::Generics { + binder, + 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), + ); + break; + } + // We have nowhere to introduce generics. Code is malformed, + // so use regular lifetime resolution to avoid spurious errors. + LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { + visit::walk_generic_args(self, path_span, args); + break; + } + LifetimeRibKind::AnonymousPassThrough(..) + | LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::AnonConst + | LifetimeRibKind::ConstGeneric => {} + } + } } } } @@ -1474,7 +1531,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let mut should_lint = match source { + let missing = match source { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true, PathSource::Expr(..) | PathSource::Pat @@ -1499,6 +1556,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, ); + 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, _) => { + let res = LifetimeRes::Anonymous { binder, elided: true }; + for id in node_ids { + self.record_lifetime_res(id, res); + } + break; + } + // `LifetimeRes::Error`, which would usually be used in the case of + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // 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); + } + break; + } + _ => {} + } + } + continue; + } + + let mut should_lint = true; 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 @@ -1526,44 +1616,38 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { err.note("assuming a `'static` lifetime..."); err.emit(); should_lint = false; - for i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + + for id in node_ids { self.record_lifetime_res(id, LifetimeRes::Error); } break; } + // Do not create a parameter for patterns and expressions. 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); + for id in node_ids { 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); + for id in node_ids { self.record_lifetime_res(id, res); } break; } + // `LifetimeRes::Error`, which would usually be used in the case of + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // 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 i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + for id in node_ids { self.record_lifetime_res(id, res); } break; @@ -2235,7 +2319,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_impl_item(&mut self, item: &'ast AssocItem) { use crate::ResolutionError::*; match &item.kind { - AssocItemKind::Const(_default, _ty, _expr) => { + AssocItemKind::Const(_, ty, default) => { debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait @@ -2248,14 +2332,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |i, s, c| ConstNotMemberOfTrait(i, s, c), ); - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // 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| { - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + self.visit_ty(ty); + if let Some(expr) = default { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // 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) + }); + } } AssocItemKind::Fn(box Fn { generics, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1a99bff610a..15f862e21d7 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2223,9 +2223,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ] .contains(&Some(did)) { - let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), - [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + let (span, span_type) = if let Some(bound) = + trait_ref.bound_generic_params.iter().rfind(|param| { + matches!( + param.kind, + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) { + (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail) + } else { + (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty) }; self.missing_named_lifetime_spots .push(MissingLifetimeSpot::HigherRanked { span, span_type }); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 447f4174c10..53f6870bdf5 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -755,7 +755,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let lifetime_span: Option<Span> = c.generic_params.iter().rev().find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(param.span), + GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => { + Some(param.span) + } _ => None, }); let (span, span_type) = if let Some(span) = lifetime_span { |
