From 8e61ff25d85dcdc81c55f51ba2a777e13e561a25 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 10 Dec 2016 06:45:58 +0000 Subject: [PATCH] Optimize `ast::PathSegment`. --- src/librustc/hir/lowering.rs | 18 +++-- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/lib.rs | 14 +--- src/librustc_resolve/macros.rs | 4 +- src/libsyntax/ast.rs | 97 +++++---------------------- src/libsyntax/ext/build.rs | 31 ++++----- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/mod.rs | 53 +++------------ src/libsyntax/parse/parser.rs | 40 ++++------- src/libsyntax/print/pprust.rs | 13 ++-- src/libsyntax/std_inject.rs | 5 +- src/libsyntax/test.rs | 5 +- src/libsyntax/visit.rs | 4 +- src/libsyntax_ext/concat_idents.rs | 6 +- 14 files changed, 86 insertions(+), 210 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f5773d351780..e8c3492705a3 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -433,13 +433,19 @@ impl<'a> LoweringContext<'a> { segment: &PathSegment, param_mode: ParamMode) -> hir::PathSegment { - let parameters = match segment.parameters { - PathParameters::AngleBracketed(ref data) => { - let data = self.lower_angle_bracketed_parameter_data(data, param_mode); - hir::AngleBracketedParameters(data) + let parameters = if let Some(ref parameters) = segment.parameters { + match **parameters { + PathParameters::AngleBracketed(ref data) => { + let data = self.lower_angle_bracketed_parameter_data(data, param_mode); + hir::AngleBracketedParameters(data) + } + PathParameters::Parenthesized(ref data) => { + hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)) + } } - PathParameters::Parenthesized(ref data) => - hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)), + } else { + let data = self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode); + hir::AngleBracketedParameters(data) }; hir::PathSegment { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2d0f0864752a..bc150b847786 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -171,7 +171,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match item.node { ItemKind::Use(ref view_path) => { let path = view_path.node.path(); - if !path.segments.iter().all(|segment| segment.parameters.is_empty()) { + if path.segments.iter().any(|segment| segment.parameters.is_some()) { self.err_handler() .span_err(path.span, "type or lifetime parameters in import path"); } @@ -275,7 +275,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_vis(&mut self, vis: &'a Visibility) { match *vis { Visibility::Restricted { ref path, .. } => { - if !path.segments.iter().all(|segment| segment.parameters.is_empty()) { + if !path.segments.iter().all(|segment| segment.parameters.is_none()) { self.err_handler() .span_err(path.span, "type or lifetime parameters in visibility path"); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d87e04f7b97f..821820df8388 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -62,7 +62,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; -use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax_pos::{Span, DUMMY_SP}; use errors::DiagnosticBuilder; @@ -2960,14 +2960,9 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let params = PathParameters::none(); - let segment = PathSegment { - identifier: ident, - parameters: params, - }; let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(segment); + segms.push(ident.into()); let path = Path { span: span, global: false, @@ -2990,10 +2985,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(PathSegment { - identifier: ident, - parameters: PathParameters::none(), - }); + path_segments.push(ident.into()); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ce92a4446f92..6399a266fcf3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -183,9 +183,9 @@ 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; - if segments.iter().any(|segment| !segment.parameters.is_empty()) { + if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = - if segments.last().unwrap().parameters.is_empty() { "module" } else { "macro" }; + if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" }; let msg = format!("type parameters are not allowed on {}s", kind); self.session.span_err(path.span, &msg); return Err(Determinacy::Determined); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 39d78cd87761..fdd82225b974 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -137,12 +137,7 @@ impl Path { Path { span: s, global: false, - segments: vec![ - PathSegment { - identifier: identifier, - parameters: PathParameters::none() - } - ], + segments: vec![identifier.into()], } } } @@ -160,7 +155,15 @@ pub struct PathSegment { /// this is more than just simple syntactic sugar; the use of /// parens affects the region binding rules, so we preserve the /// distinction. - pub parameters: PathParameters, + /// The `Option>` wrapper is purely a size optimization; + /// `None` is used to represent both `Path` and `Path<>`. + pub parameters: Option>, +} + +impl From for PathSegment { + fn from(id: Ident) -> Self { + PathSegment { identifier: id, parameters: None } + } } /// Parameters of a path segment. @@ -174,79 +177,8 @@ pub enum PathParameters { Parenthesized(ParenthesizedParameterData), } -impl PathParameters { - pub fn none() -> PathParameters { - PathParameters::AngleBracketed(AngleBracketedParameterData { - lifetimes: Vec::new(), - types: P::new(), - bindings: P::new(), - }) - } - - pub fn is_empty(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => data.is_empty(), - - // Even if the user supplied no types, something like - // `X()` is equivalent to `X<(),()>`. - PathParameters::Parenthesized(..) => false, - } - } - - pub fn has_lifetimes(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => !data.lifetimes.is_empty(), - PathParameters::Parenthesized(_) => false, - } - } - - pub fn has_types(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => !data.types.is_empty(), - PathParameters::Parenthesized(..) => true, - } - } - - /// Returns the types that the user wrote. Note that these do not necessarily map to the type - /// parameters in the parenthesized case. - pub fn types(&self) -> Vec<&P> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.types.iter().collect() - } - PathParameters::Parenthesized(ref data) => { - data.inputs.iter() - .chain(data.output.iter()) - .collect() - } - } - } - - pub fn lifetimes(&self) -> Vec<&Lifetime> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.lifetimes.iter().collect() - } - PathParameters::Parenthesized(_) => { - Vec::new() - } - } - } - - pub fn bindings(&self) -> Vec<&TypeBinding> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.bindings.iter().collect() - } - PathParameters::Parenthesized(_) => { - Vec::new() - } - } - } -} - /// A path like `Foo<'a, T>` -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Default)] pub struct AngleBracketedParameterData { /// The lifetime parameters for this path segment. pub lifetimes: Vec, @@ -258,9 +190,10 @@ pub struct AngleBracketedParameterData { pub bindings: P<[TypeBinding]>, } -impl AngleBracketedParameterData { - fn is_empty(&self) -> bool { - self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() +impl Into>> for AngleBracketedParameterData { + fn into(self) -> Option> { + let empty = self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty(); + if empty { None } else { Some(P(PathParameters::AngleBracketed(self))) } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a208b934d79e..c0dfb9002400 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -322,21 +322,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec ) -> ast::Path { let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = idents.into_iter() - .map(|ident| { - ast::PathSegment { - identifier: ident, - parameters: ast::PathParameters::none(), - } - }).collect(); - segments.push(ast::PathSegment { - identifier: last_identifier, - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { + let mut segments: Vec = idents.into_iter().map(Into::into).collect(); + let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { + None + } else { + Some(P(ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { lifetimes: lifetimes, types: P::from_vec(types), bindings: P::from_vec(bindings), - }) - }); + }))) + }; + segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); ast::Path { span: sp, global: global, @@ -367,13 +363,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec) -> (ast::QSelf, ast::Path) { let mut path = trait_path; + let parameters = ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: P::from_vec(types), + bindings: P::from_vec(bindings), + }; path.segments.push(ast::PathSegment { identifier: ident, - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: P::from_vec(types), - bindings: P::from_vec(bindings), - }) + parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); (ast::QSelf { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 6af8efb2a195..b3753e3e977e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -438,7 +438,7 @@ pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut global: global, segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { identifier: fld.fold_ident(identifier), - parameters: fld.fold_path_parameters(parameters), + parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c982205f0ece..b9e6605639ea 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -634,12 +634,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), global: false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("a"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("a").into()], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -651,19 +646,10 @@ mod tests { P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { - span: sp(0, 6), - global: true, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("a"), - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: ast::PathParameters::none(), - } - ] - }), + span: sp(0, 6), + global: true, + segments: vec![Ident::from_str("a").into(), Ident::from_str("b").into()], + }), span: sp(0, 6), attrs: ThinVec::new(), })) @@ -772,12 +758,7 @@ mod tests { node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), global: false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("d"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("d").into()], }), span:sp(7,8), attrs: ThinVec::new(), @@ -795,12 +776,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("b").into()], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -842,12 +818,7 @@ mod tests { node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("i32"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("i32").into()], }), span:sp(10,13) }), @@ -890,13 +861,7 @@ mod tests { ast::Path{ span:sp(17,18), global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: - ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("b").into()], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a1d4ad9d629c..72462b74e686 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1705,12 +1705,11 @@ impl<'a> Parser<'a> { // Parse types, optionally. let parameters = if self.eat_lt() { let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; - - ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { + ast::AngleBracketedParameterData { lifetimes: lifetimes, types: P::from_vec(types), bindings: P::from_vec(bindings), - }) + }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { let lo = self.prev_span.lo; @@ -1727,18 +1726,17 @@ impl<'a> Parser<'a> { let hi = self.prev_span.hi; - ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { + Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { span: mk_sp(lo, hi), inputs: inputs, output: output_ty, - }) + }))) } else { - ast::PathParameters::none() + None }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, - parameters: parameters }); + segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1757,10 +1755,7 @@ impl<'a> Parser<'a> { // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none() - }); + segments.push(identifier.into()); return Ok(segments); } @@ -1768,14 +1763,13 @@ impl<'a> Parser<'a> { if self.eat_lt() { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; - let parameters = ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: P::from_vec(types), - bindings: P::from_vec(bindings), - }; segments.push(ast::PathSegment { identifier: identifier, - parameters: ast::PathParameters::AngleBracketed(parameters), + parameters: ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: P::from_vec(types), + bindings: P::from_vec(bindings), + }.into(), }); // Consumed `a::b::`, check for `::` before proceeding @@ -1784,10 +1778,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - }); + segments.push(identifier.into()); } } } @@ -1802,10 +1793,7 @@ impl<'a> Parser<'a> { let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none() - }); + segments.push(identifier.into()); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c28b9d00501b..22e8391de93e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2349,7 +2349,9 @@ impl<'a> State<'a> { try!(self.print_ident(segment.identifier)); - try!(self.print_path_parameters(&segment.parameters, colons_before_params)); + if let Some(ref parameters) = segment.parameters { + try!(self.print_path_parameters(parameters, colons_before_params)) + } } Ok(()) @@ -2373,7 +2375,10 @@ impl<'a> State<'a> { try!(word(&mut self.s, "::")); let item_segment = path.segments.last().unwrap(); try!(self.print_ident(item_segment.identifier)); - self.print_path_parameters(&item_segment.parameters, colons_before_params) + match item_segment.parameters { + Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params), + None => Ok(()), + } } fn print_path_parameters(&mut self, @@ -2381,10 +2386,6 @@ impl<'a> State<'a> { colons_before_params: bool) -> io::Result<()> { - if parameters.is_empty() { - return Ok(()); - } - if colons_before_params { try!(word(&mut self.s, "::")) } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 6a291ad9c408..4ad760a3cafe 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -81,9 +81,8 @@ 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| ast::PathSegment { - identifier: ast::Ident::from_str(name), - parameters: ast::PathParameters::none(), + segments: vec![name, "prelude", "v1"].into_iter().map(|name| { + ast::Ident::from_str(name).into() }).collect(), span: span, })))), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fca89e265e4e..7709d3bd1cf1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,10 +580,7 @@ fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, global: false, - segments: ids.into_iter().map(|identifier| ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - }).collect() + segments: ids.into_iter().map(Into::into).collect(), } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index c1391d0b1c2f..ad29cb50a84c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -383,7 +383,9 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V, path_span: Span, segment: &'a PathSegment) { visitor.visit_ident(path_span, segment.identifier); - visitor.visit_path_parameters(path_span, &segment.parameters); + if let Some(ref parameters) = segment.parameters { + visitor.visit_path_parameters(path_span, parameters); + } } pub fn walk_path_parameters<'a, V>(visitor: &mut V, diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index b26e33eb384d..1381490efa19 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -59,14 +59,10 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, impl Result { fn path(&self) -> ast::Path { - let segment = ast::PathSegment { - identifier: self.ident, - parameters: ast::PathParameters::none(), - }; ast::Path { span: self.span, global: false, - segments: vec![segment], + segments: vec![self.ident.into()], } } }