提交 48c1c548 编写于 作者: B bors

Auto merge of #44758 - arielb1:a-small-path, r=eddyb

put empty generic lists behind a pointer

This reduces the size of hir::Expr from 128 to 88 bytes (!) and shaves
200MB out of #36799.

This is a performance-sensitive PR so please don't roll it up.

r? @EddyB
......@@ -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,
......
......@@ -690,10 +690,9 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
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,
})))
}
......@@ -914,12 +913,8 @@ fn lower_path_extra(&mut self,
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,
}
}
......@@ -940,7 +935,7 @@ fn lower_path_segment(&mut self,
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) => {
......@@ -951,12 +946,12 @@ fn lower_path_segment(&mut self,
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)
}
}
}
......@@ -970,29 +965,29 @@ fn lower_path_segment(&mut self,
}).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| {
......@@ -1000,10 +995,9 @@ fn lower_parenthesized_parameter_data(&mut self,
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),
......@@ -1012,7 +1006,7 @@ fn lower_parenthesized_parameter_data(&mut self,
span: output.as_ref().map_or(span, |ty| ty.span),
}],
parenthesized: true,
}
}, false)
}
fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
......
......@@ -236,7 +236,13 @@ 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 {
......@@ -244,9 +250,35 @@ impl PathSegment {
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)]
......@@ -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>,
......@@ -274,12 +301,16 @@ pub fn none() -> Self {
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) {
......
......@@ -1213,11 +1213,17 @@ fn print_expr_method_call(&mut self,
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)
}
......@@ -1564,8 +1570,12 @@ pub fn print_path(&mut self,
}
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)
})?;
}
}
......@@ -1593,7 +1603,11 @@ pub fn print_qpath(&mut self,
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)
})?;
}
}
......@@ -1601,7 +1615,11 @@ pub fn print_qpath(&mut self,
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("<")?;
......@@ -1609,13 +1627,18 @@ pub fn print_qpath(&mut self,
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 {
......@@ -1652,7 +1675,7 @@ fn print_path_parameters(&mut self,
// 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("..")?;
}
......
......@@ -150,13 +150,13 @@ fn hash_stable<W: StableHasherResult>(&self,
impl_stable_hash_for!(struct hir::PathSegment {
name,
infer_types,
parameters
});
impl_stable_hash_for!(struct hir::PathParameters {
lifetimes,
types,
infer_types,
bindings,
parenthesized
});
......
......@@ -445,7 +445,9 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
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);
}
}
}
......
......@@ -157,11 +157,16 @@ pub fn ast_path_substs_for_ty(&self,
item_segment: &hir::PathSegment)
-> &'tcx Substs<'tcx>
{
let (substs, assoc_bindings) =
self.create_substs_for_ast_path(span,
def_id,
&item_segment.parameters,
None);
item_segment.with_parameters(|parameters| {
self.create_substs_for_ast_path(
span,
def_id,
parameters,
item_segment.infer_types,
None)
});
assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
......@@ -177,6 +182,7 @@ fn create_substs_for_ast_path(&self,
span: Span,
def_id: DefId,
parameters: &hir::PathParameters,
infer_types: bool,
self_ty: Option<Ty<'tcx>>)
-> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
{
......@@ -204,7 +210,7 @@ fn create_substs_for_ast_path(&self,
// Check the number of type parameters supplied by the user.
let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..];
if !parameters.infer_types || num_types_provided > ty_param_defs.len() {
if !infer_types || num_types_provided > ty_param_defs.len() {
check_type_argument_count(tcx, span, num_types_provided, ty_param_defs);
}
......@@ -240,7 +246,7 @@ fn create_substs_for_ast_path(&self,
if i < num_types_provided {
// A provided type parameter.
self.ast_ty_to_ty(&parameters.types[i])
} else if parameters.infer_types {
} else if infer_types {
// No type parameters were provided, we can infer all.
let ty_var = if !default_needs_object_self(def) {
self.ty_infer_for_def(def, substs, span)
......@@ -390,7 +396,7 @@ fn create_substs_for_ast_trait_ref(&self,
let trait_def = self.tcx().trait_def(trait_def_id);
if !self.tcx().sess.features.borrow().unboxed_closures &&
trait_segment.parameters.parenthesized != trait_def.paren_sugar {
trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar {
// For now, require that parenthetical notation be used only with `Fn()` etc.
let msg = if trait_def.paren_sugar {
"the precise format of `Fn`-family traits' type parameters is subject to change. \
......@@ -402,10 +408,13 @@ fn create_substs_for_ast_trait_ref(&self,
span, GateIssue::Language, msg);
}
self.create_substs_for_ast_path(span,
trait_def_id,
&trait_segment.parameters,
Some(self_ty))
trait_segment.with_parameters(|parameters| {
self.create_substs_for_ast_path(span,
trait_def_id,
parameters,
trait_segment.infer_types,
Some(self_ty))
})
}
fn trait_defines_associated_type_named(&self,
......@@ -876,25 +885,27 @@ fn qpath_to_ty(&self,
pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
for segment in segments {
for typ in &segment.parameters.types {
struct_span_err!(self.tcx().sess, typ.span, E0109,
"type parameters are not allowed on this type")
.span_label(typ.span, "type parameter not allowed")
.emit();
break;
}
for lifetime in &segment.parameters.lifetimes {
struct_span_err!(self.tcx().sess, lifetime.span, E0110,
"lifetime parameters are not allowed on this type")
.span_label(lifetime.span,
"lifetime parameter not allowed on this type")
.emit();
break;
}
for binding in &segment.parameters.bindings {
self.prohibit_projection(binding.span);
break;
}
segment.with_parameters(|parameters| {
for typ in &parameters.types {
struct_span_err!(self.tcx().sess, typ.span, E0109,
"type parameters are not allowed on this type")
.span_label(typ.span, "type parameter not allowed")
.emit();
break;
}
for lifetime in &parameters.lifetimes {
struct_span_err!(self.tcx().sess, lifetime.span, E0110,
"lifetime parameters are not allowed on this type")
.span_label(lifetime.span,
"lifetime parameter not allowed on this type")
.emit();
break;
}
for binding in &parameters.bindings {
self.prohibit_projection(binding.span);
break;
}
})
}
}
......@@ -978,12 +989,14 @@ pub fn def_to_ty(&self,
}
Def::Err => {
for segment in &path.segments {
for ty in &segment.parameters.types {
self.ast_ty_to_ty(ty);
}
for binding in &segment.parameters.bindings {
self.ast_ty_to_ty(&binding.ty);
}
segment.with_parameters(|parameters| {
for ty in &parameters.types {
self.ast_ty_to_ty(ty);
}
for binding in &parameters.bindings {
self.ast_ty_to_ty(&binding.ty);
}
});
}
self.set_tainted_by_errors();
return self.tcx().types.err;
......@@ -1314,15 +1327,16 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
if Some(trait_did) == tcx.lang_items().send_trait() ||
Some(trait_did) == tcx.lang_items().sync_trait() {
let segments = &bound.trait_ref.path.segments;
let parameters = &segments[segments.len() - 1].parameters;
if !parameters.types.is_empty() {
check_type_argument_count(tcx, bound.trait_ref.path.span,
parameters.types.len(), &[]);
}
if !parameters.lifetimes.is_empty() {
report_lifetime_number_error(tcx, bound.trait_ref.path.span,
parameters.lifetimes.len(), 0);
}
segments[segments.len() - 1].with_parameters(|parameters| {
if !parameters.types.is_empty() {
check_type_argument_count(tcx, bound.trait_ref.path.span,
parameters.types.len(), &[]);
}
if !parameters.lifetimes.is_empty() {
report_lifetime_number_error(tcx, bound.trait_ref.path.span,
parameters.lifetimes.len(), 0);
}
});
true
} else {
false
......
......@@ -300,7 +300,7 @@ fn instantiate_method_substs(&mut self,
if i < parent_substs.len() {
parent_substs.region_at(i)
} else if let Some(lifetime)
= provided.lifetimes.get(i - parent_substs.len()) {
= provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) {
AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
} else {
self.region_var_for_def(self.span, def)
......@@ -310,7 +310,10 @@ fn instantiate_method_substs(&mut self,
if i < parent_substs.len() {
parent_substs.type_at(i)
} else if let Some(ast_ty)
= provided.types.get(i - parent_substs.len() - method_generics.regions.len()) {
= provided.as_ref().and_then(|p| {
p.types.get(i - parent_substs.len() - method_generics.regions.len())
})
{
self.to_ty(ast_ty)
} else {
self.type_var_for_def(self.span, def, cur_substs)
......
......@@ -4668,7 +4668,9 @@ pub fn instantiate_value_path(&self,
i -= fn_start;
fn_segment
};
let lifetimes = segment.map_or(&[][..], |(s, _)| &s.parameters.lifetimes[..]);
let lifetimes = segment.map_or(&[][..], |(s, _)| {
s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
});
if let Some(lifetime) = lifetimes.get(i) {
AstConv::ast_region_to_region(self, lifetime, Some(def))
......@@ -4692,7 +4694,7 @@ pub fn instantiate_value_path(&self,
fn_segment
};
let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
(&s.parameters.types[..], s.parameters.infer_types)
(s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
});
// Skip over the lifetimes in the same segment.
......@@ -4769,8 +4771,10 @@ fn check_path_parameter_count(&self,
is_method_call: bool) {
let (lifetimes, types, infer_types, bindings) = segment.map_or(
(&[][..], &[][..], true, &[][..]),
|(s, _)| (&s.parameters.lifetimes[..], &s.parameters.types[..],
s.parameters.infer_types, &s.parameters.bindings[..]));
|(s, _)| s.parameters.as_ref().map_or(
(&[][..], &[][..], s.infer_types, &[][..]),
|p| (&p.lifetimes[..], &p.types[..],
s.infer_types, &p.bindings[..])));
let infer_lifetimes = lifetimes.len() == 0;
let count_lifetime_params = |n| {
......
......@@ -1852,25 +1852,27 @@ fn clean(&self, cx: &DocContext) -> Type {
};
if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
let provided_params = &path.segments.last().unwrap().parameters;
let provided_params = &path.segments.last().unwrap();
let mut ty_substs = FxHashMap();
let mut lt_substs = FxHashMap();
for (i, ty_param) in generics.ty_params.iter().enumerate() {
let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
if let Some(ty) = provided_params.types.get(i).cloned() {
ty_substs.insert(ty_param_def, ty.unwrap().clean(cx));
} else if let Some(default) = ty_param.default.clone() {
ty_substs.insert(ty_param_def, default.unwrap().clean(cx));
provided_params.with_parameters(|provided_params| {
for (i, ty_param) in generics.ty_params.iter().enumerate() {
let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
if let Some(ty) = provided_params.types.get(i).cloned() {
ty_substs.insert(ty_param_def, ty.unwrap().clean(cx));
} else if let Some(default) = ty_param.default.clone() {
ty_substs.insert(ty_param_def, default.unwrap().clean(cx));
}
}
}
for (i, lt_param) in generics.lifetimes.iter().enumerate() {
if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
if !lt.is_elided() {
let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
lt_substs.insert(lt_def_id, lt.clean(cx));
for (i, lt_param) in generics.lifetimes.iter().enumerate() {
if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
if !lt.is_elided() {
let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
lt_substs.insert(lt_def_id, lt.clean(cx));
}
}
}
}
});
return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
}
resolve_type(cx, path.clean(cx), self.id)
......@@ -2419,7 +2421,7 @@ impl Clean<PathSegment> for hir::PathSegment {
fn clean(&self, cx: &DocContext) -> PathSegment {
PathSegment {
name: self.name.clean(cx),
params: self.parameters.clean(cx)
params: self.with_parameters(|parameters| parameters.clean(cx))
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册