From 218caa410aa38c29984be31a5229b9fa717560ee Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:13 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_resolve/src/late.rs | 91 +++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 22 deletions(-) (limited to 'compiler/rustc_resolve/src/late.rs') diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index cf3e59460..83932c089 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -16,7 +16,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; +use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg}; 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, LOCAL_CRATE}; @@ -536,6 +536,9 @@ struct DiagnosticMetadata<'ast> { in_assignment: Option<&'ast Expr>, is_assign_rhs: bool, + /// Used to detect possible `.` -> `..` typo when calling methods. + in_range: Option<(&'ast Expr, &'ast Expr)>, + /// If we are currently in a trait object definition. Used to point at the bounds when /// encountering a struct or enum. current_trait_object: Option<&'ast [ast::GenericBound]>, @@ -566,6 +569,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS>>, + /// Previous poped `rib`, only used for diagnostic. + last_block_rib: Option>, + /// The current set of local scopes, for labels. label_ribs: Vec>, @@ -645,7 +651,7 @@ 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, _) => { + TyKind::Ref(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. @@ -662,7 +668,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { && let Some(partial_res) = self.r.partial_res_map.get(&ty.id) && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { - // This path is actually a bare trait object. In case of a bare `Fn`-trait + // This path is actually a bare trait object. In case of a bare `Fn`-trait // object with anonymous lifetimes, we need this rib to correctly place the // synthetic lifetimes. let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo()); @@ -873,6 +879,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // 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); + // We only care block in the same function + this.last_block_rib = None; // Resolve the function body, potentially inside the body of an async closure this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Infer), @@ -1038,7 +1046,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // 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 + // We are inside a `PolyTraitRef`. The lifetimes are // to be intoduced in that (maybe implicit) `for<>` binder. LifetimeRibKind::Generics { binder, @@ -1061,7 +1069,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); break; } - // We have nowhere to introduce generics. Code is malformed, + // 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, args); @@ -1168,6 +1176,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { type_ns: vec![Rib::new(start_rib_kind)], macro_ns: vec![Rib::new(start_rib_kind)], }, + last_block_rib: None, label_ribs: Vec::new(), lifetime_ribs: Vec::new(), lifetime_elision_candidates: None, @@ -1506,7 +1515,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { count: 1, }; let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); - for rib in self.lifetime_ribs.iter().rev() { + for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() { debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { @@ -1523,16 +1532,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } else { ("`'_` cannot be used here", "`'_` is a reserved lifetime name") }; - rustc_errors::struct_span_err!( + let mut diag = rustc_errors::struct_span_err!( self.r.session, lifetime.ident.span, E0637, "{}", msg, - ) - .span_label(lifetime.ident.span, note) - .emit(); - + ); + diag.span_label(lifetime.ident.span, note); + if elided { + for rib in self.lifetime_ribs[i..].iter().rev() { + if let LifetimeRibKind::Generics { + span, + kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, + .. + } = &rib.kind + { + diag.span_help( + *span, + "consider introducing a higher-ranked lifetime here with `for<'a>`", + ); + break; + } + } + } + diag.emit(); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); return; } @@ -1751,7 +1775,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { 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, + // `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 => { @@ -1995,7 +2019,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { 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) { + if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { let lt_id = if let Some(lt) = lt { lt.id } else { @@ -3314,6 +3338,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } + #[instrument(level = "debug", skip(self))] fn smart_resolve_path_fragment( &mut self, qself: &Option>, @@ -3321,10 +3346,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, finalize: Finalize, ) -> PartialRes { - debug!( - "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})", - qself, path, finalize, - ); let ns = source.namespace(); let Finalize { node_id, path_span, .. } = finalize; @@ -3335,8 +3356,28 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); - let suggestion = - if res.is_none() { this.report_missing_type_error(path) } else { None }; + let suggestion = if let Some((start, end)) = this.diagnostic_metadata.in_range + && path[0].ident.span.lo() == end.span.lo() + { + let mut sugg = "."; + let mut span = start.span.between(end.span); + if span.lo() + BytePos(2) == span.hi() { + // There's no space between the start, the range op and the end, suggest + // removal which will look better. + span = span.with_lo(span.lo() + BytePos(1)); + sugg = ""; + } + Some(( + span, + "you might have meant to write `.` instead of `..`", + sugg.to_string(), + Applicability::MaybeIncorrect, + )) + } else if res.is_none() && matches!(source, PathSource::Type) { + this.report_missing_type_error(path) + } else { + None + }; this.r.use_injections.push(UseError { err, @@ -3606,7 +3647,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let Some(qself) = qself { if qself.position == 0 { // This is a case like `::B`, where there is no - // trait to resolve. In that case, we leave the `B` + // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. return Ok(Some(PartialRes::with_unresolved_segments( Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()), @@ -3617,7 +3658,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Make sure `A::B` in `::C` is a trait item. // // Currently, `path` names the full item (`A::B::C`, in - // our example). so we extract the prefix of that that is + // our example). so we extract the prefix of that that is // the trait (the slice upto and including // `qself.position`). And then we recursively resolve that, // but with `qself` set to `None`. @@ -3769,7 +3810,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.ribs[ValueNS].pop(); self.label_ribs.pop(); } - self.ribs[ValueNS].pop(); + self.last_block_rib = self.ribs[ValueNS].pop(); if anonymous_module.is_some() { self.ribs[TypeNS].pop(); } @@ -3999,6 +4040,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.visit_expr(rhs); self.diagnostic_metadata.is_assign_rhs = false; } + ExprKind::Range(Some(ref start), Some(ref end), RangeLimits::HalfOpen) => { + self.diagnostic_metadata.in_range = Some((start, end)); + self.resolve_expr(start, Some(expr)); + self.resolve_expr(end, Some(expr)); + self.diagnostic_metadata.in_range = None; + } _ => { visit::walk_expr(self, expr); } -- cgit v1.2.3