Skip to content

Commit

Permalink
put empty generic lists behind a pointer
Browse files Browse the repository at this point in the history
This reduces the size of hir::Expr from 128 to 88 bytes (!) and shaves
200MB out of #36799.
  • Loading branch information
arielb1 committed Sep 24, 2017
1 parent acb73db commit e921b32
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 112 deletions.
4 changes: 3 additions & 1 deletion src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
path_span: Span,
segment: &'v PathSegment) {
visitor.visit_name(path_span, segment.name);
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<'v, V: Visitor<'v>>(visitor: &mut V,
Expand Down
42 changes: 18 additions & 24 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,10 +690,9 @@ impl<'a> LoweringContext<'a> {
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
def: self.expect_full_def(t.id),
segments: hir_vec![hir::PathSegment {
name: keywords::SelfType.name(),
parameters: hir::PathParameters::none()
}],
segments: hir_vec![
hir::PathSegment::from_name(keywords::SelfType.name())
],
span: t.span,
})))
}
Expand Down Expand Up @@ -914,12 +913,8 @@ impl<'a> LoweringContext<'a> {
segments: segments.map(|segment| {
self.lower_path_segment(p.span, segment, param_mode, 0,
ParenthesizedGenericArgs::Err)
}).chain(name.map(|name| {
hir::PathSegment {
name,
parameters: hir::PathParameters::none()
}
})).collect(),
}).chain(name.map(|name| hir::PathSegment::from_name(name)))
.collect(),
span: p.span,
}
}
Expand All @@ -940,7 +935,7 @@ impl<'a> LoweringContext<'a> {
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs)
-> hir::PathSegment {
let mut parameters = if let Some(ref parameters) = segment.parameters {
let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
let msg = "parenthesized parameters may only be used with a trait";
match **parameters {
PathParameters::AngleBracketed(ref data) => {
Expand All @@ -951,12 +946,12 @@ impl<'a> LoweringContext<'a> {
ParenthesizedGenericArgs::Warn => {
self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
CRATE_NODE_ID, data.span, msg.into());
hir::PathParameters::none()
(hir::PathParameters::none(), true)
}
ParenthesizedGenericArgs::Err => {
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
.span_label(data.span, "only traits may use parentheses").emit();
hir::PathParameters::none()
(hir::PathParameters::none(), true)
}
}
}
Expand All @@ -970,40 +965,39 @@ impl<'a> LoweringContext<'a> {
}).collect();
}

hir::PathSegment {
name: self.lower_ident(segment.identifier),
hir::PathSegment::new(
self.lower_ident(segment.identifier),
parameters,
}
infer_types
)
}

