diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index c1fe7188f6d..f56954e32ae 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1,15 +1,14 @@ use std::cmp::Reverse; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder}; use log::debug; -use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind}; +use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::def::Namespace::{self, *}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::PrimTy; -use rustc::session::{Session, config::nightly_options}; +use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::FxHashSet; -use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind}; +use syntax::ast::{self, Ident, Path}; use syntax::ext::base::MacroKind; use syntax::feature_gate::BUILTIN_ATTRIBUTES; use syntax::symbol::{Symbol, kw}; @@ -17,40 +16,33 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{BytePos, Span}; use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; -use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS}; -use crate::{CrateLint, LateResolutionVisitor, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot}; -use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment}; +use crate::{path_names_to_string, KNOWN_TOOLS}; +use crate::{CrateLint, LegacyScope, Module, ModuleOrUniformRoot}; +use crate::{PathResult, ParentScope, Resolver, Scope, ScopeSet, Segment}; type Res = def::Res; /// A vector of spans and replacements, a message and applicability. crate type Suggestion = (Vec<(Span, String)>, String, Applicability); -/// A field or associated item from self type suggested in case of resolution failure. -enum AssocSuggestion { - Field, - MethodWithSelf, - AssocItem, -} - -struct TypoSuggestion { - candidate: Symbol, - res: Res, +crate struct TypoSuggestion { + pub candidate: Symbol, + pub res: Res, } impl TypoSuggestion { - fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { + crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion { TypoSuggestion { candidate, res } } } /// A free importable items suggested in case of resolution failure. crate struct ImportSuggestion { - did: Option, + pub did: Option, pub path: Path, } -fn add_typo_suggestion( +crate fn add_typo_suggestion( err: &mut DiagnosticBuilder<'_>, suggestion: Option, span: Span ) -> bool { if let Some(suggestion) = suggestion { @@ -65,7 +57,7 @@ fn add_typo_suggestion( false } -fn add_module_candidates( +crate fn add_module_candidates( module: Module<'_>, names: &mut Vec, filter_fn: &impl Fn(Res) -> bool ) { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { @@ -78,488 +70,6 @@ fn add_module_candidates( } } -impl<'a> LateResolutionVisitor<'a, '_> { - /// Handles error reporting for `smart_resolve_path_fragment` function. - /// Creates base error and amends it with one short label and possibly some longer helps/notes. - pub(crate) fn smart_resolve_report_errors( - &mut self, - path: &[Segment], - span: Span, - source: PathSource<'_>, - res: Option, - ) -> (DiagnosticBuilder<'a>, Vec) { - let ident_span = path.last().map_or(span, |ident| ident.ident.span); - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - let is_enum_variant = &|res| { - if let Res::Def(DefKind::Variant, _) = res { true } else { false } - }; - - // Make the base error. - let expected = source.descr_expected(); - let path_str = Segment::names_to_string(path); - let item_str = path.last().unwrap().ident; - let code = source.error_code(res.is_some()); - let (base_msg, fallback_label, base_span) = if let Some(res) = res { - (format!("expected {}, found {} `{}`", expected, res.descr(), path_str), - format!("not a {}", expected), - span) - } else { - let item_span = path.last().unwrap().ident.span; - let (mod_prefix, mod_str) = if path.len() == 1 { - (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].ident.name == kw::PathRoot { - (String::new(), "the crate root".to_string()) - } else { - let mod_path = &path[..path.len() - 1]; - let mod_prefix = match self.resolve_path( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => - module.def_kind(), - _ => None, - }.map_or(String::new(), |kind| format!("{} ", kind.descr())); - (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) - }; - (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), - item_span) - }; - - let code = DiagnosticId::Error(code.into()); - let mut err = self.session.struct_span_err_with_code(base_span, &base_msg, code); - - // Emit help message for fake-self from other languages (e.g., `this` in Javascript). - if ["this", "my"].contains(&&*item_str.as_str()) - && self.self_value_is_available(path[0].ident.span, span) { - err.span_suggestion( - span, - "did you mean", - "self".to_string(), - Applicability::MaybeIncorrect, - ); - } - - // Emit special messages for unresolved `Self` and `self`. - if is_self_type(path, ns) { - __diagnostic_used!(E0411); - err.code(DiagnosticId::Error("E0411".into())); - err.span_label(span, format!("`Self` is only available in impls, traits, \ - and type definitions")); - return (err, Vec::new()); - } - if is_self_value(path, ns) { - debug!("smart_resolve_path_fragment: E0424, source={:?}", source); - - __diagnostic_used!(E0424); - err.code(DiagnosticId::Error("E0424".into())); - err.span_label(span, match source { - PathSource::Pat => { - format!("`self` value is a keyword \ - and may not be bound to \ - variables or shadowed") - } - _ => { - format!("`self` value is a keyword \ - only available in methods \ - with `self` parameter") - } - }); - return (err, Vec::new()); - } - - // Try to lookup name in more relaxed fashion for better error reporting. - let ident = path.last().unwrap().ident; - let candidates = self.lookup_import_candidates(ident, ns, is_expected) - .drain(..) - .filter(|ImportSuggestion { did, .. }| { - match (did, res.and_then(|res| res.opt_def_id())) { - (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did, - _ => true, - } - }) - .collect::>(); - let crate_def_id = DefId::local(CRATE_DEF_INDEX); - if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { - let enum_candidates = - self.lookup_import_candidates(ident, ns, is_enum_variant); - let mut enum_candidates = enum_candidates.iter() - .map(|suggestion| { - import_candidate_to_enum_paths(&suggestion) - }).collect::>(); - enum_candidates.sort(); - - if !enum_candidates.is_empty() { - // Contextualize for E0412 "cannot find type", but don't belabor the point - // (that it's a variant) for E0573 "expected type, found variant". - let preamble = if res.is_none() { - let others = match enum_candidates.len() { - 1 => String::new(), - 2 => " and 1 other".to_owned(), - n => format!(" and {} others", n) - }; - format!("there is an enum variant `{}`{}; ", - enum_candidates[0].0, others) - } else { - String::new() - }; - let msg = format!("{}try using the variant's enum", preamble); - - err.span_suggestions( - span, - &msg, - enum_candidates.into_iter() - .map(|(_variant_path, enum_ty_path)| enum_ty_path) - // Variants re-exported in prelude doesn't mean `prelude::v1` is the - // type name! - // FIXME: is there a more principled way to do this that - // would work for other re-exports? - .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1") - // Also write `Option` rather than `std::prelude::v1::Option`. - .map(|enum_ty_path| { - // FIXME #56861: DRY-er prelude filtering. - enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned() - }), - Applicability::MachineApplicable, - ); - } - } - if path.len() == 1 && self.self_type_is_available(span) { - if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = self.self_value_is_available(path[0].ident.span, span); - match candidate { - AssocSuggestion::Field => { - if self_is_available { - err.span_suggestion( - span, - "you might have meant to use the available field", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - } else { - err.span_label( - span, - "a field by this name exists in `Self`", - ); - } - } - AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_suggestion( - span, - "try", - format!("Self::{}", path_str), - Applicability::MachineApplicable, - ); - } - } - return (err, candidates); - } - } - - // Try Levenshtein algorithm. - let levenshtein_worked = add_typo_suggestion( - &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span - ); - - // Try context-dependent help if relaxed lookup didn't work. - if let Some(res) = res { - if self.smart_resolve_context_dependent_help(&mut err, - span, - source, - res, - &path_str, - &fallback_label) { - return (err, candidates); - } - } - - // Fallback label. - if !levenshtein_worked { - err.span_label(base_span, fallback_label); - self.type_ascription_suggestion(&mut err, base_span); - } - (err, candidates) - } -} - -impl<'a> Resolver<'a> { - fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) { - // HACK(estebank): find a better way to figure out that this was a - // parser issue where a struct literal is being used on an expression - // where a brace being opened means a block is being started. Look - // ahead for the next text to see if `span` is followed by a `{`. - let sm = self.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| { !c.is_whitespace() }) { - break; - } - } - _ => break, - } - } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; - // In case this could be a struct literal that needs to be surrounded - // by parenthesis, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - let sp = span.to(sp); - if let Ok(snippet) = sm.span_to_snippet(sp) { - closing_brace = Some((sp, snippet)); - } - break; - } - } - _ => break, - } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; - } - } - return (followed_by_brace, closing_brace) - } -} - -impl<'a> LateResolutionVisitor<'a, '_> { - /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` - /// function. - /// Returns `true` if able to provide context-dependent help. - fn smart_resolve_context_dependent_help( - &mut self, - err: &mut DiagnosticBuilder<'a>, - span: Span, - source: PathSource<'_>, - res: Res, - path_str: &str, - fallback_label: &str, - ) -> bool { - let ns = source.namespace(); - let is_expected = &|res| source.is_expected(res); - - let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node { - ExprKind::Field(_, ident) => { - err.span_suggestion( - expr.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect, - ); - true - } - ExprKind::MethodCall(ref segment, ..) => { - let span = expr.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( - span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), - Applicability::MaybeIncorrect, - ); - true - } - _ => false, - }; - - let mut bad_struct_syntax_suggestion = || { - let (followed_by_brace, closing_brace) = self.followed_by_brace(span); - let mut suggested = false; - match source { - PathSource::Expr(Some(parent)) => { - suggested = path_sep(err, &parent); - } - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, // Note the parenthesis surrounding the suggestion below - format!("did you mean `({} {{ /* fields */ }})`?", path_str), - ); - } - suggested = true; - }, - _ => {} - } - if !suggested { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - } - }; - - match (res, source) { - (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { - err.span_suggestion( - span, - "use `!` to invoke the macro", - format!("{}!", path_str), - Applicability::MaybeIncorrect, - ); - if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, you need to be in the 2018 edition"); - } - } - (Res::Def(DefKind::TyAlias, _), PathSource::Trait(_)) => { - err.span_label(span, "type aliases cannot be used as traits"); - if nightly_options::is_nightly_build() { - err.note("did you mean to use a trait alias?"); - } - } - (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => { - if !path_sep(err, &parent) { - return false; - } - } - (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct) - | (Res::Def(DefKind::Enum, def_id), PathSource::Expr(..)) => { - if let Some(variants) = self.collect_enum_variants(def_id) { - if !variants.is_empty() { - let msg = if variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; - - err.span_suggestions( - span, - msg, - variants.iter().map(path_names_to_string), - Applicability::MaybeIncorrect, - ); - } - } else { - err.note("did you mean to use one of the enum's variants?"); - } - }, - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) - = self.struct_constructors.get(&def_id).cloned() { - let accessible_ctor = self.is_accessible_from(ctor_vis, self.current_module); - if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - format!("constructor is not visible here due to private fields"), - ); - } - } else { - bad_struct_syntax_suggestion(); - } - } - (Res::Def(DefKind::Union, _), _) | - (Res::Def(DefKind::Variant, _), _) | - (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => { - bad_struct_syntax_suggestion(); - } - (Res::SelfTy(..), _) if ns == ValueNS => { - err.span_label(span, fallback_label); - err.note("can't use `Self` as a constructor, you must use the implemented struct"); - } - (Res::Def(DefKind::TyAlias, _), _) - | (Res::Def(DefKind::AssocTy, _), _) if ns == ValueNS => { - err.note("can't use a type alias as a constructor"); - } - _ => return false, - } - true - } - - fn lookup_assoc_candidate(&mut self, - ident: Ident, - ns: Namespace, - filter_fn: FilterFn) - -> Option - where FilterFn: Fn(Res) -> bool - { - fn extract_node_id(t: &Ty) -> Option { - match t.node { - TyKind::Path(None, _) => Some(t.id), - TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty), - // This doesn't handle the remaining `Ty` variants as they are not - // that commonly the self_type, it might be interesting to provide - // support for those in future. - _ => None, - } - } - - // Fields are generally expected in the same contexts as locals. - if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { - if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { - // Look for a field with the same name in the current self_type. - if let Some(resolution) = self.partial_res_map.get(&node_id) { - match resolution.base_res() { - Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) - if resolution.unresolved_segments() == 0 => { - if let Some(field_names) = self.field_names.get(&did) { - if field_names.iter().any(|&field_name| ident.name == field_name) { - return Some(AssocSuggestion::Field); - } - } - } - _ => {} - } - } - } - } - - for assoc_type_ident in &self.current_trait_assoc_types { - if *assoc_type_ident == ident { - return Some(AssocSuggestion::AssocItem); - } - } - - // Look for associated items in the current trait. - if let Some((module, _)) = self.current_trait_ref { - let parent_scope = &self.parent_scope(); - if let Ok(binding) = self.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - false, - module.span, - ) { - let res = binding.res(); - if filter_fn(res) { - return Some(if self.has_self.contains(&res.def_id()) { - AssocSuggestion::MethodWithSelf - } else { - AssocSuggestion::AssocItem - }); - } - } - } - - None - } -} - impl<'a> Resolver<'a> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( @@ -690,103 +200,7 @@ impl<'a> Resolver<'a> { _ => None, } } -} -impl<'a> LateResolutionVisitor<'a, '_> { - fn lookup_typo_candidate( - &mut self, - path: &[Segment], - ns: Namespace, - filter_fn: &impl Fn(Res) -> bool, - span: Span, - ) -> Option { - let mut names = Vec::new(); - if path.len() == 1 { - // Search in lexical scope. - // Walk backwards up the ribs in scope and collect candidates. - for rib in self.ribs[ns].iter().rev() { - // Locals and type parameters - for (ident, &res) in &rib.bindings { - if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); - } - } - // Items in scope - if let RibKind::ModuleRibKind(module) = rib.kind { - // Items from this module - add_module_candidates(module, &mut names, &filter_fn); - - if let ModuleKind::Block(..) = module.kind { - // We can see through blocks - } else { - // Items from the prelude - if !module.no_implicit_prelude { - names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| { - self.crate_loader - .maybe_process_path_extern(ident.name, ident.span) - .and_then(|crate_id| { - let crate_mod = Res::Def( - DefKind::Mod, - DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }, - ); - - if filter_fn(crate_mod) { - Some(TypoSuggestion::from_res(ident.name, crate_mod)) - } else { - None - } - }) - })); - - if let Some(prelude) = self.prelude { - add_module_candidates(prelude, &mut names, &filter_fn); - } - } - break; - } - } - } - // Add primitive types to the mix - if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend( - self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| { - TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty)) - }) - ) - } - } else { - // Search in module. - let mod_path = &path[..path.len() - 1]; - if let PathResult::Module(module) = self.resolve_path( - mod_path, Some(TypeNS), false, span, CrateLint::No - ) { - if let ModuleOrUniformRoot::Module(module) = module { - add_module_candidates(module, &mut names, &filter_fn); - } - } - } - - let name = path[path.len() - 1].ident.name; - // Make sure error reporting is deterministic. - names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str()); - - match find_best_match_for_name( - names.iter().map(|suggestion| &suggestion.candidate), - &name.as_str(), - None, - ) { - Some(found) if found != name => names - .into_iter() - .find(|suggestion| suggestion.candidate == found), - _ => None, - } - } -} - -impl<'a> Resolver<'a> { fn lookup_import_candidates_from_module(&mut self, lookup_ident: Ident, namespace: Namespace, @@ -913,65 +327,6 @@ impl<'a> Resolver<'a> { suggestions } - fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { - let mut result = None; - let mut seen_modules = FxHashSet::default(); - let mut worklist = vec![(self.graph_root, Vec::new())]; - - while let Some((in_module, path_segments)) = worklist.pop() { - // abort if the module is already found - if result.is_some() { break; } - - self.populate_module_if_necessary(in_module); - - in_module.for_each_child_stable(|ident, _, name_binding| { - // abort if the module is already found or if name_binding is private external - if result.is_some() || !name_binding.vis.is_visible_locally() { - return - } - if let Some(module) = name_binding.module() { - // form the path - let mut path_segments = path_segments.clone(); - path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id().unwrap(); - if module_def_id == def_id { - let path = Path { - span: name_binding.span, - segments: path_segments, - }; - result = Some((module, ImportSuggestion { did: Some(def_id), path })); - } else { - // add the module to the lookup - if seen_modules.insert(module_def_id) { - worklist.push((module, path_segments)); - } - } - } - }); - } - - result - } - - fn collect_enum_variants(&mut self, def_id: DefId) -> Option> { - self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { - self.populate_module_if_necessary(enum_module); - - let mut variants = Vec::new(); - enum_module.for_each_child_stable(|ident, _, name_binding| { - if let Res::Def(DefKind::Variant, _) = name_binding.res() { - let mut segms = enum_import_suggestion.path.segments.clone(); - segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { - span: name_binding.span, - segments: segms, - }); - } - }); - variants - }) - } - crate fn unresolved_macro_suggestions( &mut self, err: &mut DiagnosticBuilder<'a>, @@ -1427,21 +782,6 @@ fn find_span_immediately_after_crate_name( (next_left_bracket == after_second_colon, from_second_colon) } -/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) { - let variant_path = &suggestion.path; - let variant_path_string = path_names_to_string(variant_path); - - let path_len = suggestion.path.segments.len(); - let enum_path = ast::Path { - span: suggestion.path.span, - segments: suggestion.path.segments[0..path_len - 1].to_vec(), - }; - let enum_path_string = path_names_to_string(&enum_path); - - (variant_path_string, enum_path_string) -} - /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs new file mode 100644 index 00000000000..e688857d038 --- /dev/null +++ b/src/librustc_resolve/late.rs @@ -0,0 +1,1806 @@ +use GenericParameters::*; + +use crate::{path_names_to_string, resolve_error}; +use crate::{AliasPossibility, BindingError, CrateLint, LexicalScopeBinding, Module}; +use crate::{ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult}; +use crate::{PathSource, ResolutionError, Resolver, Rib, RibKind, Segment, UseError}; +use crate::RibKind::*; + +use log::debug; +use rustc::{bug, lint, span_bug}; +use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS}; +use rustc::hir::def::Namespace::{self, *}; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::TraitCandidate; +use rustc::util::nodemap::FxHashMap; +use smallvec::{smallvec, SmallVec}; +use syntax::{unwrap_or, walk_list}; +use syntax::ast::*; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::{self, Visitor, FnKind}; +use syntax_pos::Span; + +use std::collections::BTreeSet; +use std::mem::replace; +use std::ops::{Deref, DerefMut}; + +mod diagnostics; + +type Res = def::Res; + +/// Map from the name in a pattern to its binding mode. +type BindingMap = FxHashMap; + +#[derive(Copy, Clone, Debug)] +struct BindingInfo { + span: Span, + binding_mode: BindingMode, +} + +#[derive(Copy, Clone)] +enum GenericParameters<'a, 'b> { + NoGenericParams, + HasGenericParams(// Type parameters. + &'b Generics, + + // The kind of the rib used for type parameters. + RibKind<'a>), +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum PatternSource { + Match, + Let, + For, + FnParam, +} + +impl PatternSource { + fn descr(self) -> &'static str { + match self { + PatternSource::Match => "match binding", + PatternSource::Let => "let binding", + PatternSource::For => "for binding", + PatternSource::FnParam => "function parameter", + } + } +} + +struct LateResolutionVisitor<'a, 'b> { + resolver: &'b mut Resolver<'a>, + + /// The module that represents the current item scope. + current_module: Module<'a>, + + /// The current set of local scopes for types and values. + /// FIXME #4948: Reuse ribs to avoid allocation. + ribs: PerNS>>, + + /// The current set of local scopes, for labels. + label_ribs: Vec>, + + /// The trait that the current context can refer to. + current_trait_ref: Option<(Module<'a>, TraitRef)>, + + /// The current trait's associated types' ident, used for diagnostic suggestions. + current_trait_assoc_types: Vec, + + /// The current self type if inside an impl (used for better errors). + current_self_type: Option, + + /// The current self item if inside an ADT (used for better errors). + current_self_item: Option, + + /// A list of labels as of yet unused. Labels will be removed from this map when + /// they are used (in a `break` or `continue` statement) + unused_labels: FxHashMap, + + /// Only used for better errors on `fn(): fn()`. + current_type_ascription: Vec, +} + +impl<'a> Deref for LateResolutionVisitor<'a, '_> { + type Target = Resolver<'a>; + fn deref(&self) -> &Self::Target { + self.resolver + } +} + +impl<'a> DerefMut for LateResolutionVisitor<'a, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.resolver + } +} + +/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. +impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> { + fn visit_item(&mut self, item: &'tcx Item) { + self.resolve_item(item); + } + fn visit_arm(&mut self, arm: &'tcx Arm) { + self.resolve_arm(arm); + } + fn visit_block(&mut self, block: &'tcx Block) { + self.resolve_block(block); + } + fn visit_anon_const(&mut self, constant: &'tcx AnonConst) { + debug!("visit_anon_const {:?}", constant); + self.with_constant_rib(|this| { + visit::walk_anon_const(this, constant); + }); + } + fn visit_expr(&mut self, expr: &'tcx Expr) { + self.resolve_expr(expr, None); + } + fn visit_local(&mut self, local: &'tcx Local) { + self.resolve_local(local); + } + fn visit_ty(&mut self, ty: &'tcx Ty) { + match ty.node { + TyKind::Path(ref qself, ref path) => { + self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); + } + TyKind::ImplicitSelf => { + let self_ty = Ident::with_empty_ctxt(kw::SelfUpper); + let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) + .map_or(Res::Err, |d| d.res()); + self.record_partial_res(ty.id, PartialRes::new(res)); + } + _ => (), + } + visit::walk_ty(self, ty); + } + fn visit_poly_trait_ref(&mut self, + tref: &'tcx PolyTraitRef, + m: &'tcx TraitBoundModifier) { + self.smart_resolve_path(tref.trait_ref.ref_id, None, + &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe)); + visit::walk_poly_trait_ref(self, tref, m); + } + fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) { + let generic_params = match foreign_item.node { + ForeignItemKind::Fn(_, ref generics) => { + HasGenericParams(generics, ItemRibKind) + } + ForeignItemKind::Static(..) => NoGenericParams, + ForeignItemKind::Ty => NoGenericParams, + ForeignItemKind::Macro(..) => NoGenericParams, + }; + self.with_generic_param_rib(generic_params, |this| { + visit::walk_foreign_item(this, foreign_item); + }); + } + fn visit_fn(&mut self, + function_kind: FnKind<'tcx>, + declaration: &'tcx FnDecl, + _: Span, + _: NodeId) + { + debug!("(resolving function) entering function"); + let rib_kind = match function_kind { + FnKind::ItemFn(..) => FnItemRibKind, + FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, + }; + + // Create a value rib for the function. + self.ribs[ValueNS].push(Rib::new(rib_kind)); + + // Create a label rib for the function. + self.label_ribs.push(Rib::new(rib_kind)); + + // Add each argument to the rib. + let mut bindings_list = FxHashMap::default(); + for argument in &declaration.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + + self.visit_ty(&argument.ty); + + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); + + // Resolve the function body, potentially inside the body of an async closure + match function_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); + } + FnKind::Closure(body) => { + self.visit_expr(body); + } + }; + + debug!("(resolving function) leaving function"); + + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + + fn visit_generics(&mut self, generics: &'tcx Generics) { + // For type parameter defaults, we have to ban access + // to following type parameters, as the InternalSubsts can only + // provide previous type parameters as they're built. We + // put all the parameters on the ban list and then remove + // them one by one as they are processed and become available. + let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind); + let mut found_default = false; + default_ban_rib.bindings.extend(generics.params.iter() + .filter_map(|param| match param.kind { + GenericParamKind::Const { .. } | + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { ref default, .. } => { + found_default |= default.is_some(); + if found_default { + Some((Ident::with_empty_ctxt(param.ident.name), Res::Err)) + } else { + None + } + } + })); + + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_empty_ctxt(param.ident.name), Res::Err))); + + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), + GenericParamKind::Type { ref default, .. } => { + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + if let Some(ref ty) = default { + self.ribs[TypeNS].push(default_ban_rib); + self.visit_ty(ty); + default_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + + // Allow all following defaults to refer to this type parameter. + default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); + } + GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + + for bound in ¶m.bounds { + self.visit_param_bound(bound); + } + + self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); + } + } + } + for p in &generics.where_clause.predicates { + self.visit_where_predicate(p); + } + } +} + +impl<'a, 'b> LateResolutionVisitor<'a, '_> { + fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> { + let graph_root = resolver.graph_root; + LateResolutionVisitor { + resolver, + current_module: graph_root, + ribs: PerNS { + value_ns: vec![Rib::new(ModuleRibKind(graph_root))], + type_ns: vec![Rib::new(ModuleRibKind(graph_root))], + macro_ns: vec![Rib::new(ModuleRibKind(graph_root))], + }, + label_ribs: Vec::new(), + current_trait_ref: None, + current_trait_assoc_types: Vec::new(), + current_self_type: None, + current_self_item: None, + unused_labels: Default::default(), + current_type_ascription: Vec::new(), + } + } + + fn parent_scope(&self) -> ParentScope<'a> { + ParentScope { module: self.current_module, ..self.dummy_parent_scope() } + } + + fn resolve_ident_in_lexical_scope(&mut self, + ident: Ident, + ns: Namespace, + record_used_id: Option, + path_span: Span) + -> Option> { + self.resolver.resolve_ident_in_lexical_scope( + ident, ns, &self.parent_scope(), record_used_id, path_span, &self.ribs[ns] + ) + } + + fn resolve_path( + &mut self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + record_used: bool, + path_span: Span, + crate_lint: CrateLint, + ) -> PathResult<'a> { + self.resolver.resolve_path_with_ribs( + path, opt_ns, &self.parent_scope(), record_used, path_span, crate_lint, &self.ribs + ) + } + + // AST resolution + // + // We maintain a list of value ribs and type ribs. + // + // Simultaneously, we keep track of the current position in the module + // graph in the `current_module` pointer. When we go to resolve a name in + // the value or type namespaces, we first look through all the ribs and + // then query the module graph. When we resolve a name in the module + // namespace, we can skip all the ribs (since nested modules are not + // allowed within blocks in Rust) and jump straight to the current module + // graph node. + // + // Named implementations are handled separately. When we find a method + // call, we consult the module node to find all of the implementations in + // scope. This information is lazily cached in the module node. We then + // generate a fake "implementation scope" containing all the + // implementations thus found, for compatibility with old resolve pass. + + fn with_scope(&mut self, id: NodeId, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let id = self.definitions.local_def_id(id); + let module = self.module_map.get(&id).cloned(); // clones a reference + if let Some(module) = module { + // Move down in the graph. + let orig_module = replace(&mut self.current_module, module); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(module))); + + self.finalize_current_module_macro_resolutions(module); + let ret = f(self); + + self.current_module = orig_module; + self.ribs[ValueNS].pop(); + self.ribs[TypeNS].pop(); + ret + } else { + f(self) + } + } + + /// Searches the current set of local scopes for labels. Returns the first non-`None` label that + /// is returned by the given predicate function + /// + /// Stops after meeting a closure. + fn search_label(&self, mut ident: Ident, pred: P) -> Option + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option + { + for rib in self.label_ribs.iter().rev() { + match rib.kind { + NormalRibKind => {} + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + MacroDefinition(def) => { + if def == self.macro_def(ident.span.ctxt()) { + ident.span.remove_mark(); + } + } + _ => { + // Do not resolve labels across function boundary + return None; + } + } + let r = pred(rib, ident); + if r.is_some() { + return r; + } + } + None + } + + fn resolve_adt(&mut self, item: &Item, generics: &Generics) { + debug!("resolve_adt"); + self.with_current_self_item(item, |this| { + this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let item_def_id = this.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + visit::walk_item(this, item); + }); + }); + }); + } + + fn future_proof_import(&mut self, use_tree: &UseTree) { + let segments = &use_tree.prefix.segments; + if !segments.is_empty() { + let ident = segments[0].ident; + if ident.is_path_segment_keyword() || ident.span.rust_2015() { + return; + } + + let nss = match use_tree.kind { + UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..], + _ => &[TypeNS], + }; + let report_error = |this: &Self, ns| { + let what = if ns == TypeNS { "type parameters" } else { "local variables" }; + this.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + }; + + for &ns in nss { + match self.resolve_ident_in_lexical_scope(ident, ns, None, use_tree.prefix.span) { + Some(LexicalScopeBinding::Res(..)) => { + report_error(self, ns); + } + Some(LexicalScopeBinding::Item(binding)) => { + let orig_blacklisted_binding = + replace(&mut self.blacklisted_binding, Some(binding)); + if let Some(LexicalScopeBinding::Res(..)) = + self.resolve_ident_in_lexical_scope(ident, ns, None, + use_tree.prefix.span) { + report_error(self, ns); + } + self.blacklisted_binding = orig_blacklisted_binding; + } + None => {} + } + } + } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind { + for (use_tree, _) in use_trees { + self.future_proof_import(use_tree); + } + } + } + + fn resolve_item(&mut self, item: &Item) { + let name = item.ident.name; + debug!("(resolving item) resolving {} ({:?})", name, item.node); + + match item.node { + ItemKind::TyAlias(_, ref generics) | + ItemKind::OpaqueTy(_, ref generics) | + ItemKind::Fn(_, _, ref generics, _) => { + self.with_generic_param_rib( + HasGenericParams(generics, ItemRibKind), + |this| visit::walk_item(this, item) + ); + } + + ItemKind::Enum(_, ref generics) | + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) => { + self.resolve_adt(item, generics); + } + + ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => + self.resolve_implementation(generics, + opt_trait_ref, + &self_type, + item.id, + impl_items), + + ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let local_def_id = this.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + + for trait_item in trait_items { + this.with_trait_items(trait_items, |this| { + let generic_params = HasGenericParams( + &trait_item.generics, + AssocItemRibKind, + ); + this.with_generic_param_rib(generic_params, |this| { + match trait_item.node { + TraitItemKind::Const(ref ty, ref default) => { + this.visit_ty(ty); + + // Only impose the restrictions of + // ConstRibKind for an actual constant + // expression in a provided default. + if let Some(ref expr) = *default{ + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + } + } + TraitItemKind::Method(_, _) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Type(..) => { + visit::walk_trait_item(this, trait_item) + } + TraitItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") + } + }; + }); + }); + } + }); + }); + } + + ItemKind::TraitAlias(ref generics, ref bounds) => { + // Create a new rib for the trait-wide type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + let local_def_id = this.definitions.local_def_id(item.id); + this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + this.visit_generics(generics); + walk_list!(this, visit_param_bound, bounds); + }); + }); + } + + ItemKind::Mod(_) | ItemKind::ForeignMod(_) => { + self.with_scope(item.id, |this| { + visit::walk_item(this, item); + }); + } + + ItemKind::Static(ref ty, _, ref expr) | + ItemKind::Const(ref ty, ref expr) => { + debug!("resolve_item ItemKind::Const"); + self.with_item_rib(|this| { + this.visit_ty(ty); + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + }); + } + + ItemKind::Use(ref use_tree) => { + self.future_proof_import(use_tree); + } + + ItemKind::ExternCrate(..) | + ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) => { + // do nothing, these are just around to be encoded + } + + ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + } + } + + fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + debug!("with_generic_param_rib"); + match generic_params { + HasGenericParams(generics, rib_kind) => { + let mut function_type_rib = Rib::new(rib_kind); + let mut function_value_rib = Rib::new(rib_kind); + let mut seen_bindings = FxHashMap::default(); + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { .. } => { + let ident = param.ident.modern(); + debug!("with_generic_param_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInParameterList( + ident.name, + *span, + ); + resolve_error(self, param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); + + // Plain insert (no renaming). + let res = Res::Def( + DefKind::TyParam, + self.definitions.local_def_id(param.id), + ); + function_type_rib.bindings.insert(ident, res); + self.record_partial_res(param.id, PartialRes::new(res)); + } + GenericParamKind::Const { .. } => { + let ident = param.ident.modern(); + debug!("with_generic_param_rib: {}", param.id); + + if seen_bindings.contains_key(&ident) { + let span = seen_bindings.get(&ident).unwrap(); + let err = ResolutionError::NameAlreadyUsedInParameterList( + ident.name, + *span, + ); + resolve_error(self, param.ident.span, err); + } + seen_bindings.entry(ident).or_insert(param.ident.span); + + let res = Res::Def( + DefKind::ConstParam, + self.definitions.local_def_id(param.id), + ); + function_value_rib.bindings.insert(ident, res); + self.record_partial_res(param.id, PartialRes::new(res)); + } + } + } + self.ribs[ValueNS].push(function_value_rib); + self.ribs[TypeNS].push(function_type_rib); + } + + NoGenericParams => { + // Nothing to do. + } + } + + f(self); + + if let HasGenericParams(..) = generic_params { + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); + } + } + + fn with_label_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + self.label_ribs.push(Rib::new(NormalRibKind)); + f(self); + self.label_ribs.pop(); + } + + fn with_item_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + self.ribs[ValueNS].push(Rib::new(ItemRibKind)); + self.ribs[TypeNS].push(Rib::new(ItemRibKind)); + f(self); + self.ribs[TypeNS].pop(); + self.ribs[ValueNS].pop(); + } + + fn with_constant_rib(&mut self, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + debug!("with_constant_rib"); + self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind)); + self.label_ribs.push(Rib::new(ConstantItemRibKind)); + f(self); + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + + fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + // Handle nested impls (inside fn bodies) + let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); + let result = f(self); + self.current_self_type = previous_value; + result + } + + fn with_current_self_item(&mut self, self_item: &Item, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let previous_value = replace(&mut self.current_self_item, Some(self_item.id)); + let result = f(self); + self.current_self_item = previous_value; + result + } + + /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. + fn with_trait_items(&mut self, trait_items: &Vec, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) -> T + { + let trait_assoc_types = replace( + &mut self.current_trait_assoc_types, + trait_items.iter().filter_map(|item| match &item.node { + TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident), + _ => None, + }).collect(), + ); + let result = f(self); + self.current_trait_assoc_types = trait_assoc_types; + result + } + + /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). + fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>, Option) -> T + { + let mut new_val = None; + let mut new_id = None; + if let Some(trait_ref) = opt_trait_ref { + let path: Vec<_> = Segment::from_path(&trait_ref.path); + let res = self.smart_resolve_path_fragment( + trait_ref.ref_id, + None, + &path, + trait_ref.path.span, + PathSource::Trait(AliasPossibility::No), + CrateLint::SimplePath(trait_ref.ref_id), + ).base_res(); + if res != Res::Err { + new_id = Some(res.def_id()); + let span = trait_ref.path.span; + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path( + &path, + Some(TypeNS), + false, + span, + CrateLint::SimplePath(trait_ref.ref_id), + ) + { + new_val = Some((module, trait_ref.clone())); + } + } + } + let original_trait_ref = replace(&mut self.current_trait_ref, new_val); + let result = f(self, new_id); + self.current_trait_ref = original_trait_ref; + result + } + + fn with_self_rib(&mut self, self_res: Res, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + let mut self_type_rib = Rib::new(NormalRibKind); + + // Plain insert (no renaming, since types are not currently hygienic) + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); + self.ribs[TypeNS].push(self_type_rib); + f(self); + self.ribs[TypeNS].pop(); + } + + fn with_self_struct_ctor_rib(&mut self, impl_id: DefId, f: F) + where F: FnOnce(&mut LateResolutionVisitor<'_, '_>) + { + let self_res = Res::SelfCtor(impl_id); + let mut self_type_rib = Rib::new(NormalRibKind); + self_type_rib.bindings.insert(Ident::with_empty_ctxt(kw::SelfUpper), self_res); + self.ribs[ValueNS].push(self_type_rib); + f(self); + self.ribs[ValueNS].pop(); + } + + fn resolve_implementation(&mut self, + generics: &Generics, + opt_trait_reference: &Option, + self_type: &Ty, + item_id: NodeId, + impl_items: &[ImplItem]) { + debug!("resolve_implementation"); + // If applicable, create a rib for the type parameters. + self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| { + // Dummy self type for better errors if `Self` is used in the trait path. + this.with_self_rib(Res::SelfTy(None, None), |this| { + // Resolve the trait reference, if necessary. + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { + let item_def_id = this.definitions.local_def_id(item_id); + this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + if let Some(trait_ref) = opt_trait_reference.as_ref() { + // Resolve type arguments in the trait path. + visit::walk_trait_ref(this, trait_ref); + } + // Resolve the self type. + this.visit_ty(self_type); + // Resolve the generic parameters. + this.visit_generics(generics); + // Resolve the items within the impl. + this.with_current_self_type(self_type, |this| { + this.with_self_struct_ctor_rib(item_def_id, |this| { + debug!("resolve_implementation with_self_struct_ctor_rib"); + for impl_item in impl_items { + this.resolver.resolve_visibility( + &impl_item.vis, &this.parent_scope() + ); + // We also need a new scope for the impl item type parameters. + let generic_params = HasGenericParams(&impl_item.generics, + AssocItemRibKind); + this.with_generic_param_rib(generic_params, |this| { + use crate::ResolutionError::*; + match impl_item.node { + ImplItemKind::Const(..) => { + debug!( + "resolve_implementation ImplItemKind::Const", + ); + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + impl_item.ident, + ValueNS, + impl_item.span, + |n, s| ConstNotMemberOfTrait(n, s), + ); + + this.with_constant_rib(|this| { + visit::walk_impl_item(this, impl_item) + }); + } + ImplItemKind::Method(..) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident, + ValueNS, + impl_item.span, + |n, s| MethodNotMemberOfTrait(n, s)); + + visit::walk_impl_item(this, impl_item); + } + ImplItemKind::TyAlias(ref ty) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + this.visit_ty(ty); + } + ImplItemKind::OpaqueTy(ref bounds) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + + for bound in bounds { + this.visit_param_bound(bound); + } + } + ImplItemKind::Macro(_) => + panic!("unexpanded macro in resolve!"), + } + }); + } + }); + }); + }); + }); + }); + }); + } + + fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) + where F: FnOnce(Name, &str) -> ResolutionError<'_> + { + // If there is a TraitRef in scope for an impl, then the method must be in the + // trait. + if let Some((module, _)) = self.current_trait_ref { + let parent_scope = &self.parent_scope(); + if self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + false, + span, + ).is_err() { + let path = &self.current_trait_ref.as_ref().unwrap().1.path; + resolve_error(self, span, err(ident.name, &path_names_to_string(path))); + } + } + } + + fn resolve_local(&mut self, local: &Local) { + // Resolve the type. + walk_list!(self, visit_ty, &local.ty); + + // Resolve the initializer. + walk_list!(self, visit_expr, &local.init); + + // Resolve the pattern. + self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap::default()); + } + + // build a map from pattern identifiers to binding-info's. + // this is done hygienically. This could arise for a macro + // that expands into an or-pattern where one 'x' was from the + // user and one 'x' came from the macro. + fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { + let mut binding_map = FxHashMap::default(); + + pat.walk(&mut |pat| { + if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { + if sub_pat.is_some() || match self.partial_res_map.get(&pat.id) + .map(|res| res.base_res()) { + Some(Res::Local(..)) => true, + _ => false, + } { + let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode }; + binding_map.insert(ident, binding_info); + } + } + true + }); + + binding_map + } + + // Checks that all of the arms in an or-pattern have exactly the + // same set of bindings, with the same binding modes for each. + fn check_consistent_bindings(&mut self, pats: &[P]) { + if pats.is_empty() { + return; + } + + let mut missing_vars = FxHashMap::default(); + let mut inconsistent_vars = FxHashMap::default(); + for (i, p) in pats.iter().enumerate() { + let map_i = self.binding_mode_map(&p); + + for (j, q) in pats.iter().enumerate() { + if i == j { + continue; + } + + let map_j = self.binding_mode_map(&q); + for (&key, &binding_i) in &map_i { + if map_j.is_empty() { // Account for missing bindings when + let binding_error = missing_vars // `map_j` has none. + .entry(key.name) + .or_insert(BindingError { + name: key.name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + }); + binding_error.origin.insert(binding_i.span); + binding_error.target.insert(q.span); + } + for (&key_j, &binding_j) in &map_j { + match map_i.get(&key_j) { + None => { // missing binding + let binding_error = missing_vars + .entry(key_j.name) + .or_insert(BindingError { + name: key_j.name, + origin: BTreeSet::new(), + target: BTreeSet::new(), + }); + binding_error.origin.insert(binding_j.span); + binding_error.target.insert(p.span); + } + Some(binding_i) => { // check consistent binding + if binding_i.binding_mode != binding_j.binding_mode { + inconsistent_vars + .entry(key.name) + .or_insert((binding_j.span, binding_i.span)); + } + } + } + } + } + } + } + let mut missing_vars = missing_vars.iter().collect::>(); + missing_vars.sort(); + for (_, v) in missing_vars { + resolve_error(self, + *v.origin.iter().next().unwrap(), + ResolutionError::VariableNotBoundInPattern(v)); + } + let mut inconsistent_vars = inconsistent_vars.iter().collect::>(); + inconsistent_vars.sort(); + for (name, v) in inconsistent_vars { + resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); + } + } + + fn resolve_arm(&mut self, arm: &Arm) { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + + self.resolve_pats(&arm.pats, PatternSource::Match); + + if let Some(ref expr) = arm.guard { + self.visit_expr(expr) + } + self.visit_expr(&arm.body); + + self.ribs[ValueNS].pop(); + } + + /// Arising from `source`, resolve a sequence of patterns (top level or-patterns). + fn resolve_pats(&mut self, pats: &[P], source: PatternSource) { + let mut bindings_list = FxHashMap::default(); + for pat in pats { + self.resolve_pattern(pat, source, &mut bindings_list); + } + // This has to happen *after* we determine which pat_idents are variants + self.check_consistent_bindings(pats); + } + + fn resolve_block(&mut self, block: &Block) { + debug!("(resolving block) entering block"); + // Move down in the graph, if there's an anonymous module rooted here. + let orig_module = self.current_module; + let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference + + let mut num_macro_definition_ribs = 0; + if let Some(anonymous_module) = anonymous_module { + debug!("(resolving block) found anonymous module, moving down"); + self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module))); + self.current_module = anonymous_module; + self.finalize_current_module_macro_resolutions(anonymous_module); + } else { + self.ribs[ValueNS].push(Rib::new(NormalRibKind)); + } + + // Descend into the block. + for stmt in &block.stmts { + if let StmtKind::Item(ref item) = stmt.node { + if let ItemKind::MacroDef(..) = item.node { + num_macro_definition_ribs += 1; + let res = self.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(res))); + self.label_ribs.push(Rib::new(MacroDefinition(res))); + } + } + + self.visit_stmt(stmt); + } + + // Move back up. + self.current_module = orig_module; + for _ in 0 .. num_macro_definition_ribs { + self.ribs[ValueNS].pop(); + self.label_ribs.pop(); + } + self.ribs[ValueNS].pop(); + if anonymous_module.is_some() { + self.ribs[TypeNS].pop(); + } + debug!("(resolving block) leaving block"); + } + + fn fresh_binding(&mut self, + ident: Ident, + pat_id: NodeId, + outer_pat_id: NodeId, + pat_src: PatternSource, + bindings: &mut FxHashMap) + -> Res { + // Add the binding to the local ribs, if it + // doesn't already exist in the bindings map. (We + // must not add it if it's in the bindings map + // because that breaks the assumptions later + // passes make about or-patterns.) + let ident = ident.modern_and_legacy(); + let mut res = Res::Local(pat_id); + match bindings.get(&ident).cloned() { + Some(id) if id == outer_pat_id => { + // `Variant(a, a)`, error + resolve_error( + self, + ident.span, + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( + &ident.as_str()) + ); + } + Some(..) if pat_src == PatternSource::FnParam => { + // `fn f(a: u8, a: u8)`, error + resolve_error( + self, + ident.span, + ResolutionError::IdentifierBoundMoreThanOnceInParameterList( + &ident.as_str()) + ); + } + Some(..) if pat_src == PatternSource::Match || + pat_src == PatternSource::Let => { + // `Variant1(a) | Variant2(a)`, ok + // Reuse definition from the first `a`. + res = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident]; + } + Some(..) => { + span_bug!(ident.span, "two bindings with the same name from \ + unexpected pattern source {:?}", pat_src); + } + None => { + // A completely fresh binding, add to the lists if it's valid. + if ident.name != kw::Invalid { + bindings.insert(ident, outer_pat_id); + self.ribs[ValueNS].last_mut().unwrap().bindings.insert(ident, res); + } + } + } + + res + } + + fn resolve_pattern(&mut self, + pat: &Pat, + pat_src: PatternSource, + // Maps idents to the node ID for the + // outermost pattern that binds them. + bindings: &mut FxHashMap) { + // Visit all direct subpatterns of this pattern. + let outer_pat_id = pat.id; + pat.walk(&mut |pat| { + debug!("resolve_pattern pat={:?} node={:?}", pat, pat.node); + match pat.node { + PatKind::Ident(bmode, ident, ref opt_pat) => { + // First try to resolve the identifier as some existing + // entity, then fall back to a fresh binding. + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, + None, pat.span) + .and_then(LexicalScopeBinding::item); + let res = binding.map(NameBinding::res).and_then(|res| { + let is_syntactic_ambiguity = opt_pat.is_none() && + bmode == BindingMode::ByValue(Mutability::Immutable); + match res { + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | + Res::Def(DefKind::Const, _) if is_syntactic_ambiguity => { + // Disambiguate in favor of a unit struct/variant + // or constant pattern. + self.record_use(ident, ValueNS, binding.unwrap(), false); + Some(res) + } + Res::Def(DefKind::Ctor(..), _) + | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::Static, _) => { + // This is unambiguously a fresh binding, either syntactically + // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves + // to something unusable as a pattern (e.g., constructor function), + // but we still conservatively report an error, see + // issues/33118#issuecomment-233962221 for one reason why. + resolve_error( + self, + ident.span, + ResolutionError::BindingShadowsSomethingUnacceptable( + pat_src.descr(), ident.name, binding.unwrap()) + ); + None + } + Res::Def(DefKind::Fn, _) | Res::Err => { + // These entities are explicitly allowed + // to be shadowed by fresh bindings. + None + } + res => { + span_bug!(ident.span, "unexpected resolution for an \ + identifier in pattern: {:?}", res); + } + } + }).unwrap_or_else(|| { + self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) + }); + + self.record_partial_res(pat.id, PartialRes::new(res)); + } + + PatKind::TupleStruct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct); + } + + PatKind::Path(ref qself, ref path) => { + self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); + } + + PatKind::Struct(ref path, ..) => { + self.smart_resolve_path(pat.id, None, path, PathSource::Struct); + } + + _ => {} + } + true + }); + + visit::walk_pat(self, pat); + } + + // High-level and context dependent path resolution routine. + // Resolves the path and records the resolution into definition map. + // If resolution fails tries several techniques to find likely + // resolution candidates, suggest imports or other help, and report + // errors in user friendly way. + fn smart_resolve_path(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &Path, + source: PathSource<'_>) { + self.smart_resolve_path_fragment( + id, + qself, + &Segment::from_path(path), + path.span, + source, + CrateLint::SimplePath(id), + ); + } + + fn smart_resolve_path_fragment(&mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + span: Span, + source: PathSource<'_>, + crate_lint: CrateLint) + -> PartialRes { + let ns = source.namespace(); + let is_expected = &|res| source.is_expected(res); + + let report_errors = |this: &mut Self, res: Option| { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + let def_id = this.current_module.normal_ancestor_id; + let node_id = this.definitions.as_local_node_id(def_id).unwrap(); + let better = res.is_some(); + this.use_injections.push(UseError { err, candidates, node_id, better }); + PartialRes::new(Res::Err) + }; + + let partial_res = match self.resolve_qpath_anywhere( + id, + qself, + path, + ns, + span, + source.defer_to_typeck(), + crate_lint, + ) { + Some(partial_res) if partial_res.unresolved_segments() == 0 => { + if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + partial_res + } else { + // Add a temporary hack to smooth the transition to new struct ctor + // visibility rules. See #38932 for more details. + let mut res = None; + if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() { + if let Some((ctor_res, ctor_vis)) + = self.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_res) && + self.is_accessible_from(ctor_vis, self.current_module) { + let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; + self.session.buffer_lint(lint, id, span, + "private struct constructors are not usable through \ + re-exports in outer modules", + ); + res = Some(PartialRes::new(ctor_res)); + } + } + } + + res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res()))) + } + } + Some(partial_res) if source.defer_to_typeck() => { + // Not fully resolved associated item `T::A::B` or `::A::B` + // or `::A::B`. If `B` should be resolved in value namespace then + // it needs to be added to the trait map. + if ns == ValueNS { + let item_name = path.last().unwrap().ident; + let traits = self.get_traits_containing_item(item_name, ns); + self.trait_map.insert(id, traits); + } + + let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))]; + std_path.extend(path); + if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { + let cl = CrateLint::No; + let ns = Some(ns); + if let PathResult::Module(_) | PathResult::NonModule(_) = + self.resolve_path(&std_path, ns, false, span, cl) { + // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + let item_span = path.iter().last().map(|segment| segment.ident.span) + .unwrap_or(span); + debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.session.confused_type_with_std_module.borrow_mut(); + hm.insert(item_span, span); + // In some places (E0223) we only have access to the full path + hm.insert(span, span); + } + } + partial_res + } + _ => report_errors(self, None) + }; + + if let PathSource::TraitItem(..) = source {} else { + // Avoid recording definition of `A::B` in `::B::C`. + self.record_partial_res(id, partial_res); + } + partial_res + } + + fn self_type_is_available(&mut self, span: Span) -> bool { + let binding = self.resolve_ident_in_lexical_scope( + Ident::with_empty_ctxt(kw::SelfUpper), + TypeNS, + None, + span, + ); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool { + let ident = Ident::new(kw::SelfLower, self_span); + let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, path_span); + if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + } + + // Resolve in alternative namespaces if resolution in the primary namespace fails. + fn resolve_qpath_anywhere( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + primary_ns: Namespace, + span: Span, + defer_to_typeck: bool, + crate_lint: CrateLint, + ) -> Option { + let mut fin_res = None; + for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { + if i == 0 || ns != primary_ns { + match self.resolve_qpath(id, qself, path, ns, span, crate_lint) { + // If defer_to_typeck, then resolution > no resolution, + // otherwise full resolution > partial resolution > no resolution. + Some(partial_res) if partial_res.unresolved_segments() == 0 || + defer_to_typeck => + return Some(partial_res), + partial_res => if fin_res.is_none() { fin_res = partial_res }, + } + } + } + + // `MacroNS` + assert!(primary_ns != MacroNS); + if qself.is_none() { + let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); + let path = Path { segments: path.iter().map(path_seg).collect(), span }; + let parent_scope = &self.parent_scope(); + if let Ok((_, res)) = + self.resolve_macro_path(&path, None, parent_scope, false, false) { + return Some(PartialRes::new(res)); + } + } + + fin_res + } + + /// Handles paths that may refer to associated items. + fn resolve_qpath( + &mut self, + id: NodeId, + qself: Option<&QSelf>, + path: &[Segment], + ns: Namespace, + span: Span, + crate_lint: CrateLint, + ) -> Option { + debug!( + "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})", + id, + qself, + path, + ns, + span, + ); + + 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` + // segment to be resolved by type-check. + return Some(PartialRes::with_unresolved_segments( + Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len() + )); + } + + // 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 + // the trait (the slice upto and including + // `qself.position`). And then we recursively resolve that, + // but with `qself` set to `None`. + // + // However, setting `qself` to none (but not changing the + // span) loses the information about where this path + // *actually* appears, so for the purposes of the crate + // lint we pass along information that this is the trait + // name from a fully qualified path, and this also + // contains the full span (the `CrateLint::QPathTrait`). + let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; + let partial_res = self.smart_resolve_path_fragment( + id, + None, + &path[..=qself.position], + span, + PathSource::TraitItem(ns), + CrateLint::QPathTrait { + qpath_id: id, + qpath_span: qself.path_span, + }, + ); + + // The remaining segments (the `C` in our example) will + // have to be resolved by type-check, since that requires doing + // trait resolution. + return Some(PartialRes::with_unresolved_segments( + partial_res.base_res(), + partial_res.unresolved_segments() + path.len() - qself.position - 1, + )); + } + + let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) { + PathResult::NonModule(path_res) => path_res, + PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { + PartialRes::new(module.res().unwrap()) + } + // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we + // don't report an error right away, but try to fallback to a primitive type. + // So, we are still able to successfully resolve something like + // + // use std::u8; // bring module u8 in scope + // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 + // u8::max_value() // OK, resolves to associated function ::max_value, + // // not to non-existent std::u8::max_value + // } + // + // Such behavior is required for backward compatibility. + // The same fallback is used when `a` resolves to nothing. + PathResult::Module(ModuleOrUniformRoot::Module(_)) | + PathResult::Failed { .. } + if (ns == TypeNS || path.len() > 1) && + self.primitive_type_table.primitive_types + .contains_key(&path[0].ident.name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].ident.name]; + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) + } + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + PartialRes::new(module.res().unwrap()), + PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { + resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion }); + PartialRes::new(Res::Err) + } + PathResult::Module(..) | PathResult::Failed { .. } => return None, + PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), + }; + + if path.len() > 1 && result.base_res() != Res::Err && + path[0].ident.name != kw::PathRoot && + path[0].ident.name != kw::DollarCrate { + let unqualified_result = { + match self.resolve_path( + &[*path.last().unwrap()], + Some(ns), + false, + span, + CrateLint::No, + ) { + PathResult::NonModule(path_res) => path_res.base_res(), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.res().unwrap(), + _ => return Some(result), + } + }; + if result.base_res() == unqualified_result { + let lint = lint::builtin::UNUSED_QUALIFICATIONS; + self.session.buffer_lint(lint, id, span, "unnecessary qualification") + } + } + + Some(result) + } + + fn with_resolved_label(&mut self, label: Option