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.rs163
1 files changed, 107 insertions, 56 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 00eb768ad..cf3e59460 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::DiagnosticId;
+use rustc_errors::{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};
@@ -31,8 +31,9 @@ use smallvec::{smallvec, SmallVec};
use rustc_span::source_map::{respan, Spanned};
use std::assert_matches::debug_assert_matches;
+use std::borrow::Cow;
use std::collections::{hash_map::Entry, BTreeSet};
-use std::mem::{replace, take};
+use std::mem::{replace, swap, take};
mod diagnostics;
@@ -78,6 +79,12 @@ impl PatternSource {
}
}
+impl IntoDiagnosticArg for PatternSource {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Borrowed(self.descr()))
+ }
+}
+
/// Denotes whether the context for the set of already bound bindings is a `Product`
/// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`.
/// See those functions for more information.
@@ -527,6 +534,7 @@ struct DiagnosticMetadata<'ast> {
/// Used to detect possible new binding written without `let` and to provide structured suggestion.
in_assignment: Option<&'ast Expr>,
+ is_assign_rhs: bool,
/// If we are currently in a trait object definition. Used to point at the bounds when
/// encountering a struct or enum.
@@ -647,7 +655,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
}
TyKind::Path(ref qself, ref path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
- self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+ self.smart_resolve_path(ty.id, &qself, path, PathSource::Type);
// Check whether we should interpret this as a bare trait object.
if qself.is_none()
@@ -748,7 +756,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
this.visit_generic_params(&tref.bound_generic_params, false);
this.smart_resolve_path(
tref.trait_ref.ref_id,
- None,
+ &None,
&tref.trait_ref.path,
PathSource::Trait(AliasPossibility::Maybe),
);
@@ -977,7 +985,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|this| {
this.smart_resolve_path(
ty.id,
- qself.as_ref(),
+ qself,
path,
PathSource::Expr(None),
);
@@ -1137,12 +1145,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
self.with_rib(ValueNS, InlineAsmSymRibKind, |this| {
this.with_rib(TypeNS, InlineAsmSymRibKind, |this| {
this.with_label_rib(InlineAsmSymRibKind, |this| {
- this.smart_resolve_path(
- sym.id,
- sym.qself.as_ref(),
- &sym.path,
- PathSource::Expr(None),
- );
+ this.smart_resolve_path(sym.id, &sym.qself, &sym.path, PathSource::Expr(None));
visit::walk_inline_asm_sym(this, sym);
});
})
@@ -1835,6 +1838,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
+ self.r.lifetime_elision_allowed.insert(fn_id);
LifetimeRibKind::Elided(*res)
} else {
LifetimeRibKind::ElisionFailure
@@ -1923,7 +1927,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// We have a single lifetime => success.
elision_lifetime = Elision::Param(res)
} else {
- // We have have multiple lifetimes => error.
+ // We have multiple lifetimes => error.
elision_lifetime = Elision::Err;
}
}
@@ -2356,8 +2360,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if let GenericParamKind::Lifetime = param.kind {
// Record lifetime res, so lowering knows there is something fishy.
self.record_lifetime_param(param.id, LifetimeRes::Error);
- continue;
}
+ continue;
}
Entry::Vacant(entry) => {
entry.insert(param.ident.span);
@@ -2570,7 +2574,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.diagnostic_metadata.currently_processing_impl_trait =
Some((trait_ref.clone(), self_type.clone()));
let res = self.smart_resolve_path_fragment(
- None,
+ &None,
&path,
PathSource::Trait(AliasPossibility::No),
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
@@ -3093,7 +3097,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
self.smart_resolve_path(
pat.id,
- qself.as_ref(),
+ qself,
path,
PathSource::TupleStruct(
pat.span,
@@ -3102,10 +3106,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
);
}
PatKind::Path(ref qself, ref path) => {
- self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
+ self.smart_resolve_path(pat.id, qself, path, PathSource::Pat);
}
PatKind::Struct(ref qself, ref path, ..) => {
- self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Struct);
+ self.smart_resolve_path(pat.id, qself, path, PathSource::Struct);
}
PatKind::Or(ref ps) => {
// Add a new set of bindings to the stack. `Or` here records that when a
@@ -3298,7 +3302,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn smart_resolve_path(
&mut self,
id: NodeId,
- qself: Option<&QSelf>,
+ qself: &Option<P<QSelf>>,
path: &Path,
source: PathSource<'ast>,
) {
@@ -3312,7 +3316,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn smart_resolve_path_fragment(
&mut self,
- qself: Option<&QSelf>,
+ qself: &Option<P<QSelf>>,
path: &[Segment],
source: PathSource<'ast>,
finalize: Finalize,
@@ -3361,18 +3365,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically:
// we're transforming `HashMap::new` into just `HashMap`.
- let path = match path.split_last() {
+ let prefix_path = match path.split_last() {
Some((_, path)) if !path.is_empty() => path,
_ => return Some(parent_err),
};
let (mut err, candidates) =
- this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
-
- if candidates.is_empty() {
- err.cancel();
- return Some(parent_err);
- }
+ this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
// There are two different error messages user might receive at
// this point:
@@ -3383,37 +3382,74 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// latter one - for paths in expression-position.
//
// Thus (since we're in expression-position at this point), not to
- // confuse the user, we want to keep the *message* from E0432 (so
+ // confuse the user, we want to keep the *message* from E0433 (so
// `parent_err`), but we want *hints* from E0412 (so `err`).
//
// And that's what happens below - we're just mixing both messages
// into a single one.
let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
+ // overwrite all properties with the parent's error message
err.message = take(&mut parent_err.message);
err.code = take(&mut parent_err.code);
+ swap(&mut err.span, &mut parent_err.span);
err.children = take(&mut parent_err.children);
+ err.sort_span = parent_err.sort_span;
+ err.is_lint = parent_err.is_lint;
+
+ // merge the parent's suggestions with the typo suggestions
+ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
+ match res1 {
+ Ok(vec1) => match res2 {
+ Ok(mut vec2) => vec1.append(&mut vec2),
+ Err(e) => *res1 = Err(e),
+ },
+ Err(_) => (),
+ };
+ }
+ append_result(&mut err.suggestions, parent_err.suggestions.clone());
parent_err.cancel();
let def_id = this.parent_scope.module.nearest_parent_mod();
if this.should_report_errs() {
- this.r.use_injections.push(UseError {
- err,
- candidates,
- def_id,
- instead: false,
- suggestion: None,
- path: path.into(),
- is_call: source.is_call(),
- });
+ if candidates.is_empty() {
+ if path.len() == 2 && prefix_path.len() == 1 {
+ // Delay to check whether methond name is an associated function or not
+ // ```
+ // let foo = Foo {};
+ // foo::bar(); // possibly suggest to foo.bar();
+ //```
+ err.stash(
+ prefix_path[0].ident.span,
+ rustc_errors::StashKey::CallAssocMethod,
+ );
+ } else {
+ // When there is no suggested imports, we can just emit the error
+ // and suggestions immediately. Note that we bypass the usually error
+ // reporting routine (ie via `self.r.report_error`) because we need
+ // to post-process the `ResolutionError` above.
+ err.emit();
+ }
+ } else {
+ // If there are suggested imports, the error reporting is delayed
+ this.r.use_injections.push(UseError {
+ err,
+ candidates,
+ def_id,
+ instead: false,
+ suggestion: None,
+ path: prefix_path.into(),
+ is_call: source.is_call(),
+ });
+ }
} else {
err.cancel();
}
// We don't return `Some(parent_err)` here, because the error will
- // be already printed as part of the `use` injections
+ // be already printed either immediately or as part of the `use` injections
None
};
@@ -3513,7 +3549,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// Resolve in alternative namespaces if resolution in the primary namespace fails.
fn resolve_qpath_anywhere(
&mut self,
- qself: Option<&QSelf>,
+ qself: &Option<P<QSelf>>,
path: &[Segment],
primary_ns: Namespace,
span: Span,
@@ -3557,7 +3593,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
/// Handles paths that may refer to associated items.
fn resolve_qpath(
&mut self,
- qself: Option<&QSelf>,
+ qself: &Option<P<QSelf>>,
path: &[Segment],
ns: Namespace,
finalize: Finalize,
@@ -3587,7 +3623,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// but with `qself` set to `None`.
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
let partial_res = self.smart_resolve_path_fragment(
- None,
+ &None,
&path[..=qself.position],
PathSource::TraitItem(ns),
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
@@ -3770,12 +3806,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// Next, resolve the node.
match expr.kind {
ExprKind::Path(ref qself, ref path) => {
- self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
+ self.smart_resolve_path(expr.id, qself, path, PathSource::Expr(parent));
visit::walk_expr(self, expr);
}
ExprKind::Struct(ref se) => {
- self.smart_resolve_path(expr.id, se.qself.as_ref(), &se.path, PathSource::Struct);
+ self.smart_resolve_path(expr.id, &se.qself, &se.path, PathSource::Struct);
visit::walk_expr(self, expr);
}
@@ -3818,7 +3854,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
}
- ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
+ ExprKind::Loop(ref block, label, _) => {
+ self.resolve_labeled_block(label, expr.id, &block)
+ }
ExprKind::While(ref cond, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
@@ -3845,12 +3883,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
}
- ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
+ ExprKind::MethodCall(box MethodCall { ref seg, ref receiver, ref args, .. }) => {
self.resolve_expr(receiver, Some(expr));
- for argument in arguments {
- self.resolve_expr(argument, None);
+ for arg in args {
+ self.resolve_expr(arg, None);
}
- self.visit_path_segment(segment);
+ self.visit_path_segment(seg);
}
ExprKind::Call(ref callee, ref arguments) => {
@@ -3889,10 +3927,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
visit::walk_expr(self, expr);
self.diagnostic_metadata.current_type_ascription.pop();
}
- // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
+ // `async |x| ...` gets desugared to `|x| async {...}`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
// closure are detected as upvars rather than normal closure arg usages.
- ExprKind::Closure(_, _, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
+ ExprKind::Closure(box ast::Closure {
+ asyncness: Async::Yes { .. },
+ ref fn_decl,
+ ref body,
+ ..
+ }) => {
self.with_rib(ValueNS, NormalRibKind, |this| {
this.with_label_rib(ClosureOrAsyncRibKind, |this| {
// Resolve arguments:
@@ -3912,7 +3955,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
});
}
// For closures, ClosureOrAsyncRibKind is added in visit_fn
- ExprKind::Closure(ClosureBinder::For { ref generic_params, span }, ..) => {
+ ExprKind::Closure(box ast::Closure {
+ binder: ClosureBinder::For { ref generic_params, span },
+ ..
+ }) => {
self.with_generic_param_rib(
&generic_params,
NormalRibKind,
@@ -3943,10 +3989,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.resolve_expr(elem, Some(expr));
self.visit_expr(idx);
}
- ExprKind::Assign(..) => {
- let old = self.diagnostic_metadata.in_assignment.replace(expr);
- visit::walk_expr(self, expr);
- self.diagnostic_metadata.in_assignment = old;
+ ExprKind::Assign(ref lhs, ref rhs, _) => {
+ if !self.diagnostic_metadata.is_assign_rhs {
+ self.diagnostic_metadata.in_assignment = Some(expr);
+ }
+ self.visit_expr(lhs);
+ self.diagnostic_metadata.is_assign_rhs = true;
+ self.diagnostic_metadata.in_assignment = None;
+ self.visit_expr(rhs);
+ self.diagnostic_metadata.is_assign_rhs = false;
}
_ => {
visit::walk_expr(self, expr);
@@ -3964,9 +4015,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let traits = self.traits_in_scope(ident, ValueNS);
self.r.trait_map.insert(expr.id, traits);
}
- ExprKind::MethodCall(ref segment, ..) => {
+ ExprKind::MethodCall(ref call) => {
debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
- let traits = self.traits_in_scope(segment.ident, ValueNS);
+ let traits = self.traits_in_scope(call.seg.ident, ValueNS);
self.r.trait_map.insert(expr.id, traits);
}
_ => {