fn lower_angle_bracketed_parameter_data(&mut self,
data: &AngleBracketedParameterData,
param_mode: ParamMode)
-> hir::PathParameters {
-> (hir::PathParameters, bool) {
let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data;
hir::PathParameters {
(hir::PathParameters {
lifetimes: self.lower_lifetimes(lifetimes),
types: types.iter().map(|ty| self.lower_ty(ty)).collect(),
infer_types: types.is_empty() && param_mode == ParamMode::Optional,
bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(),
parenthesized: false,
}
}, types.is_empty() && param_mode == ParamMode::Optional)
}

fn lower_parenthesized_parameter_data(&mut self,
data: &ParenthesizedParameterData)
-> hir::PathParameters {
-> (hir::PathParameters, bool) {
let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect();
let mk_tup = |this: &mut Self, tys, span| {
let LoweredNodeId { node_id, hir_id } = this.next_id();
P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
};

hir::PathParameters {
(hir::PathParameters {
lifetimes: hir::HirVec::new(),
types: hir_vec![mk_tup(self, inputs, span)],
infer_types: false,
bindings: hir_vec![hir::TypeBinding {
id: self.next_id().node_id,
name: Symbol::intern(FN_OUTPUT_NAME),
Expand All @@ -1012,7 +1006,7 @@ impl<'a> LoweringContext<'a> {
span: output.as_ref().map_or(span, |ty| ty.span),
}],
parenthesized: true,
}
}, false)
}

fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
Expand Down
47 changes: 39 additions & 8 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,49 @@ 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,
pub parameters: Option<P<PathParameters>>,

/// Whether to infer remaining type parameters, if any.
/// This only applies to expression and pattern paths, and
/// out of those only the segments with no type parameters
/// to begin with, e.g. `Vec::new` is `<Vec<..>>::new::<..>`.
pub infer_types: bool,
}

impl PathSegment {
/// Convert an identifier to the corresponding segment.
pub fn from_name(name: Name) -> PathSegment {
PathSegment {
name,
parameters: PathParameters::none()
infer_types: true,
parameters: None
}
}

pub fn new(name: Name, parameters: PathParameters, infer_types: bool) -> Self {
PathSegment {
name,
infer_types,
parameters: if parameters.is_empty() {
None
} else {
Some(P(parameters))
}
}
}

// FIXME: hack required because you can't create a static
// PathParameters, so you can't just return a &PathParameters.
pub fn with_parameters<F, R>(&self, f: F) -> R
where F: FnOnce(&PathParameters) -> R
{
let dummy = PathParameters::none();
f(if let Some(ref params) = self.parameters {
&params
} else {
&dummy
})
}
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
Expand All @@ -255,11 +287,6 @@ pub struct PathParameters {
pub lifetimes: HirVec<Lifetime>,
/// The type parameters for this path segment, if present.
pub types: HirVec<P<Ty>>,
/// Whether to infer remaining type parameters, if any.
/// This only applies to expression and pattern paths, and
/// out of those only the segments with no type parameters
/// to begin with, e.g. `Vec::new` is `<Vec<..>>::new::<..>`.
pub infer_types: bool,
/// Bindings (equality constraints) on associated types, if present.
/// E.g., `Foo<A=Bar>`.
pub bindings: HirVec<TypeBinding>,
Expand All @@ -274,12 +301,16 @@ impl PathParameters {
Self {
lifetimes: HirVec::new(),
types: HirVec::new(),
infer_types: true,
bindings: HirVec::new(),
parenthesized: false,
}
}

pub fn is_empty(&self) -> bool {
self.lifetimes.is_empty() && self.types.is_empty() &&
self.bindings.is_empty() && !self.parenthesized
}

pub fn inputs(&self) -> &[P<Ty>] {
if self.parenthesized {
if let Some(ref ty) = self.types.get(0) {
Expand Down
45 changes: 34 additions & 11 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,11 +1213,17 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX)?;
self.s.word(".")?;
self.print_name(segment.name)?;
if !segment.parameters.lifetimes.is_empty() ||
!segment.parameters.types.is_empty() ||
!segment.parameters.bindings.is_empty() {
self.print_path_parameters(&segment.parameters, true)?;
}

segment.with_parameters(|parameters| {
if !parameters.lifetimes.is_empty() ||
!parameters.types.is_empty() ||
!parameters.bindings.is_empty()
{
self.print_path_parameters(&parameters, segment.infer_types, true)
} else {
Ok(())
}
})?;
self.print_call_post(base_args)
}

Expand Down Expand Up @@ -1564,8 +1570,12 @@ impl<'a> State<'a> {
}
if segment.name != keywords::CrateRoot.name() &&
segment.name != keywords::DollarCrate.name() {
self.print_name(segment.name)?;
self.print_path_parameters(&segment.parameters, colons_before_params)?;
self.print_name(segment.name)?;
segment.with_parameters(|parameters| {
self.print_path_parameters(parameters,
segment.infer_types,
colons_before_params)
})?;
}
}

Expand Down Expand Up @@ -1593,29 +1603,42 @@ impl<'a> State<'a> {
if segment.name != keywords::CrateRoot.name() &&
segment.name != keywords::DollarCrate.name() {
self.print_name(segment.name)?;
self.print_path_parameters(&segment.parameters, colons_before_params)?;
segment.with_parameters(|parameters| {
self.print_path_parameters(parameters,
segment.infer_types,
colons_before_params)
})?;
}
}

self.s.word(">")?;
self.s.word("::")?;
let item_segment = path.segments.last().unwrap();
self.print_name(item_segment.name)?;
self.print_path_parameters(&item_segment.parameters, colons_before_params)
item_segment.with_parameters(|parameters| {
self.print_path_parameters(parameters,
item_segment.infer_types,
colons_before_params)
})
}
hir::QPath::TypeRelative(ref qself, ref item_segment) => {
self.s.word("<")?;
self.print_type(qself)?;
self.s.word(">")?;
self.s.word("::")?;
self.print_name(item_segment.name)?;
self.print_path_parameters(&item_segment.parameters, colons_before_params)
item_segment.with_parameters(|parameters| {
self.print_path_parameters(parameters,
item_segment.infer_types,
colons_before_params)
})
}
}
}

fn print_path_parameters(&mut self,
parameters: &hir::PathParameters,
infer_types: bool,
colons_before_params: bool)
-> io::Result<()> {
if parameters.parenthesized {
Expand Down Expand Up @@ -1652,7 +1675,7 @@ impl<'a> State<'a> {

// FIXME(eddyb) This would leak into error messages, e.g.:
// "non-exhaustive patterns: `Some::<..>(_)` not covered".
if parameters.infer_types && false {
if infer_types && false {
start_or_comma(self)?;
self.s.word("..")?;
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,13 @@ impl_stable_hash_for!(struct hir::Path {

impl_stable_hash_for!(struct hir::PathSegment {
name,
infer_types,
parameters
});

impl_stable_hash_for!(struct hir::PathParameters {
lifetimes,
types,
infer_types,
bindings,
parenthesized
});
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
self.visit_segment_parameters(path.def, depth, &segment.parameters);
if let Some(ref parameters) = segment.parameters {
self.visit_segment_parameters(path.def, depth, parameters);
}
}
}

Expand Down
Loading

0 comments on commit e921b32

Please sign in to comment.