diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 127331152c155..1dfd7a68db145 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -84,6 +84,13 @@ mod check_unused; mod build_reduced_graph; mod resolve_imports; +pub struct ResolvePath<'a> { + segments: &'a [Ident], + /// NodeId of the path that we are attempting to resolve. When None, this path is being + /// speculatively resolved and we should not emit errors or lints about it + source: Option, +} + /// A free importable items suggested in case of resolution failure. struct ImportSuggestion { path: Path, @@ -1654,12 +1661,17 @@ impl<'a> Resolver<'a> { let path: Vec = segments.iter() .map(|seg| Ident::new(seg.name, span)) .collect(); + + let path = ResolvePath { + segments: &path, + source: None, + }; // FIXME (Manishearth): Intra doc links won't get warned of epoch changes - match self.resolve_path(&path, Some(namespace), true, span, None) { + match self.resolve_path(&path, Some(namespace), true, span) { PathResult::Module(module) => *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), - PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span, None) { + PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) { PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); } @@ -2351,6 +2363,10 @@ impl<'a> Resolver<'a> { let path: Vec<_> = trait_ref.path.segments.iter() .map(|seg| seg.ident) .collect(); + let path = ResolvePath { + segments: &path, + source: Some(trait_ref.ref_id), + }; let def = self.smart_resolve_path_fragment( trait_ref.ref_id, None, @@ -2361,8 +2377,7 @@ impl<'a> Resolver<'a> { if def != Def::Err { new_id = Some(def.def_id()); let span = trait_ref.path.span; - if let PathResult::Module(module) = self.resolve_path(&path, None, false, span, - Some(trait_ref.ref_id)) { + if let PathResult::Module(module) = self.resolve_path(&path, None, false, span) { new_val = Some((module, trait_ref.clone())); } } @@ -2787,17 +2802,21 @@ impl<'a> Resolver<'a> { let segments = &path.segments.iter() .map(|seg| seg.ident) .collect::>(); - self.smart_resolve_path_fragment(id, qself, segments, path.span, source) + let resolve_path = ResolvePath { + segments: &segments, + source: Some(id), + }; + self.smart_resolve_path_fragment(id, qself, &resolve_path, path.span, source) } fn smart_resolve_path_fragment(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &ResolvePath, span: Span, source: PathSource) -> PathResolution { - let ident_span = path.last().map_or(span, |ident| ident.span); + let ident_span = path.segments.last().map_or(span, |ident| ident.span); let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; @@ -2806,27 +2825,31 @@ impl<'a> Resolver<'a> { let report_errors = |this: &mut Self, def: Option| { // Make the base error. let expected = source.descr_expected(); - let path_str = names_to_string(path); + let path_str = names_to_string(path.segments); let code = source.error_code(def.is_some()); let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), format!("not a {}", expected), span) } else { - let item_str = path[path.len() - 1]; - let item_span = path[path.len() - 1].span; - let (mod_prefix, mod_str) = if path.len() == 1 { + let item_str = path.segments[path.segments.len() - 1]; + let item_span = path.segments[path.segments.len() - 1].span; + let (mod_prefix, mod_str) = if path.segments.len() == 1 { (format!(""), format!("this scope")) - } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { + } else if path.segments.len() == 2 && + path.segments[0].name == keywords::CrateRoot.name() { (format!(""), format!("the crate root")) } else { - let mod_path = &path[..path.len() - 1]; - let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), - false, span, None) { + let mod_path = ResolvePath { + segments: &path.segments[..path.segments.len() - 1], + source: Some(id), + }; + let mod_prefix = match this.resolve_path(&mod_path, Some(TypeNS), + false, span) { PathResult::Module(module) => module.def(), _ => None, }.map_or(format!(""), |def| format!("{} ", def.kind_name())); - (mod_prefix, format!("`{}`", names_to_string(mod_path))) + (mod_prefix, format!("`{}`", names_to_string(mod_path.segments))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), format!("not found in {}", mod_str), @@ -2836,13 +2859,13 @@ impl<'a> Resolver<'a> { let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit special messages for unresolved `Self` and `self`. - if is_self_type(path, ns) { + if is_self_type(path.segments, ns) { __diagnostic_used!(E0411); err.code(DiagnosticId::Error("E0411".into())); err.span_label(span, "`Self` is only available in traits and impls"); return (err, Vec::new()); } - if is_self_value(path, ns) { + if is_self_value(path.segments, ns) { __diagnostic_used!(E0424); err.code(DiagnosticId::Error("E0424".into())); err.span_label(span, format!("`self` value is only available in \ @@ -2851,7 +2874,7 @@ impl<'a> Resolver<'a> { } // Try to lookup the name in more relaxed fashion for better error reporting. - let ident = *path.last().unwrap(); + let ident = *path.segments.last().unwrap(); let candidates = this.lookup_import_candidates(ident.name, ns, is_expected); if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = @@ -2872,9 +2895,10 @@ impl<'a> Resolver<'a> { } } } - if path.len() == 1 && this.self_type_is_available(span) { + if path.segments.len() == 1 && this.self_type_is_available(span) { if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = this.self_value_is_available(path[0].span, span); + let self_is_available = this.self_value_is_available(path.segments[0].span, + span); match candidate { AssocSuggestion::Field => { err.span_suggestion(span, "try", @@ -2900,7 +2924,8 @@ impl<'a> Resolver<'a> { let mut levenshtein_worked = false; // Try Levenshtein. - if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected, span) { + if let Some(candidate) = this.lookup_typo_candidate(path.segments, ns, is_expected, + span) { err.span_label(ident_span, format!("did you mean `{}`?", candidate)); levenshtein_worked = true; } @@ -3028,7 +3053,7 @@ impl<'a> Resolver<'a> { // 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(); + let item_name = *path.segments.last().unwrap(); let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } @@ -3095,7 +3120,7 @@ impl<'a> Resolver<'a> { fn resolve_qpath_anywhere(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &ResolvePath, primary_ns: Namespace, span: Span, defer_to_typeck: bool, @@ -3115,10 +3140,10 @@ impl<'a> Resolver<'a> { }; } } - let is_global = self.global_macros.get(&path[0].name).cloned() + let is_global = self.global_macros.get(&path.segments[0].name).cloned() .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); if primary_ns != MacroNS && (is_global || - self.macro_names.contains(&path[0].modern())) { + self.macro_names.contains(&path.segments[0].modern())) { // Return some dummy definition, it's enough for error reporting. return Some( PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) @@ -3131,7 +3156,7 @@ impl<'a> Resolver<'a> { fn resolve_qpath(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &ResolvePath, ns: Namespace, span: Span, global_by_default: bool) @@ -3140,19 +3165,23 @@ impl<'a> Resolver<'a> { if qself.position == 0 { // FIXME: Create some fake resolution that can't possibly be a type. return Some(PathResolution::with_unresolved_segments( - Def::Mod(DefId::local(CRATE_DEF_INDEX)), path.len() + Def::Mod(DefId::local(CRATE_DEF_INDEX)), path.segments.len() )); } // Make sure `A::B` in `::B::C` is a trait item. - let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; - let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1], + let ns = if qself.position + 1 == path.segments.len() { ns } else { TypeNS }; + let path = ResolvePath { + segments: &path.segments[..qself.position + 1], + source: Some(id), + }; + let res = self.smart_resolve_path_fragment(id, None, &path, span, PathSource::TraitItem(ns)); return Some(PathResolution::with_unresolved_segments( - res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 + res.base_def(), res.unresolved_segments() + path.segments.len() - qself.position - 1 )); } - let result = match self.resolve_path(&path, Some(ns), true, span, Some(id)) { + let result = match self.resolve_path(&path, Some(ns), true, span) { PathResult::NonModule(path_res) => path_res, PathResult::Module(module) if !module.is_normal() => { PathResolution::new(module.def().unwrap()) @@ -3170,11 +3199,11 @@ impl<'a> Resolver<'a> { // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. PathResult::Module(..) | PathResult::Failed(..) - if (ns == TypeNS || path.len() > 1) && + if (ns == TypeNS || path.segments.len() > 1) && self.primitive_type_table.primitive_types - .contains_key(&path[0].name) => { - let prim = self.primitive_type_table.primitive_types[&path[0].name]; - PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) + .contains_key(&path.segments[0].name) => { + let prim = self.primitive_type_table.primitive_types[&path.segments[0].name]; + PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.segments.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), PathResult::Failed(span, msg, false) => { @@ -3185,11 +3214,15 @@ impl<'a> Resolver<'a> { PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), }; - if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && - path[0].name != keywords::DollarCrate.name() { + if path.segments.len() > 1 && !global_by_default && result.base_def() != Def::Err && + path.segments[0].name != keywords::CrateRoot.name() && + path.segments[0].name != keywords::DollarCrate.name() { let unqualified_result = { - match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span, None) { + let path = ResolvePath { + segments: &[*path.segments.last().unwrap()], + source: None, + }; + match self.resolve_path(&path, Some(ns), false, span) { PathResult::NonModule(path_res) => path_res.base_def(), PathResult::Module(module) => module.def().unwrap(), _ => return Some(result), @@ -3205,19 +3238,16 @@ impl<'a> Resolver<'a> { } fn resolve_path(&mut self, - path: &[Ident], + path: &ResolvePath, opt_ns: Option, // `None` indicates a module path record_used: bool, - path_span: Span, - node_id: Option) // None indicates that we don't care about linting - // `::module` paths - -> PathResult<'a> { + path_span: Span) -> PathResult<'a> { let mut module = None; let mut allow_super = true; - for (i, &ident) in path.iter().enumerate() { + for (i, &ident) in path.segments.iter().enumerate() { debug!("resolve_path ident {} {:?}", i, ident); - let is_last = i == path.len() - 1; + let is_last = i == path.segments.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; let name = ident.name; @@ -3247,7 +3277,7 @@ impl<'a> Resolver<'a> { if (i == 0 && name == keywords::CrateRoot.name()) || (i == 0 && name == keywords::Crate.name()) || (i == 1 && name == keywords::Crate.name() && - path[0].name == keywords::CrateRoot.name()) { + path.segments[0].name == keywords::CrateRoot.name()) { // `::a::b` or `::crate::a::b` module = Some(self.resolve_crate_root(ident.span.ctxt(), false)); continue @@ -3256,7 +3286,7 @@ impl<'a> Resolver<'a> { module = Some(self.resolve_crate_root(ident.span.ctxt(), true)); continue } else if i == 1 && !token::is_path_segment_keyword(ident) { - let prev_name = path[0].name; + let prev_name = path.segments[0].name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && // Note: When this feature stabilizes, this should @@ -3282,14 +3312,14 @@ impl<'a> Resolver<'a> { name == keywords::Extern.name() && i != 0 || // we allow crate::foo and ::crate::foo but nothing else name == keywords::Crate.name() && i > 1 && - path[0].name != keywords::CrateRoot.name() || - name == keywords::Crate.name() && path.len() == 1 { + path.segments[0].name != keywords::CrateRoot.name() || + name == keywords::Crate.name() && path.segments.len() == 1 { let name_str = if name == keywords::CrateRoot.name() { format!("crate root") } else { format!("`{}`", name) }; - let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() { + let msg = if i == 1 && path.segments[0].name == keywords::CrateRoot.name() { format!("global paths cannot start with {}", name_str) } else { format!("{} in paths can only be used in start position", name_str) @@ -3308,7 +3338,7 @@ impl<'a> Resolver<'a> { Some(LexicalScopeBinding::Def(def)) if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => { return PathResult::NonModule(PathResolution::with_unresolved_segments( - def, path.len() - 1 + def, path.segments.len() - 1 )); } _ => Err(if record_used { Determined } else { Undetermined }), @@ -3325,7 +3355,7 @@ impl<'a> Resolver<'a> { return PathResult::NonModule(err_path_resolution()); } else if opt_ns.is_some() && (is_last || maybe_assoc) { return PathResult::NonModule(PathResolution::with_unresolved_segments( - def, path.len() - i - 1 + def, path.segments.len() - i - 1 )); } else { return PathResult::Failed(ident.span, @@ -3333,10 +3363,10 @@ impl<'a> Resolver<'a> { is_last); } - if let Some(id) = node_id { + if let Some(id) = path.source { if i == 1 && self.session.features_untracked().crate_in_paths && !self.session.rust_2018() { - let prev_name = path[0].name; + let prev_name = path.segments[0].name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() { let mut is_crate = false; @@ -3365,7 +3395,7 @@ impl<'a> Resolver<'a> { if let Some(module) = module { if opt_ns.is_some() && !module.is_normal() { return PathResult::NonModule(PathResolution::with_unresolved_segments( - module.def().unwrap(), path.len() - i + module.def().unwrap(), path.segments.len() - i )); } } @@ -3384,7 +3414,7 @@ impl<'a> Resolver<'a> { } else if i == 0 { format!("Use of undeclared type or module `{}`", ident) } else { - format!("Could not find `{}` in `{}`", ident, path[i - 1]) + format!("Could not find `{}` in `{}`", ident, path.segments[i - 1]) }; return PathResult::Failed(ident.span, msg, is_last); } @@ -3604,9 +3634,12 @@ impl<'a> Resolver<'a> { } } 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, None) { + let mod_path = ResolvePath { + segments: &path[..path.len() - 1], + source: None, + }; + if let PathResult::Module(module) = self.resolve_path(&mod_path, Some(TypeNS), + false, span) { add_module_candidates(module, &mut names); } } @@ -4024,7 +4057,12 @@ impl<'a> Resolver<'a> { let segments = path.make_root().iter().chain(path.segments.iter()) .map(|seg| seg.ident) .collect::>(); - let def = self.smart_resolve_path_fragment(id, None, &segments, path.span, + let span = path.span; + let path = ResolvePath { + segments: &segments, + source: None, + }; + let def = self.smart_resolve_path_fragment(id, None, &path, span, PathSource::Visibility).base_def(); if def == Def::Err { ty::Visibility::Public @@ -4033,8 +4071,8 @@ impl<'a> Resolver<'a> { if self.is_accessible(vis) { vis } else { - self.session.span_err(path.span, "visibilities can only be restricted \ - to ancestor modules"); + self.session.span_err(span, "visibilities can only be restricted \ + to ancestor modules"); ty::Visibility::Public } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index e72e02933e5e5..2e03ced679121 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {AmbiguityError, Resolver, ResolutionError, resolve_error}; +use {ResolvePath, AmbiguityError, Resolver, ResolutionError, resolve_error}; use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; use Namespace::{self, MacroNS}; use build_reduced_graph::BuildReducedGraphVisitor; @@ -425,12 +425,12 @@ impl<'a> Resolver<'a> { kind: MacroKind, force: bool) -> Result { let ast::Path { ref segments, span } = *path; - let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); + let segments: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); let invocation = self.invocations[&scope]; let module = invocation.module.get(); self.current_module = if module.is_trait() { module.parent.unwrap() } else { module }; - if path.len() > 1 { + if segments.len() > 1 { if !self.use_extern_macros && self.gated_errors.insert(span) { let msg = "non-ident macro paths are experimental"; let feature = "use_extern_macros"; @@ -439,36 +439,44 @@ impl<'a> Resolver<'a> { return Err(Determinacy::Determined); } - let def = match self.resolve_path(&path, Some(MacroNS), false, span, None) { - PathResult::NonModule(path_res) => match path_res.base_def() { - Def::Err => Err(Determinacy::Determined), - def @ _ => { - if path_res.unresolved_segments() > 0 { - self.found_unresolved_macro = true; - self.session.span_err(span, "fail to resolve non-ident macro path"); - Err(Determinacy::Determined) - } else { - Ok(def) + let def = { + let path = ResolvePath { + segments: &segments, + source: None, + }; + + match self.resolve_path(&path, Some(MacroNS), false, span) { + PathResult::NonModule(path_res) => match path_res.base_def() { + Def::Err => Err(Determinacy::Determined), + def @ _ => { + if path_res.unresolved_segments() > 0 { + self.found_unresolved_macro = true; + self.session.span_err(span, "fail to resolve non-ident macro path"); + Err(Determinacy::Determined) + } else { + Ok(def) + } } - } - }, - PathResult::Module(..) => unreachable!(), - PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), - _ => { - self.found_unresolved_macro = true; - Err(Determinacy::Determined) - }, + }, + PathResult::Module(..) => unreachable!(), + PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), + _ => { + self.found_unresolved_macro = true; + Err(Determinacy::Determined) + }, + } }; self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() - .push((path.into_boxed_slice(), span)); + .push((segments.into_boxed_slice(), span)); return def; } - let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false); + let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, + segments[0], false); let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { Ok(Def::Macro(binding.def_id, MacroKind::Bang)) } else { - match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) { + match self.resolve_lexical_macro_path_segment(segments[0], MacroNS, false, span) { Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { @@ -479,7 +487,7 @@ impl<'a> Resolver<'a> { }; self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() - .push((scope, path[0], span, kind)); + .push((scope, segments[0], span, kind)); result } @@ -617,7 +625,11 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(&path, Some(MacroNS), true, span, None) { + let path = ResolvePath { + segments: &path, + source: None, + }; + match self.resolve_path(&path, Some(MacroNS), true, span) { PathResult::NonModule(_) => {}, PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e2a7f5668d251..6c467f11b90a0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,7 +10,7 @@ use self::ImportDirectiveSubclass::*; -use {AmbiguityError, Module, PerNS}; +use {ResolvePath, AmbiguityError, Module, PerNS}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use Resolver; @@ -535,8 +535,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::Invisible); - let result = self.resolve_path(&directive.module_path[..], None, false, - directive.span, Some(directive.id)); + let path = ResolvePath { + segments: &directive.module_path[..], + source: Some(directive.id), + }; + let result = self.resolve_path(&path, None, false, directive.span); directive.vis.set(vis); match result { @@ -664,7 +667,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - let module_result = self.resolve_path(&module_path, None, true, span, Some(directive.id)); + let module_path = ResolvePath { + segments: &module_path, + source: Some(directive.id), + }; + let module_result = self.resolve_path(&module_path, None, true, span); let module = match module_result { PathResult::Module(module) => module, PathResult::Failed(span, msg, false) => { @@ -672,17 +679,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return None; } PathResult::Failed(span, msg, true) => { - let (mut self_path, mut self_result) = (module_path.clone(), None); + let (mut self_path, mut self_result) = (module_path.segments.to_vec(), None); let is_special = |ident| token::is_path_segment_keyword(ident) && ident.name != keywords::CrateRoot.name(); if !self_path.is_empty() && !is_special(self_path[0]) && !(self_path.len() > 1 && is_special(self_path[1])) { self_path[0].name = keywords::SelfValue.name(); - self_result = Some(self.resolve_path(&self_path, None, false, - span, None)); + let self_path = ResolvePath { + segments: &self_path, + source: None, + }; + self_result = Some(self.resolve_path(&self_path, None, false, span)); } return if let Some(PathResult::Module(..)) = self_result { - Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..])))) + Some((span, format!("Did you mean `{}`?", + names_to_string(&self_path[..])))) } else { Some((span, msg)) };