diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index cb05f7b44c3b9..8bce2b079bdc4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -142,8 +142,13 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - /// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool); + /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc. + fn resolve_hir_path( + &mut self, + path: &ast::Path, + args: Option>, + is_value: bool, + ) -> hir::Path; /// Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; @@ -162,7 +167,7 @@ pub trait Resolver { span: Span, crate_root: Option<&str>, components: &[&str], - params: Option>, + args: Option>, is_value: bool, ) -> hir::Path; } @@ -1309,13 +1314,15 @@ impl<'a> LoweringContext<'a> { // does not actually exist in the AST. lctx.items.insert(exist_ty_id.node_id, exist_ty_item); + let def = Def::Existential(DefId::local(exist_ty_def_index)); // `impl Trait` now just becomes `Foo<'a, 'b, ..>` let path = P(hir::Path { span: exist_ty_span, - def: Def::Existential(DefId::local(exist_ty_def_index)), + def, segments: hir_vec![hir::PathSegment { infer_types: false, ident: Ident::new(keywords::Invalid.name(), exist_ty_span), + def: None, args: Some(P(hir::GenericArgs { parenthesized: false, bindings: HirVec::new(), @@ -1792,8 +1799,10 @@ impl<'a> LoweringContext<'a> { } } + let def = self.expect_full_def(segment.id); hir::PathSegment::new( segment.ident, + Some(def), generic_args, infer_types, ) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7ac334d84a9bf..2f725b73ddbfe 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -337,6 +337,7 @@ impl fmt::Display for Path { pub struct PathSegment { /// The identifier portion of this path segment. pub ident: Ident, + pub def: Option, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -357,14 +358,16 @@ impl PathSegment { pub fn from_ident(ident: Ident) -> PathSegment { PathSegment { ident, + def: None, infer_types: true, args: None, } } - pub fn new(ident: Ident, args: GenericArgs, infer_types: bool) -> Self { + pub fn new(ident: Ident, def: Option, args: GenericArgs, infer_types: bool) -> Self { PathSegment { ident, + def, infer_types, args: if args.is_empty() { None diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 2ac195dca82c4..039430aac4933 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -172,6 +172,7 @@ impl_stable_hash_for!(struct hir::Path { impl_stable_hash_for!(struct hir::PathSegment { ident -> (ident.name), + def, infer_types, args }); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 80f6c263e1999..0b9563b3c8aa2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -136,7 +136,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let mut module_path: Vec<_> = prefix.segments.iter() .chain(path.segments.iter()) - .map(|seg| seg.ident) + .map(|seg| (seg.ident, Some(seg.id))) .collect(); debug!("build_reduced_graph_for_use_tree: module_path={:?}", module_path); @@ -172,7 +172,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // ergonomically unacceptable. let emit_uniform_paths_canary = !uniform_paths_canary_emitted && - module_path.get(0).map_or(false, |ident| { + module_path.get(0).map_or(false, |(ident, _)| { !ident.is_path_segment_keyword() }); if emit_uniform_paths_canary { @@ -182,13 +182,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let source = module_path[0]; // Helper closure to emit a canary with the given base path. - let emit = |this: &mut Self, base: Option| { + let emit = |this: &mut Self, base: Option<(Ident, Option)>| { let subclass = SingleImport { target: Ident { name: keywords::Underscore.name().gensymed(), - span: source.span, + span: source.0.span, }, - source, + source: source.0, result: PerNS { type_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Undetermined)), @@ -199,7 +199,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { this.add_import_directive( base.into_iter().collect(), subclass.clone(), - source.span, + source.0.span, id, root_use_tree.span, root_id, @@ -210,15 +210,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> { }; // A single simple `self::x` canary. - emit(self, Some(Ident { + emit(self, Some((Ident { name: keywords::SelfValue.name(), - span: source.span, - })); + span: source.0.span, + }, source.1))); // One special unprefixed canary per block scope around // the import, to detect items unreachable by `self::x`. let orig_current_module = self.current_module; - let mut span = source.span.modern(); + let mut span = source.0.span.modern(); loop { match self.current_module.kind { ModuleKind::Block(..) => emit(self, None), @@ -244,10 +244,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { if nested { // Correctly handle `self` - if source.name == keywords::SelfValue.name() { + if source.0.name == keywords::SelfValue.name() { type_ns_only = true; - let empty_prefix = module_path.last().map_or(true, |ident| { + let empty_prefix = module_path.last().map_or(true, |(ident, _)| { ident.name == keywords::CrateRoot.name() }); if empty_prefix { @@ -263,20 +263,20 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // Replace `use foo::self;` with `use foo;` source = module_path.pop().unwrap(); if rename.is_none() { - ident = source; + ident = source.0; } } } else { // Disallow `self` - if source.name == keywords::SelfValue.name() { + if source.0.name == keywords::SelfValue.name() { resolve_error(self, use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin); } // Disallow `use $crate;` - if source.name == keywords::DollarCrate.name() && module_path.is_empty() { - let crate_root = self.resolve_crate_root(source); + if source.0.name == keywords::DollarCrate.name() && module_path.is_empty() { + let crate_root = self.resolve_crate_root(source.0); let crate_name = match crate_root.kind { ModuleKind::Def(_, name) => name, ModuleKind::Block(..) => unreachable!(), @@ -286,11 +286,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // while the current crate doesn't have a valid `crate_name`. if crate_name != keywords::Invalid.name() { // `crate_name` should not be interpreted as relative. - module_path.push(Ident { + module_path.push((Ident { name: keywords::CrateRoot.name(), - span: source.span, - }); - source.name = crate_name; + span: source.0.span, + }, Some(self.session.next_node_id()))); + source.0.name = crate_name; } if rename.is_none() { ident.name = crate_name; @@ -311,7 +311,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let subclass = SingleImport { target: ident, - source, + source: source.0, result: PerNS { type_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Undetermined)), @@ -349,13 +349,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> { ); } ast::UseTreeKind::Nested(ref items) => { - let prefix = ast::Path { - segments: module_path.into_iter() - .map(|ident| ast::PathSegment::from_ident(ident)) - .collect(), - span: path.span, - }; - // Ensure there is at most one `self` in the list let self_spans = items.iter().filter_map(|&(ref use_tree, _)| { if let ast::UseTreeKind::Simple(..) = use_tree.kind { @@ -379,6 +372,17 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } for &(ref tree, id) in items { + let prefix = ast::Path { + segments: module_path.iter() + .map(|ident| { + let mut seg = ast::PathSegment::from_ident(ident.0); + seg.id = self.session.next_node_id(); + seg + }) + .collect(), + span: path.span, + }; + self.build_reduced_graph_for_use_tree( root_use_tree, root_id, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 78c518aea961d..5535882d2db4d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1497,8 +1497,13 @@ impl<'a, 'b: 'a, 'cl: 'b> ty::DefIdTree for &'a Resolver<'b, 'cl> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> { - fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { - self.resolve_hir_path_cb(path, is_value, + fn resolve_hir_path( + &mut self, + path: &ast::Path, + args: Option>, + is_value: bool, + ) -> hir::Path { + self.resolve_hir_path_cb(path, args, is_value, |resolver, span, error| resolve_error(resolver, span, error)) } @@ -1510,30 +1515,20 @@ impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> { args: Option>, is_value: bool ) -> hir::Path { - let mut segments = iter::once(keywords::CrateRoot.ident()) + let segments = iter::once(keywords::CrateRoot.ident()) .chain( crate_root.into_iter() .chain(components.iter().cloned()) .map(Ident::from_str) - ).map(hir::PathSegment::from_ident).collect::>(); + ).map(|i| self.new_ast_path_segment(i)).collect::>(); - if let Some(args) = args { - let ident = segments.last().unwrap().ident; - *segments.last_mut().unwrap() = hir::PathSegment { - ident, - args: Some(args), - infer_types: true, - }; - } - let mut path = hir::Path { + let path = ast::Path { span, - def: Def::Err, - segments: segments.into(), + segments, }; - self.resolve_hir_path(&mut path, is_value); - path + self.resolve_hir_path(&path, args, is_value) } fn get_resolution(&mut self, id: NodeId) -> Option { @@ -1559,23 +1554,27 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { use std::iter; let mut errored = false; - let mut path = if path_str.starts_with("::") { - hir::Path { + let path = if path_str.starts_with("::") { + ast::Path { span, - def: Def::Err, - segments: iter::once(keywords::CrateRoot.ident()).chain({ - path_str.split("::").skip(1).map(Ident::from_str) - }).map(hir::PathSegment::from_ident).collect(), + segments: iter::once(keywords::CrateRoot.ident()) + .chain({ + path_str.split("::").skip(1).map(Ident::from_str) + }) + .map(|i| self.new_ast_path_segment(i)) + .collect(), } } else { - hir::Path { + ast::Path { span, - def: Def::Err, - segments: path_str.split("::").map(Ident::from_str) - .map(hir::PathSegment::from_ident).collect(), + segments: path_str + .split("::") + .map(Ident::from_str) + .map(|i| self.new_ast_path_segment(i)) + .collect(), } }; - self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true); + let path = self.resolve_hir_path_cb(&path, None, is_value, |_, _, _| errored = true); if errored || path.def == Def::Err { Err(()) } else { @@ -1584,38 +1583,67 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } /// resolve_hir_path, but takes a callback in case there was an error - fn resolve_hir_path_cb(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F) + fn resolve_hir_path_cb( + &mut self, + path: &ast::Path, + args: Option>, + is_value: bool, + error_callback: F, + ) -> hir::Path where F: for<'c, 'b> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>) { let namespace = if is_value { ValueNS } else { TypeNS }; - let hir::Path { ref segments, span, ref mut def } = *path; - let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); + let span = path.span; + let segments = &path.segments; + let path: Vec<_> = segments.iter().map(|seg| (seg.ident, Some(seg.id))).collect(); // FIXME (Manishearth): Intra doc links won't get warned of epoch changes - match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) { + let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => - *def = module.def().unwrap(), + module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => - *def = path_res.base_def(), - PathResult::NonModule(..) => match self.resolve_path( - None, - &path, - None, - true, - span, - CrateLint::No, - ) { - PathResult::Failed(span, msg, _) => { - error_callback(self, span, ResolutionError::FailedToResolve(&msg)); + path_res.base_def(), + PathResult::NonModule(..) => { + match self.resolve_path( + None, + &path, + None, + true, + span, + CrateLint::No, + ) { + PathResult::Failed(span, msg, _) => { + error_callback(self, span, ResolutionError::FailedToResolve(&msg)); + } + _ => {} } - _ => {} - }, + Def::Err + } PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); + Def::Err } + }; + + let mut segments: Vec<_> = segments.iter().map(|seg| { + let mut hir_seg = hir::PathSegment::from_ident(seg.ident); + hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def())); + hir_seg + }).collect(); + segments.last_mut().unwrap().args = args; + hir::Path { + span, + def, + segments: segments.into(), } } + + fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment { + let mut seg = ast::PathSegment::from_ident(ident); + seg.id = self.session.next_node_id(); + seg + } } impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { @@ -2432,7 +2460,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { let path: Vec<_> = trait_ref.path.segments.iter() - .map(|seg| seg.ident) + .map(|seg| (seg.ident, Some(seg.id))) .collect(); let def = self.smart_resolve_path_fragment( trait_ref.ref_id, @@ -2915,7 +2943,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { crate_lint: CrateLint ) -> PathResolution { let segments = &path.segments.iter() - .map(|seg| seg.ident) + .map(|seg| (seg.ident, Some(seg.id))) .collect::>(); self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint) } @@ -2923,12 +2951,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn smart_resolve_path_fragment(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[(Ident, Option)], span: Span, source: PathSource, crate_lint: CrateLint) -> PathResolution { - let ident_span = path.last().map_or(span, |ident| ident.span); + let ident_span = path.last().map_or(span, |ident| ident.0.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 }; @@ -2937,18 +2965,18 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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_and_ids_to_string(path); 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 item_str = path[path.len() - 1].0; + let item_span = path[path.len() - 1].0.span; let (mod_prefix, mod_str) = if path.len() == 1 { (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { + } else if path.len() == 2 && path[0].0.name == keywords::CrateRoot.name() { (String::new(), "the crate root".to_string()) } else { let mod_path = &path[..path.len() - 1]; @@ -2958,7 +2986,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { module.def(), _ => None, }.map_or(String::new(), |def| format!("{} ", def.kind_name())); - (mod_prefix, format!("`{}`", names_to_string(mod_path))) + (mod_prefix, format!("`{}`", names_and_ids_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), format!("not found in {}", mod_str), @@ -2988,7 +3016,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } // Try to lookup the name in more relaxed fashion for better error reporting. - let ident = *path.last().unwrap(); + let ident = path.last().unwrap().0; 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 = @@ -3011,7 +3039,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } if path.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[0].0.span, span); match candidate { AssocSuggestion::Field => { err.span_suggestion(span, "try", @@ -3202,7 +3230,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // 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.last().unwrap().0; let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } @@ -3269,7 +3297,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn resolve_qpath_anywhere(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[(Ident, Option)], primary_ns: Namespace, span: Span, defer_to_typeck: bool, @@ -3290,10 +3318,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { }; } } - let is_global = self.macro_prelude.get(&path[0].name).cloned() + let is_global = self.macro_prelude.get(&path[0].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[0].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)) @@ -3306,7 +3334,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn resolve_qpath(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[(Ident, Option)], ns: Namespace, span: Span, global_by_default: bool, @@ -3396,8 +3424,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types - .contains_key(&path[0].name) => { - let prim = self.primitive_type_table.primitive_types[&path[0].name]; + .contains_key(&path[0].0.name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].0.name]; PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => @@ -3412,8 +3440,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { }; if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && - path[0].name != keywords::DollarCrate.name() { + path[0].0.name != keywords::CrateRoot.name() && + path[0].0.name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path( None, @@ -3441,7 +3469,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn resolve_path( &mut self, base_module: Option>, - path: &[Ident], + path: &[(Ident, Option)], opt_ns: Option, // `None` indicates a module path record_used: bool, path_span: Span, @@ -3461,7 +3489,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { crate_lint, ); - for (i, &ident) in path.iter().enumerate() { + for (i, &(ident, id)) in path.iter().enumerate() { debug!("resolve_path ident {} {:?}", i, ident); let is_last = i == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; @@ -3523,7 +3551,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } else { format!("`{}`", name) }; - let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() { + let msg = if i == 1 && path[0].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) @@ -3563,6 +3591,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def); if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); + if !is_last && record_used { + if let Some(id) = id { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + self.record_def(id, PathResolution::new(def)); + } + } } else if def == Def::ToolMod && i + 1 != path.len() { let def = Def::NonMacroAttr(NonMacroAttrKind::Tool); return PathResult::NonModule(PathResolution::new(def)); @@ -3612,7 +3646,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } 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[i - 1].0) }; return PathResult::Failed(ident.span, msg, is_last); } @@ -3630,7 +3664,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn lint_if_path_starts_with_module( &self, crate_lint: CrateLint, - path: &[Ident], + path: &[(Ident, Option)], path_span: Span, second_binding: Option<&NameBinding>, ) { @@ -3653,7 +3687,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { }; let first_name = match path.get(0) { - Some(ident) => ident.name, + Some(ident) => ident.0.name, None => return, }; @@ -3665,7 +3699,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { match path.get(1) { // If this import looks like `crate::...` it's already good - Some(ident) if ident.name == keywords::Crate.name() => return, + Some((ident, _)) if ident.name == keywords::Crate.name() => return, // Otherwise go below to see if it's an extern crate Some(_) => {} // If the path has length one (and it's `CrateRoot` most likely) @@ -3858,7 +3892,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } fn lookup_typo_candidate(&mut self, - path: &[Ident], + path: &[(Ident, Option)], ns: Namespace, filter_fn: FilterFn, span: Span) @@ -3922,7 +3956,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } } - let name = path[path.len() - 1].name; + let name = path[path.len() - 1].0.name; // Make sure error reporting is deterministic. names.sort_by_cached_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { @@ -4443,7 +4477,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { ast::VisibilityKind::Restricted { ref path, id, .. } => { // Visibilities are resolved as global by default, add starting root segment. let segments = path.make_root().iter().chain(path.segments.iter()) - .map(|seg| seg.ident) + .map(|seg| (seg.ident, Some(seg.id))) .collect::>(); let def = self.smart_resolve_path_fragment( id, @@ -4681,12 +4715,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } } -fn is_self_type(path: &[Ident], namespace: Namespace) -> bool { - namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name() +fn is_self_type(path: &[(Ident, Option)], namespace: Namespace) -> bool { + namespace == TypeNS && path.len() == 1 && path[0].0.name == keywords::SelfType.name() } -fn is_self_value(path: &[Ident], namespace: Namespace) -> bool { - namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name() +fn is_self_value(path: &[(Ident, Option)], namespace: Namespace) -> bool { + namespace == ValueNS && path.len() == 1 && path[0].0.name == keywords::SelfValue.name() } fn names_to_string(idents: &[Ident]) -> String { @@ -4702,6 +4736,12 @@ fn names_to_string(idents: &[Ident]) -> String { result } +fn names_and_ids_to_string(segments: &[(Ident, Option)]) -> String { + names_to_string(&segments.iter() + .map(|seg| seg.0) + .collect::>()) +} + fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter() .map(|seg| seg.ident) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 879b4ea3fe579..6c230a477eff8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -423,16 +423,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> { derives_in_scope: &[ast::Path], force: bool) -> Result { let ast::Path { ref segments, span } = *path; - let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); + let mut path: Vec<_> = segments.iter().map(|seg| (seg.ident, Some(seg.id))).collect(); let invocation = self.invocations[&scope]; let module = invocation.module.get(); self.current_module = if module.is_trait() { module.parent.unwrap() } else { module }; // Possibly apply the macro helper hack if kind == MacroKind::Bang && path.len() == 1 && - path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) { - let root = Ident::new(keywords::DollarCrate.name(), path[0].span); - path.insert(0, root); + path[0].0.span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) { + let root = Ident::new(keywords::DollarCrate.name(), path[0].0.span); + path.insert(0, (root, None)); } if path.len() > 1 { @@ -457,16 +457,24 @@ impl<'a, 'cl> Resolver<'a, 'cl> { Err(Determinacy::Determined) }, }; - self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() - .push((path.into_boxed_slice(), span)); + self.current_module + .nearest_item_scope() + .macro_resolutions + .borrow_mut() + .push((path + .iter() + .map(|(ident, _)| *ident) + .collect::>() + .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, path[0].0, false); let result = if let Some((legacy_binding, _)) = legacy_resolution { Ok(legacy_binding.def()) } else { - match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force, + match self.resolve_lexical_macro_path_segment(path[0].0, MacroNS, false, force, kind == MacroKind::Attr, span) { Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()), Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), @@ -478,7 +486,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { }; self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() - .push((scope, path[0], kind, result.ok())); + .push((scope, path[0].0, kind, result.ok())); if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else { return result; @@ -499,7 +507,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { for derive in derives_in_scope { match self.resolve_macro_path(derive, MacroKind::Derive, scope, &[], force) { Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext { - if inert_attrs.contains(&path[0].name) { + if inert_attrs.contains(&path[0].0.name) { convert_to_derive_helper = ConvertToDeriveHelper::Yes; break } @@ -811,6 +819,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { + let path = path + .iter() + .map(|ident| (*ident, None)) + .collect::)>>(); match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) { PathResult::NonModule(_) => {}, PathResult::Failed(span, msg, _) => { @@ -919,7 +931,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } }; let ident = Ident::new(Symbol::intern(name), span); - self.lookup_typo_candidate(&[ident], MacroNS, is_macro, span) + self.lookup_typo_candidate(&[(ident, None)], MacroNS, is_macro, span) }); if let Some(suggestion) = suggestion { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c60f9293d58e7..f6aeffebf951f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -14,7 +14,7 @@ use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use Resolver; -use {names_to_string, module_to_string}; +use {names_to_string, names_and_ids_to_string, module_to_string}; use {resolve_error, ResolutionError}; use rustc_data_structures::ptr_key::PtrKey; @@ -86,7 +86,7 @@ pub struct ImportDirective<'a> { pub root_span: Span, pub parent: Module<'a>, - pub module_path: Vec, + pub module_path: Vec<(Ident, Option)>, /// The resolution of `module_path`. pub imported_module: Cell>>, pub subclass: ImportDirectiveSubclass<'a>, @@ -382,7 +382,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { // Add an import directive to the current module. pub fn add_import_directive(&mut self, - module_path: Vec, + module_path: Vec<(Ident, Option)>, subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, @@ -653,7 +653,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let has_explicit_self = import.module_path.len() > 0 && - import.module_path[0].name == keywords::SelfValue.name(); + import.module_path[0].0.name == keywords::SelfValue.name(); let (prev_name, canary_results) = uniform_paths_canaries.entry((import.span, import.id)) @@ -690,9 +690,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(import); if !seen_spans.contains(&span) { - let path = import_path_to_string(&import.module_path[..], - &import.subclass, - span); + let path = import_path_to_string( + &import.module_path.iter().map(|(ident, _)| *ident).collect::>(), + &import.subclass, + span, + ); let error = ResolutionError::UnresolvedImport(Some((span, &path, &err))); resolve_error(self.resolver, span, error); seen_spans.insert(span); @@ -779,7 +781,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { /// If successful, the resolved bindings are written into the module. fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool { debug!("(resolving import for module) resolving import `{}::...` in `{}`", - names_to_string(&directive.module_path[..]), + names_and_ids_to_string(&directive.module_path[..]), module_to_string(self.current_module).unwrap_or("???".to_string())); self.current_module = directive.parent; @@ -892,14 +894,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let (mut self_path, mut self_result) = (module_path.clone(), None); let is_special = |ident: Ident| ident.is_path_segment_keyword() && 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(); + if !self_path.is_empty() && !is_special(self_path[0].0) && + !(self_path.len() > 1 && is_special(self_path[1].0)) { + self_path[0].0.name = keywords::SelfValue.name(); self_result = Some(self.resolve_path(None, &self_path, None, false, span, CrateLint::No)); } 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_and_ids_to_string(&self_path[..])))) } else { Some((span, msg)) }; @@ -914,7 +917,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = module_path.clone(); - full_path.push(keywords::Invalid.ident()); + full_path.push((keywords::Invalid.ident(), None)); self.lint_if_path_starts_with_module( directive.crate_lint(), &full_path, @@ -1068,7 +1071,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = module_path.clone(); - full_path.push(ident); + full_path.push((ident, None)); self.per_ns(|this, ns| { if let Ok(binding) = result[ns].get() { this.lint_if_path_starts_with_module( @@ -1203,7 +1206,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let resolutions = imported_module.parent.expect("parent should exist") .resolutions.borrow(); let enum_path_segment_index = directive.module_path.len() - 1; - let enum_ident = directive.module_path[enum_path_segment_index]; + let enum_ident = directive.module_path[enum_path_segment_index].0; let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) .expect("resolution should exist"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b6084bcf34307..9e4d3c91d07cf 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -121,6 +121,8 @@ pub struct PathSegment { /// The identifier portion of this path segment. pub ident: Ident, + pub id: NodeId, + /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. /// `None` means that no parameter list is supplied (`Path`), @@ -132,10 +134,14 @@ pub struct PathSegment { impl PathSegment { pub fn from_ident(ident: Ident) -> Self { - PathSegment { ident, args: None } + PathSegment { ident, id: DUMMY_NODE_ID, args: None } } pub fn crate_root(span: Span) -> Self { - PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span)) + PathSegment { + ident: Ident::new(keywords::CrateRoot.name(), span), + id: DUMMY_NODE_ID, + args: None, + } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index b1bed9602f362..dac857b166fbe 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -329,7 +329,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } else { None }; - segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args }); + segments.push(ast::PathSegment { + ident: last_ident.with_span_pos(span), + id: ast::DUMMY_NODE_ID, + args, + }); let mut path = ast::Path { span, segments }; if global { if let Some(seg) = path.make_root() { @@ -366,7 +370,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } else { None }; - path.segments.push(ast::PathSegment { ident, args }); + path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args }); (ast::QSelf { ty: self_type, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 660056e15e06b..bd9fa6b15211b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -448,8 +448,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment { ident, args }| PathSegment { + segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment { ident: fld.fold_ident(ident), + id: fld.new_id(id), args: args.map(|args| args.map(|args| fld.fold_generic_args(args))), }), span: fld.new_span(span) @@ -1210,6 +1211,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::MethodCall( PathSegment { ident: folder.fold_ident(seg.ident), + id: folder.new_id(seg.id), args: seg.args.map(|args| { args.map(|args| folder.fold_generic_args(args)) }), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1695d3a8f96b0..7bef48c6d3228 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2082,10 +2082,10 @@ impl<'a> Parser<'a> { ParenthesisedArgs { inputs, output, span }.into() }; - PathSegment { ident, args } + PathSegment { ident, args, id: ast::DUMMY_NODE_ID } } else { // Generic arguments are not found. - PathSegment::from_ident(ident) + PathSegment::from_ident(ident,) }) }