about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-21 23:24:26 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-09-24 12:34:21 +0300
commite921b32be35f3166757c5a7b93a21e2339769023 (patch)
tree2b7f2ffbcff8287d34b9da9a895b523f1b94e1e3
parentacb73dbe8b311eb2ffa640ac3e01795d84159df4 (diff)
downloadrust-e921b32be35f3166757c5a7b93a21e2339769023.tar.gz
rust-e921b32be35f3166757c5a7b93a21e2339769023.zip
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.
-rw-r--r--src/librustc/hir/intravisit.rs4
-rw-r--r--src/librustc/hir/lowering.rs42
-rw-r--r--src/librustc/hir/mod.rs47
-rw-r--r--src/librustc/hir/print.rs45
-rw-r--r--src/librustc/ich/impls_hir.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs4
-rw-r--r--src/librustc_typeck/astconv.rs104
-rw-r--r--src/librustc_typeck/check/method/confirm.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs12
-rw-r--r--src/librustdoc/clean/mod.rs32
10 files changed, 187 insertions, 112 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 088fd8d9090..1755b3bca05 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -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,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 8208eb896d6..95b8e49d60c 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -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,
                 })))
             }
@@ -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,
         }
     }
@@ -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) => {
@@ -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)
                     }
                 }
             }
@@ -970,29 +965,29 @@ 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| {
@@ -1000,10 +995,9 @@ impl<'a> LoweringContext<'a> {
             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 @@ 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> {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index e96edaa86d2..bff71155440 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -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 @@ 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) {
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index ad31b2009a0..5daffe667fd 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -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)
     }
 
@@ -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)
+               })?;
             }
         }
 
@@ -1593,7 +1603,11 @@ 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)
+                        })?;
                     }
                 }
 
@@ -1601,7 +1615,11 @@ impl<'a> State<'a> {
                 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 @@ impl<'a> State<'a> {
                 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 @@ 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("..")?;
             }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index bc0c52575ae..96d5940caf6 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -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
 });
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 60f03eb5d89..d0c5460fa97 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -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);
+            }
         }
     }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 3171bd41f92..54fd070e93c 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -157,11 +157,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         // 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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                              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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     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 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             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
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 852134bbee3..a9830dd5dde 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -300,7 +300,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             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 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             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)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index edbdfc1a7d4..38558f50f6e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4668,7 +4668,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   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| {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1e25a57b1d2..c9afa3646b2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1852,25 +1852,27 @@ impl Clean<Type> for hir::Ty {
                 };
 
                 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))
         }
     }
 }