From f10f50b42639718b2580d10802f05f2b6ff209d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Dec 2016 03:51:11 +0000 Subject: [PATCH 1/2] Refactor how global paths are represented (for both ast and hir). --- src/librustc/hir/lowering.rs | 46 +++++---- src/librustc/hir/mod.rs | 9 +- src/librustc/hir/print.rs | 28 +++--- src/librustc/infer/error_reporting.rs | 1 - src/librustc_const_eval/_match.rs | 1 - .../calculate_svh/svh_visitor.rs | 2 - src/librustc_lint/bad_style.rs | 2 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 31 +++--- src/librustc_resolve/lib.rs | 96 ++++++++----------- src/librustc_resolve/macros.rs | 28 +++--- src/librustc_resolve/resolve_imports.rs | 21 ++-- src/librustc_save_analysis/dump_visitor.rs | 49 ++++------ src/librustdoc/clean/mod.rs | 27 ++---- src/libsyntax/ast.rs | 27 +++++- src/libsyntax/ext/build.rs | 8 +- src/libsyntax/ext/placeholders.rs | 2 +- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/mod.rs | 10 +- src/libsyntax/parse/parser.rs | 16 ++-- src/libsyntax/print/pprust.rs | 67 +++++++------ src/libsyntax/std_inject.rs | 3 +- src/libsyntax/symbol.rs | 3 + src/libsyntax/test.rs | 1 - src/libsyntax_ext/concat_idents.rs | 1 - src/libsyntax_ext/deriving/generic/mod.rs | 11 +-- .../resolve-primitive-fallback.rs | 2 +- 27 files changed, 242 insertions(+), 257 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e8c3492705a3f..1cf5e35a0957f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -81,7 +81,7 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc. + // 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); // Obtain the resolution for a node id @@ -337,7 +337,6 @@ impl<'a> LoweringContext<'a> { let proj_start = p.segments.len() - resolution.depth; let path = P(hir::Path { - global: p.global, def: resolution.base_def, segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| { let param_mode = match (qself_position, param_mode) { @@ -404,12 +403,17 @@ impl<'a> LoweringContext<'a> { id: NodeId, p: &Path, name: Option, - param_mode: ParamMode) + param_mode: ParamMode, + defaults_to_global: bool) -> hir::Path { + let mut segments = p.segments.iter(); + if defaults_to_global && p.is_global() { + segments.next(); + } + hir::Path { - global: p.global, def: self.expect_full_def(id), - segments: p.segments.iter().map(|segment| { + segments: segments.map(|segment| { self.lower_path_segment(segment, param_mode) }).chain(name.map(|name| { hir::PathSegment { @@ -424,9 +428,10 @@ impl<'a> LoweringContext<'a> { fn lower_path(&mut self, id: NodeId, p: &Path, - param_mode: ParamMode) + param_mode: ParamMode, + defaults_to_global: bool) -> hir::Path { - self.lower_path_extra(id, p, None, param_mode) + self.lower_path_extra(id, p, None, param_mode, defaults_to_global) } fn lower_path_segment(&mut self, @@ -602,8 +607,8 @@ impl<'a> LoweringContext<'a> { // Check if the where clause type is a plain type parameter. match bound_pred.bounded_ty.node { TyKind::Path(None, ref path) - if !path.global && path.segments.len() == 1 && - bound_pred.bound_lifetimes.is_empty() => { + if path.segments.len() == 1 && + bound_pred.bound_lifetimes.is_empty() => { if let Some(Def::TyParam(def_id)) = self.resolver.get_resolution(bound_pred.bounded_ty.id) .map(|d| d.base_def) { @@ -677,7 +682,7 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: self.lower_path(id, path, ParamMode::Explicit), + path: self.lower_path(id, path, ParamMode::Explicit, false), ty: self.lower_ty(ty), span: span, }) @@ -707,7 +712,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { hir::TraitRef { - path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit), + path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false), ref_id: p.ref_id, } } @@ -800,7 +805,7 @@ impl<'a> LoweringContext<'a> { }; let mut path = self.lower_path_extra(import.id, path, suffix, - ParamMode::Explicit); + ParamMode::Explicit, true); path.span = span; self.items.insert(import.id, hir::Item { id: import.id, @@ -814,7 +819,7 @@ impl<'a> LoweringContext<'a> { path } }; - let path = P(self.lower_path(id, path, ParamMode::Explicit)); + let path = P(self.lower_path(id, path, ParamMode::Explicit, true)); let kind = match view_path.node { ViewPathSimple(ident, _) => { *name = ident.name; @@ -1135,7 +1140,6 @@ impl<'a> LoweringContext<'a> { Some(def) => { hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path { span: pth1.span, - global: false, def: def, segments: hir_vec![ hir::PathSegment::from_name(pth1.node.name) @@ -1878,7 +1882,7 @@ impl<'a> LoweringContext<'a> { Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { - path: P(self.lower_path(id, path, ParamMode::Explicit)), + path: P(self.lower_path(id, path, ParamMode::Explicit, true)), id: id } } @@ -1971,7 +1975,6 @@ impl<'a> LoweringContext<'a> { let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path { span: span, - global: false, def: def, segments: hir_vec![hir::PathSegment::from_name(id)], }))); @@ -2139,17 +2142,12 @@ impl<'a> LoweringContext<'a> { /// `fld.cx.use_std`, and `::core::b::c::d` otherwise. /// The path is also resolved according to `is_value`. fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path { - let idents = self.crate_root.iter().chain(components); - - let segments: Vec<_> = idents.map(|name| { - hir::PathSegment::from_name(Symbol::intern(name)) - }).collect(); - let mut path = hir::Path { span: span, - global: true, def: Def::Err, - segments: segments.into(), + segments: iter::once(keywords::CrateRoot.name()).chain({ + self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern) + }).map(hir::PathSegment::from_name).collect(), }; self.resolver.resolve_hir_path(&mut path, is_value); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f52ee35e17573..a0039f612b985 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -105,15 +105,18 @@ pub struct LifetimeDef { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Path { pub span: Span, - /// A `::foo` path, is relative to the crate root rather than current - /// module (like paths in an import). - pub global: bool, /// The definition that the path resolved to. pub def: Def, /// The segments in the path: the things separated by `::`. pub segments: HirVec, } +impl Path { + pub fn is_global(&self) -> bool { + !self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name() + } +} + impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "path({})", print::path_to_string(self)) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 74920b1328076..de4047df81c5d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1643,17 +1643,14 @@ impl<'a> State<'a> { -> io::Result<()> { self.maybe_print_comment(path.span.lo)?; - let mut first = !path.global; - for segment in &path.segments { - if first { - first = false - } else { + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 { word(&mut self.s, "::")? } - - self.print_name(segment.name)?; - - self.print_path_parameters(&segment.parameters, colons_before_params)?; + if segment.name != keywords::CrateRoot.name() { + self.print_name(segment.name)?; + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } } Ok(()) @@ -1673,15 +1670,14 @@ impl<'a> State<'a> { space(&mut self.s)?; self.word_space("as")?; - let mut first = !path.global; - for segment in &path.segments[..path.segments.len() - 1] { - if first { - first = false - } else { + for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() { + if i > 0 { word(&mut self.s, "::")? } - self.print_name(segment.name)?; - self.print_path_parameters(&segment.parameters, colons_before_params)?; + if segment.name != keywords::CrateRoot.name() { + self.print_name(segment.name)?; + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } } word(&mut self.s, ">")?; diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 90d752ae6ee29..9d48fbca53edd 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1620,7 +1620,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { new_segs.push(new_seg); hir::Path { span: path.span, - global: path.global, def: path.def, segments: new_segs.into() } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 23771f4bae3dc..ebe1034901104 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -324,7 +324,6 @@ impl Witness { let v = ctor.variant_for_adt(adt); let qpath = hir::QPath::Resolved(None, P(hir::Path { span: DUMMY_SP, - global: false, def: Def::Err, segments: vec![hir::PathSegment::from_name(v.name)].into(), })); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index ec44e19df10c9..bd865d10efcaf 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -189,7 +189,6 @@ enum SawAbiComponent<'a> { SawStructField, SawVariant, SawQPath, - SawPath(bool), SawPathSegment, SawPathParameters, SawBlock, @@ -678,7 +677,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); - SawPath(path.global).hash(self.st); hash_span!(self, path.span); visit::walk_path(self, path) } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 2aa74407afc5b..1d384741d9660 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -382,7 +382,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { + if path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if let Def::Const(..) = path.def { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bc150b847786f..52bdd014933b8 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -154,8 +154,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_path(&mut self, path: &'a Path, id: NodeId) { - if path.global && path.segments.len() > 0 { - let ident = path.segments[0].identifier; + if path.segments.len() >= 2 && path.is_global() { + let ident = path.segments[1].identifier; if token::Ident(ident).is_path_segment_keyword() { self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, id, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index cd2a276797914..09f438953ecd2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -40,6 +40,7 @@ use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; +use syntax::parse::token; use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; @@ -112,7 +113,7 @@ impl<'a> Resolver<'a> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - let module_path: Vec<_> = match view_path.node { + let mut module_path: Vec<_> = match view_path.node { ViewPathSimple(_, ref full_path) => { full_path.segments .split_last() @@ -132,6 +133,12 @@ impl<'a> Resolver<'a> { } }; + // This can be removed once warning cycle #36888 is complete. + if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() && + token::Ident(module_path[1]).is_path_segment_keyword() { + module_path.remove(0); + } + // Build up the import directives. let is_prelude = attr::contains_name(&item.attrs, "prelude_import"); @@ -193,18 +200,16 @@ impl<'a> Resolver<'a> { let rename = node.rename.unwrap_or(node.name); (module_path.clone(), node.name, rename) } else { - let ident = match module_path.last() { - Some(&ident) => ident, - None => { - resolve_error( - self, - source_item.span, - ResolutionError:: - SelfImportOnlyInImportListWithNonEmptyPrefix - ); - continue; - } - }; + let ident = *module_path.last().unwrap(); + if ident.name == keywords::CrateRoot.name() { + resolve_error( + self, + source_item.span, + ResolutionError:: + SelfImportOnlyInImportListWithNonEmptyPrefix + ); + continue; + } let module_path = module_path.split_last().unwrap().1; let rename = node.rename.unwrap_or(ident); (module_path.to_vec(), ident, rename) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f73227681c5e1..7f91576f6d68f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -578,9 +578,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_poly_trait_ref(&mut self, tref: &'tcx ast::PolyTraitRef, m: &'tcx ast::TraitBoundModifier) { - let ast::Path { ref segments, span, global } = tref.trait_ref.path; + let ast::Path { ref segments, span } = tref.trait_ref.path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let def = self.resolve_trait_reference(&path, global, None, span); + let def = self.resolve_trait_reference(&path, None, span); self.record_def(tref.trait_ref.ref_id, def); visit::walk_poly_trait_ref(self, tref, m); } @@ -753,13 +753,6 @@ impl<'a> LexicalScopeBinding<'a> { } } -#[derive(Copy, Clone, PartialEq)] -enum PathScope { - Global, - Lexical, - Import, -} - #[derive(Clone)] enum PathResult<'a> { Module(Module<'a>), @@ -783,7 +776,7 @@ pub struct ModuleData<'a> { resolutions: RefCell>>>, legacy_macro_resolutions: RefCell>, - macro_resolutions: RefCell, PathScope, Span)>>, + macro_resolutions: RefCell, Span)>>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -1174,13 +1167,12 @@ impl<'a> ty::NodeIdTree for Resolver<'a> { impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { let namespace = if is_value { ValueNS } else { TypeNS }; - let hir::Path { ref segments, span, global, ref mut def } = *path; + let hir::Path { ref segments, span, ref mut def } = *path; let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - match self.resolve_path(&path, scope, Some(namespace), Some(span)) { + match self.resolve_path(&path, Some(namespace), Some(span)) { PathResult::Module(module) => *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.depth == 0 => *def = path_res.base_def, - PathResult::NonModule(..) => match self.resolve_path(&path, scope, None, Some(span)) { + PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) { PathResult::Failed(msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } @@ -1601,17 +1593,16 @@ impl<'a> Resolver<'a> { prefix.segments.iter().map(|seg| seg.identifier).collect(); // Resolve prefix of an import with empty braces (issue #28388) if items.is_empty() && !prefix.segments.is_empty() { - let (scope, span) = (PathScope::Import, prefix.span); + let span = prefix.span; // FIXME(#38012) This should be a module path, not anything in TypeNS. - let result = - self.resolve_path(&path, scope, Some(TypeNS), Some(span)); + let result = self.resolve_path(&path, Some(TypeNS), Some(span)); let (def, msg) = match result { PathResult::Module(module) => (module.def().unwrap(), None), PathResult::NonModule(res) if res.depth == 0 => (res.base_def, None), PathResult::NonModule(_) => { // Resolve a module path for better errors - match self.resolve_path(&path, scope, None, Some(span)) { + match self.resolve_path(&path, None, Some(span)) { PathResult::Failed(msg, _) => (Def::Err, Some(msg)), _ => unreachable!(), } @@ -1698,19 +1689,17 @@ impl<'a> Resolver<'a> { fn resolve_trait_reference(&mut self, path: &[Ident], - global: bool, generics: Option<&Generics>, span: Span) -> PathResolution { - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - let def = match self.resolve_path(path, scope, None, Some(span)) { + let def = match self.resolve_path(path, None, Some(span)) { PathResult::Module(module) => Some(module.def().unwrap()), PathResult::NonModule(..) => return err_path_resolution(), PathResult::Failed(msg, false) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); return err_path_resolution(); } - _ => match self.resolve_path(path, scope, Some(TypeNS), None) { + _ => match self.resolve_path(path, Some(TypeNS), None) { PathResult::NonModule(path_resolution) => Some(path_resolution.base_def), _ => None, }, @@ -1766,9 +1755,9 @@ impl<'a> Resolver<'a> { let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - let ast::Path { ref segments, span, global } = trait_ref.path; + let ast::Path { ref segments, span } = trait_ref.path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let path_res = self.resolve_trait_reference(&path, global, generics, span); + let path_res = self.resolve_trait_reference(&path, generics, span); assert!(path_res.depth == 0); self.record_def(trait_ref.ref_id, path_res); if path_res.base_def != Def::Err { @@ -2260,9 +2249,8 @@ impl<'a> Resolver<'a> { path: &Path, ns: Namespace) -> Option { - let ast::Path { ref segments, global, span } = *path; + let ast::Path { ref segments, span } = *path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; if let Some(qself) = maybe_qself { if qself.position == 0 { @@ -2273,10 +2261,10 @@ impl<'a> Resolver<'a> { }); } // Make sure the trait is valid. - self.resolve_trait_reference(&path[..qself.position], global, None, span); + self.resolve_trait_reference(&path[..qself.position], None, span); } - let result = match self.resolve_path(&path, scope, Some(ns), Some(span)) { + let result = match self.resolve_path(&path, Some(ns), Some(span)) { PathResult::NonModule(path_res) => match path_res.base_def { Def::Trait(..) if maybe_qself.is_some() => return None, _ => path_res, @@ -2297,7 +2285,7 @@ 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 scope == PathScope::Lexical && (ns == TypeNS || path.len() > 1) && + if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { PathResolution { base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]), @@ -2317,7 +2305,7 @@ impl<'a> Resolver<'a> { } let unqualified_result = { - match self.resolve_path(&[*path.last().unwrap()], PathScope::Lexical, Some(ns), None) { + match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) { PathResult::NonModule(path_res) => path_res.base_def, PathResult::Module(module) => module.def().unwrap(), _ => return Some(result), @@ -2333,27 +2321,19 @@ impl<'a> Resolver<'a> { fn resolve_path(&mut self, path: &[Ident], - scope: PathScope, opt_ns: Option, // `None` indicates a module path record_used: Option) -> PathResult<'a> { - let (mut module, allow_self) = match scope { - PathScope::Lexical => (None, true), - PathScope::Import => (Some(self.graph_root), true), - PathScope::Global => (Some(self.graph_root), false), - }; - let mut allow_super = allow_self; + let mut module = None; + let mut allow_super = true; for (i, &ident) in path.iter().enumerate() { let is_last = i == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; - if i == 0 && allow_self && ns == TypeNS && ident.name == keywords::SelfValue.name() { + if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() { module = Some(self.module_map[&self.current_module.normal_ancestor_id.unwrap()]); continue - } else if i == 0 && allow_self && ns == TypeNS && ident.name == "$crate" { - module = Some(self.resolve_crate_var(ident.ctxt)); - continue } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() { let current_module = if i == 0 { self.current_module } else { module.unwrap() }; let self_module = self.module_map[¤t_module.normal_ancestor_id.unwrap()]; @@ -2367,6 +2347,14 @@ impl<'a> Resolver<'a> { } allow_super = false; + if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { + module = Some(self.graph_root); + continue + } else if i == 0 && ns == TypeNS && ident.name == "$crate" { + module = Some(self.resolve_crate_var(ident.ctxt)); + continue + } + let binding = if let Some(module) = module { self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { @@ -2430,7 +2418,7 @@ impl<'a> Resolver<'a> { } } - PathResult::Module(module.unwrap()) + PathResult::Module(module.unwrap_or(self.graph_root)) } // Resolve a local definition, potentially adjusting for closures. @@ -2665,10 +2653,8 @@ impl<'a> Resolver<'a> { } else { // Be helpful if the name refers to a struct let path_name = path_names_to_string(path, 0); - let ast::Path { ref segments, global, .. } = *path; - let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - let type_res = match self.resolve_path(&path, scope, Some(TypeNS), None) { + let path: Vec<_> = path.segments.iter().map(|seg| seg.identifier).collect(); + let type_res = match self.resolve_path(&path, Some(TypeNS), None) { PathResult::NonModule(type_res) => Some(type_res), _ => None, }; @@ -2738,7 +2724,7 @@ impl<'a> Resolver<'a> { } else { // we display a help message if this is a module if let PathResult::Module(module) = - self.resolve_path(&path, scope, None, None) { + self.resolve_path(&path, None, None) { def = module.def().unwrap(); context = UnresolvedNameContext::PathIsMod(parent); } @@ -2964,7 +2950,6 @@ impl<'a> Resolver<'a> { segms.push(ident.into()); let path = Path { span: span, - global: false, segments: segms, }; // the entity is accessible in the following cases: @@ -3022,7 +3007,7 @@ impl<'a> Resolver<'a> { let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let mut path_resolution = err_path_resolution(); - let vis = match self.resolve_path(&path, PathScope::Import, None, Some(span)) { + let vis = match self.resolve_path(&path, None, Some(span)) { PathResult::Module(module) => { path_resolution = PathResolution::new(module.def().unwrap()); ty::Visibility::Restricted(module.normal_ancestor_id.unwrap()) @@ -3190,15 +3175,14 @@ impl<'a> Resolver<'a> { } fn names_to_string(names: &[Ident]) -> String { - let mut first = true; let mut result = String::new(); - for ident in names { - if first { - first = false - } else { - result.push_str("::") + for (i, ident) in names.iter().enumerate() { + if i > 0 { + result.push_str("::"); + } + if ident.name != keywords::CrateRoot.name() { + result.push_str(&ident.name.as_str()); } - result.push_str(&ident.name.as_str()); } result } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 204d1127fc48d..ff3c583629371 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -9,7 +9,7 @@ // except according to those terms. use {AmbiguityError, Resolver, ResolutionError, resolve_error}; -use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult}; +use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; use Namespace::{self, MacroNS}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; @@ -30,6 +30,7 @@ use syntax::ext::tt::macro_rules; use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::fold::Folder; use syntax::ptr::P; +use syntax::symbol::keywords; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::Visitor; use syntax_pos::{Span, DUMMY_SP}; @@ -105,15 +106,13 @@ impl<'a> base::Resolver for Resolver<'a> { fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { let ident = path.segments[0].identifier; if ident.name == "$crate" { - path.global = true; + path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); - if module.is_local() { - path.segments.remove(0); - } else { - path.segments[0].identifier = match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name), + if !module.is_local() { + path.segments.insert(1, match module.kind { + ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), _ => unreachable!(), - }; + }) } } path @@ -182,7 +181,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy> { - let ast::Path { ref segments, global, span } = *path; + let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" }; @@ -191,12 +190,11 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let path_scope = if global { PathScope::Global } else { PathScope::Lexical }; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let invocation = self.invocations[&scope]; self.current_module = invocation.module.get(); - if path.len() > 1 || global { + if path.len() > 1 { if !self.use_extern_macros { let msg = "non-ident macro paths are experimental"; let feature = "use_extern_macros"; @@ -204,7 +202,7 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) { + let ext = match self.resolve_path(&path, Some(MacroNS), None) { PathResult::NonModule(path_res) => match path_res.base_def { Def::Err => Err(Determinacy::Determined), def @ _ => Ok(self.get_macro(def)), @@ -214,7 +212,7 @@ impl<'a> base::Resolver for Resolver<'a> { _ => Err(Determinacy::Determined), }; self.current_module.macro_resolutions.borrow_mut() - .push((path.into_boxed_slice(), path_scope, span)); + .push((path.into_boxed_slice(), span)); return ext; } @@ -351,8 +349,8 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; - for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(path, scope, Some(MacroNS), Some(span)) { + for &(ref path, span) in module.macro_resolutions.borrow().iter() { + match self.resolve_path(path, Some(MacroNS), Some(span)) { PathResult::NonModule(_) => {}, PathResult::Failed(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 8bc0bfb41ff75..f62974b30d18e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -12,7 +12,7 @@ use self::ImportDirectiveSubclass::*; use {AmbiguityError, Module, PerNS}; use Namespace::{self, TypeNS, MacroNS}; -use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError}; +use {NameBinding, NameBindingKind, PathResult, PrivacyError}; use Resolver; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; @@ -24,6 +24,7 @@ use rustc::hir::def::*; use syntax::ast::{Ident, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; +use syntax::parse::token; use syntax::symbol::keywords; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -490,7 +491,7 @@ 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::PrivateExternal); - let result = self.resolve_path(&directive.module_path, PathScope::Import, None, None); + let result = self.resolve_path(&directive.module_path, None, None); directive.vis.set(vis); match result { @@ -553,15 +554,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; - let module_result = self.resolve_path(&module_path, PathScope::Import, None, Some(span)); + let module_result = self.resolve_path(&module_path, None, Some(span)); let module = match module_result { PathResult::Module(module) => module, PathResult::Failed(msg, _) => { - let mut path = vec![keywords::SelfValue.ident()]; - path.extend(module_path); - let result = self.resolve_path(&path, PathScope::Import, None, None); - return if let PathResult::Module(..) = result { - Some(format!("Did you mean `self::{}`?", &names_to_string(module_path))) + let (mut self_path, mut self_result) = (module_path.clone(), None); + if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() { + self_path[0].name = keywords::SelfValue.name(); + self_result = Some(self.resolve_path(&self_path, None, None)); + } + return if let Some(PathResult::Module(..)) = self_result { + Some(format!("Did you mean `{}`?", names_to_string(&self_path))) } else { Some(msg) }; @@ -787,6 +790,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String { + let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name(); + let names = if global { &names[1..] } else { names }; if names.is_empty() { import_directive_subclass_to_string(subclass) } else { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index afa78a05a63a8..65372d4dca9a1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -143,19 +143,20 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // a str representation of the entire prefix. fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { let spans = self.span.spans_for_path_segments(path); + let segments = &path.segments[if path.is_global() { 1 } else { 0 }..]; // Paths to enums seem to not match their spans - the span includes all the // variants too. But they seem to always be at the end, so I hope we can cope with // always using the first ones. So, only error out if we don't have enough spans. // What could go wrong...? - if spans.len() < path.segments.len() { + if spans.len() < segments.len() { if generated_code(path.span) { return vec![]; } error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", path_to_string(path), spans.len(), - path.segments.len()); + segments.len()); for s in &spans { let loc = self.sess.codemap().lookup_char_pos(s.lo); error!(" '{}' in {}, line {}", @@ -170,14 +171,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let mut result: Vec<(Span, String)> = vec![]; let mut segs = vec![]; - for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() { + for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() { segs.push(seg.clone()); let sub_path = ast::Path { span: *span, // span for the last segment - global: path.global, segments: segs, }; - let qualname = if i == 0 && path.global { + let qualname = if i == 0 && path.is_global() { format!("::{}", path_to_string(&sub_path)) } else { path_to_string(&sub_path) @@ -189,20 +189,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { result } - // The global arg allows us to override the global-ness of the path (which - // actually means 'does the path start with `::`', rather than 'is the path - // semantically global). We use the override for `use` imports (etc.) where - // the syntax is non-global, but the semantics are global. - fn write_sub_paths(&mut self, path: &ast::Path, global: bool) { + fn write_sub_paths(&mut self, path: &ast::Path) { let sub_paths = self.process_path_prefixes(path); - for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { - let qualname = if i == 0 && global && !path.global { - format!("::{}", qualname) - } else { - qualname.clone() - }; + for (span, qualname) in sub_paths { self.dumper.mod_ref(ModRefData { - span: *span, + span: span, qualname: qualname, scope: self.cur_scope, ref_id: None @@ -212,22 +203,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // As write_sub_paths, but does not process the last ident in the path (assuming it // will be processed elsewhere). See note on write_sub_paths about global. - fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) { + fn write_sub_paths_truncated(&mut self, path: &ast::Path) { let sub_paths = self.process_path_prefixes(path); let len = sub_paths.len(); if len <= 1 { return; } - let sub_paths = &sub_paths[..len-1]; - for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { - let qualname = if i == 0 && global && !path.global { - format!("::{}", qualname) - } else { - qualname.clone() - }; + for (span, qualname) in sub_paths.into_iter().take(len - 1) { self.dumper.mod_ref(ModRefData { - span: *span, + span: span, qualname: qualname, scope: self.cur_scope, ref_id: None @@ -935,7 +920,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::Union(..) | Def::Variant(..) | Def::TyAlias(..) | - Def::AssociatedTy(..) => self.write_sub_paths_truncated(path, false), + Def::AssociatedTy(..) => self.write_sub_paths_truncated(path), _ => {} } } @@ -946,7 +931,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fields: &'l [ast::Field], variant: &'l ty::VariantDef, base: &'l Option>) { - self.write_sub_paths_truncated(path, false); + self.write_sub_paths_truncated(path); if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(struct_lit_data, TypeRefData, ex.span); @@ -1201,7 +1186,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: From::from(&item.vis), }.lower(self.tcx)); } - self.write_sub_paths_truncated(path, true); + self.write_sub_paths_truncated(path); } ast::ViewPathGlob(ref path) => { // Make a comma-separated list of names of imported modules. @@ -1225,7 +1210,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: From::from(&item.vis), }.lower(self.tcx)); } - self.write_sub_paths(path, true); + self.write_sub_paths(path); } ast::ViewPathList(ref path, ref list) => { for plid in list { @@ -1237,7 +1222,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } } - self.write_sub_paths(path, true); + self.write_sub_paths(path); } } } @@ -1340,7 +1325,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, }.lower(self.tcx)); } - self.write_sub_paths_truncated(path, false); + self.write_sub_paths_truncated(path); visit::walk_path(self, path); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 123516dc89d74..fdbd2f3647c0c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1737,7 +1737,6 @@ impl Clean for hir::Ty { segments.pop(); let trait_path = hir::Path { span: p.span, - global: p.global, def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()), segments: segments.into(), }; @@ -1756,7 +1755,6 @@ impl Clean for hir::Ty { } let trait_path = hir::Path { span: self.span, - global: false, def: def, segments: vec![].into(), }; @@ -2213,9 +2211,9 @@ impl Path { impl Clean for hir::Path { fn clean(&self, cx: &DocContext) -> Path { Path { - global: self.global, + global: self.is_global(), def: self.def, - segments: self.segments.clean(cx), + segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx), } } } @@ -2270,24 +2268,19 @@ impl Clean for hir::PathSegment { } fn qpath_to_string(p: &hir::QPath) -> String { - let (segments, global) = match *p { - hir::QPath::Resolved(_, ref path) => { - (&path.segments, path.global) - } - hir::QPath::TypeRelative(_, ref segment) => { - return segment.name.to_string() - } + let segments = match *p { + hir::QPath::Resolved(_, ref path) => &path.segments, + hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(), }; let mut s = String::new(); - let mut first = true; - for i in segments.iter().map(|x| x.name.as_str()) { - if !first || global { + for (i, seg) in segments.iter().enumerate() { + if i > 0 { s.push_str("::"); - } else { - first = false; } - s.push_str(&i); + if seg.name != keywords::CrateRoot.name() { + s.push_str(&*seg.name.as_str()); + } } s } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fdd82225b9747..648a82ffb7684 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -111,10 +111,8 @@ pub struct LifetimeDef { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Path { pub span: Span, - /// A `::foo` path, is relative to the crate root rather than current - /// module (like paths in an import). - pub global: bool, /// The segments in the path: the things separated by `::`. + /// Global paths begin with `keywords::CrateRoot`. pub segments: Vec, } @@ -136,10 +134,22 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - global: false, segments: vec![identifier.into()], } } + + pub fn default_to_global(mut self) -> Path { + let name = self.segments[0].identifier.name; + if !self.is_global() && name != "$crate" && + name != keywords::SelfValue.name() && name != keywords::Super.name() { + self.segments.insert(0, PathSegment::crate_root()); + } + self + } + + pub fn is_global(&self) -> bool { + !self.segments.is_empty() && self.segments[0].identifier.name == keywords::CrateRoot.name() + } } /// A segment of a path: an identifier, an optional lifetime, and a set of types. @@ -166,6 +176,15 @@ impl From for PathSegment { } } +impl PathSegment { + pub fn crate_root() -> Self { + PathSegment { + identifier: keywords::CrateRoot.ident(), + parameters: None, + } + } +} + /// Parameters of a path segment. /// /// E.g. `` as in `Foo` or `(A, B)` as in `Foo(A, B)` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index c3dc64f91247b..7584fa3916de0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -322,7 +322,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec ) -> ast::Path { let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = idents.into_iter().map(Into::into).collect(); + let mut segments: Vec = Vec::new(); + if global { + segments.push(ast::PathSegment::crate_root()); + } + + segments.extend(idents.into_iter().map(Into::into)); let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { None } else { @@ -335,7 +340,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); ast::Path { span: sp, - global: global, segments: segments, } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index eb4b6144c8d28..66555d7d95dce 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -25,7 +25,7 @@ use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { dummy_spanned(ast::Mac_ { - path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, tts: Vec::new(), }) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b3753e3e977e3..bf10d45add4a0 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -433,9 +433,8 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { i } -pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut T) -> Path { +pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - global: global, segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { identifier: fld.fold_ident(identifier), parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b9e6605639ead..24178e1f675b5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -633,7 +633,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - global: false, segments: vec![Ident::from_str("a").into()], }), span: sp(0, 1), @@ -647,8 +646,9 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), - global: true, - segments: vec![Ident::from_str("a").into(), Ident::from_str("b").into()], + segments: vec![ast::PathSegment::crate_root(), + Ident::from_str("a").into(), + Ident::from_str("b").into()] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -757,7 +757,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - global: false, segments: vec![Ident::from_str("d").into()], }), span:sp(7,8), @@ -775,7 +774,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - global:false, segments: vec![Ident::from_str("b").into()], }), span: sp(0,1), @@ -817,7 +815,6 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - global:false, segments: vec![Ident::from_str("i32").into()], }), span:sp(10,13) @@ -860,7 +857,6 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - global:false, segments: vec![Ident::from_str("b").into()], }), span: sp(17,18), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 72462b74e686c..cd4f255b5e3f8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1614,7 +1614,6 @@ impl<'a> Parser<'a> { } else { ast::Path { span: span, - global: false, segments: vec![] } }; @@ -1658,7 +1657,7 @@ impl<'a> Parser<'a> { // Parse any number of segments and bound sets. A segment is an // identifier followed by an optional lifetime and a set of types. // A bound set is a set of type parameter bounds. - let segments = match mode { + let mut segments = match mode { PathStyle::Type => { self.parse_path_segments_without_colons()? } @@ -1670,13 +1669,16 @@ impl<'a> Parser<'a> { } }; + if is_global { + segments.insert(0, ast::PathSegment::crate_root()); + } + // Assemble the span. let span = mk_sp(lo, self.prev_span.hi); // Assemble the result. Ok(ast::Path { span: span, - global: is_global, segments: segments, }) } @@ -5180,7 +5182,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Crate) { pub_crate(self) } else { - let path = self.parse_path(PathStyle::Mod)?; + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); self.expect(&token::CloseDelim(token::Paren))?; Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) } @@ -6068,9 +6070,9 @@ impl<'a> Parser<'a> { if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. + self.eat(&token::ModSep); let prefix = ast::Path { - global: self.eat(&token::ModSep), - segments: Vec::new(), + segments: vec![ast::PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { @@ -6080,7 +6082,7 @@ impl<'a> Parser<'a> { }; Ok(P(spanned(lo, self.span.hi, view_path_kind))) } else { - let prefix = self.parse_path(PathStyle::Mod)?; + let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { // `foo::bar::{a, b}` or `foo::bar::*` self.bump(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 22e8391de93ed..e9c1cbcba61db 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -371,7 +371,7 @@ pub fn fn_block_to_string(p: &ast::FnDecl) -> String { } pub fn path_to_string(p: &ast::Path) -> String { - to_string(|s| s.print_path(p, false, 0)) + to_string(|s| s.print_path(p, false, 0, false)) } pub fn ident_to_string(id: ast::Ident) -> String { @@ -435,7 +435,8 @@ pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { match *vis { ast::Visibility::Public => format!("pub {}", s), ast::Visibility::Crate(_) => format!("pub(crate) {}", s), - ast::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s), + ast::Visibility::Restricted { ref path, .. } => + format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s), ast::Visibility::Inherited => s.to_string() } } @@ -1021,7 +1022,7 @@ impl<'a> State<'a> { &generics)); } ast::TyKind::Path(None, ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, false)); } ast::TyKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, false)) @@ -1332,7 +1333,7 @@ impl<'a> State<'a> { } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { try!(self.print_visibility(&item.vis)); - try!(self.print_path(&node.path, false, 0)); + try!(self.print_path(&node.path, false, 0, false)); try!(word(&mut self.s, "! ")); try!(self.print_ident(item.ident)); try!(self.cbox(INDENT_UNIT)); @@ -1347,7 +1348,7 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> { - self.print_path(&t.path, false, 0) + self.print_path(&t.path, false, 0, false) } fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> { @@ -1405,8 +1406,10 @@ impl<'a> State<'a> { match *vis { ast::Visibility::Public => self.word_nbsp("pub"), ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"), - ast::Visibility::Restricted { ref path, .. } => - self.word_nbsp(&format!("pub({})", path)), + ast::Visibility::Restricted { ref path, .. } => { + let path = to_string(|s| s.print_path(path, false, 0, true)); + self.word_nbsp(&format!("pub({})", path)) + } ast::Visibility::Inherited => Ok(()) } } @@ -1571,7 +1574,7 @@ impl<'a> State<'a> { } ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - self.print_path(&node.path, false, 0)?; + self.print_path(&node.path, false, 0, false)?; word(&mut self.s, "! ")?; self.cbox(INDENT_UNIT)?; self.popen()?; @@ -1607,7 +1610,7 @@ impl<'a> State<'a> { } ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - try!(self.print_path(&node.path, false, 0)); + try!(self.print_path(&node.path, false, 0, false)); try!(word(&mut self.s, "! ")); try!(self.cbox(INDENT_UNIT)); try!(self.popen()); @@ -1793,7 +1796,7 @@ impl<'a> State<'a> { pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken) -> io::Result<()> { - try!(self.print_path(&m.node.path, false, 0)); + try!(self.print_path(&m.node.path, false, 0, false)); try!(word(&mut self.s, "!")); match delim { token::Paren => try!(self.popen()), @@ -1885,7 +1888,7 @@ impl<'a> State<'a> { fields: &[ast::Field], wth: &Option>, attrs: &[Attribute]) -> io::Result<()> { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(word(&mut self.s, "{")); try!(self.print_inner_attributes_inline(attrs)); try!(self.commasep_cmnt( @@ -2186,7 +2189,7 @@ impl<'a> State<'a> { } } ast::ExprKind::Path(None, ref path) => { - try!(self.print_path(path, true, 0)) + try!(self.print_path(path, true, 0, false)) } ast::ExprKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, true)) @@ -2334,23 +2337,25 @@ impl<'a> State<'a> { fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, - depth: usize) + depth: usize, + defaults_to_global: bool) -> io::Result<()> { try!(self.maybe_print_comment(path.span.lo)); - let mut first = !path.global; - for segment in &path.segments[..path.segments.len()-depth] { - if first { - first = false - } else { + let mut segments = path.segments[..path.segments.len()-depth].iter(); + if defaults_to_global && path.is_global() { + segments.next(); + } + for (i, segment) in segments.enumerate() { + if i > 0 { try!(word(&mut self.s, "::")) } - - try!(self.print_ident(segment.identifier)); - - if let Some(ref parameters) = segment.parameters { - try!(self.print_path_parameters(parameters, colons_before_params)) + if segment.identifier.name != keywords::CrateRoot.name() { + try!(self.print_ident(segment.identifier)); + if let Some(ref parameters) = segment.parameters { + try!(self.print_path_parameters(parameters, colons_before_params)); + } } } @@ -2369,7 +2374,7 @@ impl<'a> State<'a> { try!(space(&mut self.s)); try!(self.word_space("as")); let depth = path.segments.len() - qself.position; - try!(self.print_path(&path, false, depth)); + try!(self.print_path(&path, false, depth, false)); } try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); @@ -2472,7 +2477,7 @@ impl<'a> State<'a> { } } PatKind::TupleStruct(ref path, ref elts, ddpos) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(self.popen()); if let Some(ddpos) = ddpos { try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))); @@ -2490,13 +2495,13 @@ impl<'a> State<'a> { try!(self.pclose()); } PatKind::Path(None, ref path) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); } PatKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, false)); } PatKind::Struct(ref path, ref fields, etc) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(self.nbsp()); try!(self.word_space("{")); try!(self.commasep_cmnt( @@ -2843,7 +2848,7 @@ impl<'a> State<'a> { try!(self.print_lifetime_bounds(lifetime, bounds)); } ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, false)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&ty)); @@ -2857,7 +2862,7 @@ impl<'a> State<'a> { pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> { match vp.node { ast::ViewPathSimple(ident, ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); if path.segments.last().unwrap().identifier.name != ident.name { @@ -2870,7 +2875,7 @@ impl<'a> State<'a> { } ast::ViewPathGlob(ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); word(&mut self.s, "::*") } @@ -2878,7 +2883,7 @@ impl<'a> State<'a> { if path.segments.is_empty() { try!(word(&mut self.s, "{")); } else { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, &idents[..], |s, w| { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4ad760a3cafe4..68d807b24a788 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -80,8 +80,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, }], vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { - global: false, - segments: vec![name, "prelude", "v1"].into_iter().map(|name| { + segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { ast::Ident::from_str(name).into() }).collect(), span: span, diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index fe9a176179ce6..c2123ea5a0798 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,6 +221,9 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + + // A virtual keyword that resolves to the crate root when used in a lexical scope. + (56, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 7709d3bd1cf1c..b8e0b938814a7 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -579,7 +579,6 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - global: false, segments: ids.into_iter().map(Into::into).collect(), } } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1381490efa194..1fc1bdff593c2 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,6 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - global: false, segments: vec![self.ident.into()], } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 51199819dfcd7..7f187d8d1c119 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -363,15 +363,12 @@ fn find_type_parameters(ty: &ast::Ty, impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyKind::Path(_, ref path) if !path.global => { - if let Some(segment) = path.segments.first() { - if self.ty_param_names.contains(&segment.identifier.name) { - self.types.push(P(ty.clone())); - } + if let ast::TyKind::Path(_, ref path) = ty.node { + if let Some(segment) = path.segments.first() { + if self.ty_param_names.contains(&segment.identifier.name) { + self.types.push(P(ty.clone())); } } - _ => {} } visit::walk_ty(self, ty) diff --git a/src/test/compile-fail/resolve-primitive-fallback.rs b/src/test/compile-fail/resolve-primitive-fallback.rs index 1e43933ad0ab4..3c585680eab11 100644 --- a/src/test/compile-fail/resolve-primitive-fallback.rs +++ b/src/test/compile-fail/resolve-primitive-fallback.rs @@ -16,5 +16,5 @@ fn main() { // Make sure primitive type fallback doesn't work with global paths let _: ::u8; - //~^ ERROR type name `u8` is undefined or not in scope + //~^ ERROR type name `::u8` is undefined or not in scope } From 8a1acb2c690eeb11b5c3f2a26bf2d68741ed5844 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 21 Dec 2016 05:31:07 +0000 Subject: [PATCH 2/2] Pretty-print `$crate::foo::bar` as `::foo::bar`. --- src/librustc/hir/print.rs | 4 ++-- src/libsyntax/print/pprust.rs | 3 ++- src/test/pretty/issue-4264.pp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index de4047df81c5d..100e344d94180 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1647,7 +1647,7 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() { + if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } @@ -1674,7 +1674,7 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() { + if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e9c1cbcba61db..7558f0256da18 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2351,7 +2351,8 @@ impl<'a> State<'a> { if i > 0 { try!(word(&mut self.s, "::")) } - if segment.identifier.name != keywords::CrateRoot.name() { + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { try!(self.print_ident(segment.identifier)); if let Some(ref parameters) = segment.parameters { try!(self.print_path_parameters(parameters, colons_before_params)); diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index fdb7f9c68b99d..6c74e7758c4ab 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -39,7 +39,7 @@ - (($crate::fmt::format as + ((::fmt::format as fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({