summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/late.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src/late.rs')
-rw-r--r--compiler/rustc_resolve/src/late.rs91
1 files changed, 69 insertions, 22 deletions
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<Vec<Rib<'a>>>,
+ /// Previous poped `rib`, only used for diagnostic.
+ last_block_rib: Option<Rib<'a>>,
+
/// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a, NodeId>>,
@@ -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<P<QSelf>>,
@@ -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 `<T>::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 `<T as A::B>::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);
}