diff options
Diffstat (limited to 'compiler/rustc_resolve/src/late.rs')
-rw-r--r-- | compiler/rustc_resolve/src/late.rs | 163 |
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); } _ => { |