about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-08-17 04:05:00 +0300
committerEduard Burtescu <edy.burt@gmail.com>2016-08-17 05:50:57 +0300
commitbfdfa1ce1d7275bbdb89ecb116bf765f19b204e1 (patch)
tree6fea15f842ff937a62fa85d5250e2e75b8ca094e /src
parent4b25f08512eab11aec151d8f718fca0d8840d0c0 (diff)
downloadrust-bfdfa1ce1d7275bbdb89ecb116bf765f19b204e1.tar.gz
rust-bfdfa1ce1d7275bbdb89ecb116bf765f19b204e1.zip
rustc_typeck: use Substs::from_generics instead of manually building them.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/mod.rs7
-rw-r--r--src/librustc_typeck/astconv.rs379
-rw-r--r--src/librustc_typeck/check/mod.rs445
-rw-r--r--src/librustc_typeck/diagnostics.rs4
4 files changed, 300 insertions, 535 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 951570679e0..1e360cd43da 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1234,13 +1234,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.mk_var(ty_var_id)
     }
 
-    pub fn region_vars_for_defs(&self,
-                                span: Span,
-                                defs: &[ty::RegionParameterDef])
-                                -> Vec<ty::Region> {
-        defs.iter().map(|def| self.region_var_for_def(span, def)).collect()
-    }
-
     /// Given a set of generics defined on a type or impl, returns a substitution mapping each
     /// type/region parameter to a fresh inference variable.
     pub fn fresh_substs_for_generics(&self,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index ed4ea3c937b..11ca012fded 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -55,7 +55,7 @@ use hir::def_id::DefId;
 use hir::print as pprust;
 use middle::resolve_lifetime as rl;
 use rustc::lint;
-use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
+use rustc::ty::subst::{TypeSpace, SelfSpace, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
@@ -350,64 +350,77 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         param_mode: PathParamMode,
         decl_generics: &ty::Generics<'tcx>,
         item_segment: &hir::PathSegment)
-        -> Substs<'tcx>
+        -> &'tcx Substs<'tcx>
     {
         let tcx = self.tcx();
 
-        // ast_path_substs() is only called to convert paths that are
-        // known to refer to traits, types, or structs. In these cases,
-        // all type parameters defined for the item being referenced will
-        // be in the TypeSpace or SelfSpace.
-        //
-        // Note: in the case of traits, the self parameter is also
-        // defined, but we don't currently create a `type_param_def` for
-        // `Self` because it is implicit.
-        assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
-        assert!(decl_generics.types.all(|d| d.space != FnSpace));
-
-        let (regions, types, assoc_bindings) = match item_segment.parameters {
-            hir::AngleBracketedParameters(ref data) => {
-                self.convert_angle_bracketed_parameters(rscope, span, decl_generics, data)
-            }
+        match item_segment.parameters {
+            hir::AngleBracketedParameters(_) => {}
             hir::ParenthesizedParameters(..) => {
                 struct_span_err!(tcx.sess, span, E0214,
                           "parenthesized parameters may only be used with a trait")
                     .span_label(span, &format!("only traits may use parentheses"))
                     .emit();
 
-                let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-                (Substs::empty(),
-                 ty_param_defs.iter().map(|_| tcx.types.err).collect(),
-                 vec![])
+                return tcx.mk_substs(Substs::from_generics(decl_generics, |_, _| {
+                    ty::ReStatic
+                }, |_, _| {
+                    tcx.types.err
+                }));
             }
-        };
+        }
+
+        let (substs, assoc_bindings) =
+            self.create_substs_for_ast_path(rscope,
+                                            span,
+                                            param_mode,
+                                            decl_generics,
+                                            &item_segment.parameters,
+                                            None);
 
         assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
 
-        self.create_substs_for_ast_path(span,
-                                        param_mode,
-                                        decl_generics,
-                                        None,
-                                        types,
-                                        regions)
+        substs
     }
 
-    fn create_region_substs(&self,
+    /// Given the type/region arguments provided to some path (along with
+    /// an implicit Self, if this is a trait reference) returns the complete
+    /// set of substitutions. This may involve applying defaulted type parameters.
+    ///
+    /// Note that the type listing given here is *exactly* what the user provided.
+    fn create_substs_for_ast_path(&self,
         rscope: &RegionScope,
         span: Span,
+        param_mode: PathParamMode,
         decl_generics: &ty::Generics<'tcx>,
-        regions_provided: Vec<ty::Region>)
-        -> Substs<'tcx>
+        parameters: &hir::PathParameters,
+        self_ty: Option<Ty<'tcx>>)
+        -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
     {
         let tcx = self.tcx();
 
+        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
+               parameters={:?})",
+               decl_generics, self_ty, parameters);
+
+        let (lifetimes, num_types_provided) = match *parameters {
+            hir::AngleBracketedParameters(ref data) => {
+                if param_mode == PathParamMode::Optional && data.types.is_empty() {
+                    (&data.lifetimes[..], None)
+                } else {
+                    (&data.lifetimes[..], Some(data.types.len()))
+                }
+            }
+            hir::ParenthesizedParameters(_) => (&[][..], Some(1))
+        };
+
         // If the type is parameterized by this region, then replace this
         // region with the current anon region binding (in other words,
         // whatever & would get replaced with).
         let expected_num_region_params = decl_generics.regions.len(TypeSpace);
-        let supplied_num_region_params = regions_provided.len();
+        let supplied_num_region_params = lifetimes.len();
         let regions = if expected_num_region_params == supplied_num_region_params {
-            regions_provided
+            lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect()
         } else {
             let anon_regions =
                 rscope.anon_regions(span, expected_num_region_params);
@@ -423,176 +436,111 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
             }
         };
-        Substs::new_type(vec![], regions)
-    }
 
-    /// Given the type/region arguments provided to some path (along with
-    /// an implicit Self, if this is a trait reference) returns the complete
-    /// set of substitutions. This may involve applying defaulted type parameters.
-    ///
-    /// Note that the type listing given here is *exactly* what the user provided.
-    ///
-    /// The `region_substs` should be the result of `create_region_substs`
-    /// -- that is, a substitution with no types but the correct number of
-    /// regions.
-    fn create_substs_for_ast_path(&self,
-        span: Span,
-        param_mode: PathParamMode,
-        decl_generics: &ty::Generics<'tcx>,
-        self_ty: Option<Ty<'tcx>>,
-        types_provided: Vec<Ty<'tcx>>,
-        region_substs: Substs<'tcx>)
-        -> Substs<'tcx>
-    {
-        let tcx = self.tcx();
+        // If a self-type was declared, one should be provided.
+        assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some());
 
-        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
-               types_provided={:?}, region_substs={:?})",
-               decl_generics, self_ty, types_provided,
-               region_substs);
-
-        assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace));
-        assert!(region_substs.types.is_empty());
-
-        // Convert the type parameters supplied by the user.
-        let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
-        let formal_ty_param_count = ty_param_defs.len();
-        let required_ty_param_count = ty_param_defs.iter()
-                                                   .take_while(|x| x.default.is_none())
-                                                   .count();
-
-        let mut type_substs = self.get_type_substs_for_defs(span,
-                                                            types_provided,
-                                                            param_mode,
-                                                            ty_param_defs,
-                                                            region_substs.clone(),
-                                                            self_ty);
-
-        let supplied_ty_param_count = type_substs.len();
-        check_type_argument_count(self.tcx(), span, supplied_ty_param_count,
-                                  required_ty_param_count, formal_ty_param_count);
-
-        if supplied_ty_param_count < required_ty_param_count {
-            while type_substs.len() < required_ty_param_count {
-                type_substs.push(tcx.types.err);
-            }
-        } else if supplied_ty_param_count > formal_ty_param_count {
-            type_substs.truncate(formal_ty_param_count);
+        // Check the number of type parameters supplied by the user.
+        if let Some(num_provided) = num_types_provided {
+            let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
+            check_type_argument_count(tcx, span, num_provided, ty_param_defs);
         }
-        assert!(type_substs.len() >= required_ty_param_count &&
-                type_substs.len() <= formal_ty_param_count);
 
-        let mut substs = region_substs;
+        let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
+        let default_needs_object_self = |p: &ty::TypeParameterDef<'tcx>| {
+            if let Some(ref default) = p.default {
+                if is_object && default.has_self_ty() {
+                    // There is no suitable inference default for a type parameter
+                    // that references self, in an object type.
+                    return true;
+                }
+            }
 
-        // If a self-type was declared, one should be provided.
-        assert_eq!(decl_generics.types.get_self().is_some(), self_ty.is_some());
-        substs.types.extend(SelfSpace, self_ty.into_iter());
-        substs.types.extend(TypeSpace, type_substs.into_iter());
+            false
+        };
+
+        let mut output_assoc_binding = None;
+        let substs = Substs::from_generics(decl_generics, |def, _| {
+            assert_eq!(def.space, TypeSpace);
+            regions[def.index as usize]
+        }, |def, substs| {
+            assert!(def.space == SelfSpace || def.space == TypeSpace);
+            let i = def.index as usize;
+            if def.space == SelfSpace {
+                // Self, which must have been provided.
+                assert_eq!(i, 0);
+                self_ty.expect("Self type parameter missing")
+            } else if num_types_provided.map_or(false, |n| i < n) {
+                // A provided type parameter.
+                match *parameters {
+                    hir::AngleBracketedParameters(ref data) => {
+                        self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i])
+                    }
+                    hir::ParenthesizedParameters(ref data) => {
+                        assert_eq!(i, 0);
+                        let (ty, assoc) =
+                            self.convert_parenthesized_parameters(rscope, substs, data);
+                        output_assoc_binding = Some(assoc);
+                        ty
+                    }
+                }
+            } else if num_types_provided.is_none() {
+                // 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)
+                } else {
+                    self.ty_infer(span)
+                };
+                ty_var
+            } else if let Some(default) = def.default {
+                // No type parameter provided, but a default exists.
 
-        let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
-        let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
-        for param in &ty_param_defs[actual_supplied_ty_param_count..] {
-            let default = if let Some(default) = param.default {
                 // If we are converting an object type, then the
                 // `Self` parameter is unknown. However, some of the
                 // other type parameters may reference `Self` in their
                 // defaults. This will lead to an ICE if we are not
                 // careful!
-                if is_object && default.has_self_ty() {
+                if default_needs_object_self(def) {
                     span_err!(tcx.sess, span, E0393,
                               "the type parameter `{}` must be explicitly specified \
                                in an object type because its default value `{}` references \
                                the type `Self`",
-                              param.name,
+                              def.name,
                               default);
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
-                    default.subst_spanned(tcx, &substs, Some(span))
+                    default.subst_spanned(tcx, substs, Some(span))
                 }
             } else {
-                span_bug!(span, "extra parameter without default");
-            };
-            substs.types.push(TypeSpace, default);
-        }
-
-        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
-               decl_generics, self_ty, substs);
-
-        substs
-    }
-
-    /// Returns types_provided if it is not empty, otherwise populating the
-    /// type parameters with inference variables as appropriate.
-    fn get_type_substs_for_defs(&self,
-                                span: Span,
-                                types_provided: Vec<Ty<'tcx>>,
-                                param_mode: PathParamMode,
-                                ty_param_defs: &[ty::TypeParameterDef<'tcx>],
-                                mut substs: Substs<'tcx>,
-                                self_ty: Option<Ty<'tcx>>)
-                                -> Vec<Ty<'tcx>>
-    {
-        let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
-        let use_default = |p: &ty::TypeParameterDef<'tcx>| {
-            if let Some(ref default) = p.default {
-                if is_object && default.has_self_ty() {
-                    // There is no suitable inference default for a type parameter
-                    // that references self, in an object type.
-                    return false;
-                }
+                // We've already errored above about the mismatch.
+                tcx.types.err
             }
+        });
 
-            true
+        let assoc_bindings = match *parameters {
+            hir::AngleBracketedParameters(ref data) => {
+                data.bindings.iter().map(|b| {
+                    ConvertedBinding {
+                        item_name: b.name,
+                        ty: self.ast_ty_to_ty(rscope, &b.ty),
+                        span: b.span
+                    }
+                }).collect()
+            }
+            hir::ParenthesizedParameters(ref data) => {
+                vec![output_assoc_binding.unwrap_or_else(|| {
+                    // This is an error condition, but we should
+                    // get the associated type binding anyway.
+                    self.convert_parenthesized_parameters(rscope, &substs, data).1
+                })]
+            }
         };
 
-        if param_mode == PathParamMode::Optional && types_provided.is_empty() {
-            ty_param_defs.iter().map(|def| {
-                let ty_var = if use_default(def) {
-                    self.ty_infer_for_def(def, &substs, span)
-                } else {
-                    self.ty_infer(span)
-                };
-                substs.types.push(def.space, ty_var);
-                ty_var
-            }).collect()
-        } else {
-            types_provided
-        }
-    }
+        debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
+               decl_generics, self_ty, substs);
 
-    fn convert_angle_bracketed_parameters(&self,
-                                          rscope: &RegionScope,
-                                          span: Span,
-                                          decl_generics: &ty::Generics<'tcx>,
-                                          data: &hir::AngleBracketedParameterData)
-                                          -> (Substs<'tcx>,
-                                              Vec<Ty<'tcx>>,
-                                              Vec<ConvertedBinding<'tcx>>)
-    {
-        let regions: Vec<_> =
-            data.lifetimes.iter()
-                          .map(|l| ast_region_to_region(self.tcx(), l))
-                          .collect();
-
-        let region_substs =
-            self.create_region_substs(rscope, span, decl_generics, regions);
-
-        let types: Vec<_> =
-            data.types.iter()
-                      .enumerate()
-                      .map(|(i,t)| self.ast_ty_arg_to_ty(rscope, decl_generics,
-                                                         i, &region_substs, t))
-                      .collect();
-
-        let assoc_bindings: Vec<_> =
-            data.bindings.iter()
-                         .map(|b| ConvertedBinding { item_name: b.name,
-                                                     ty: self.ast_ty_to_ty(rscope, &b.ty),
-                                                     span: b.span })
-                         .collect();
-
-        (region_substs, types, assoc_bindings)
+        (tcx.mk_substs(substs), assoc_bindings)
     }
 
     /// Returns the appropriate lifetime to use for any output lifetimes
@@ -657,29 +605,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     fn convert_parenthesized_parameters(&self,
                                         rscope: &RegionScope,
-                                        span: Span,
-                                        decl_generics: &ty::Generics<'tcx>,
+                                        region_substs: &Substs<'tcx>,
                                         data: &hir::ParenthesizedParameterData)
-                                        -> (Substs<'tcx>,
-                                            Vec<Ty<'tcx>>,
-                                            Vec<ConvertedBinding<'tcx>>)
+                                        -> (Ty<'tcx>, ConvertedBinding<'tcx>)
     {
-        let region_substs =
-            self.create_region_substs(rscope, span, decl_generics, Vec::new());
-
         let anon_scope = rscope.anon_type_scope();
         let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope);
-        let inputs =
-            data.inputs.iter()
-                       .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics,
-                                                        0, &region_substs, a_t))
-                       .collect::<Vec<Ty<'tcx>>>();
-
+        let inputs: Vec<_> = data.inputs.iter().map(|a_t| {
+            self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
+        }).collect();
         let input_params = vec![String::new(); inputs.len()];
         let implied_output_region = self.find_implied_output_region(&inputs, input_params);
 
-        let input_ty = self.tcx().mk_tup(inputs);
-
         let (output, output_span) = match data.output {
             Some(ref output_ty) => {
                 (self.convert_ty_with_lifetime_elision(implied_output_region,
@@ -698,7 +635,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             span: output_span
         };
 
-        (region_substs, vec![input_ty], vec![output_binding])
+        (self.tcx().mk_tup(inputs), output_binding)
     }
 
     pub fn instantiate_poly_trait_ref(&self,
@@ -838,8 +775,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
         };
 
-        let (regions, types, assoc_bindings) = match trait_segment.parameters {
-            hir::AngleBracketedParameters(ref data) => {
+        match trait_segment.parameters {
+            hir::AngleBracketedParameters(_) => {
                 // For now, require that parenthetical notation be used
                 // only with `Fn()` etc.
                 if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
@@ -850,10 +787,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         type parameters is subject to change. \
                         Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead");
                 }
-
-                self.convert_angle_bracketed_parameters(rscope, span, &trait_def.generics, data)
             }
-            hir::ParenthesizedParameters(ref data) => {
+            hir::ParenthesizedParameters(_) => {
                 // For now, require that parenthetical notation be used
                 // only with `Fn()` etc.
                 if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
@@ -862,19 +797,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                      "\
                         parenthetical notation is only stable when used with `Fn`-family traits");
                 }
-
-                self.convert_parenthesized_parameters(rscope, span, &trait_def.generics, data)
             }
-        };
-
-        let substs = self.create_substs_for_ast_path(span,
-                                                     param_mode,
-                                                     &trait_def.generics,
-                                                     Some(self_ty),
-                                                     types,
-                                                     regions);
+        }
 
-        (self.tcx().mk_substs(substs), assoc_bindings)
+        self.create_substs_for_ast_path(rscope,
+                                        span,
+                                        param_mode,
+                                        &trait_def.generics,
+                                        &trait_segment.parameters,
+                                        Some(self_ty))
     }
 
     fn ast_type_binding_to_poly_projection_predicate(
@@ -1000,7 +931,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             return self.tcx().mk_box(*substs.types.get(TypeSpace, 0));
         }
 
-        decl_ty.subst(self.tcx(), &substs)
+        decl_ty.subst(self.tcx(), substs)
     }
 
     fn ast_ty_to_object_trait_ref(&self,
@@ -1473,24 +1404,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// # Parameters
     ///
     /// * `this`, `rscope`: the surrounding context
-    /// * `decl_generics`: the generics of the struct/enum/trait declaration being
-    ///   referenced
-    /// * `index`: the index of the type parameter being instantiated from the list
-    ///   (we assume it is in the `TypeSpace`)
+    /// * `def`: the type parameter being instantiated (if available)
     /// * `region_substs`: a partial substitution consisting of
     ///   only the region type parameters being supplied to this type.
     /// * `ast_ty`: the ast representation of the type being supplied
-    pub fn ast_ty_arg_to_ty(&self,
-                            rscope: &RegionScope,
-                            decl_generics: &ty::Generics<'tcx>,
-                            index: usize,
-                            region_substs: &Substs<'tcx>,
-                            ast_ty: &hir::Ty)
-                            -> Ty<'tcx>
+    fn ast_ty_arg_to_ty(&self,
+                        rscope: &RegionScope,
+                        def: Option<&ty::TypeParameterDef<'tcx>>,
+                        region_substs: &Substs<'tcx>,
+                        ast_ty: &hir::Ty)
+                        -> Ty<'tcx>
     {
         let tcx = self.tcx();
 
-        if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
+        if let Some(def) = def {
             let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
             let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
             self.ast_ty_to_ty(rscope1, ast_ty)
@@ -2194,7 +2121,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                             let parameters = &segments[segments.len() - 1].parameters;
                             if !parameters.types().is_empty() {
                                 check_type_argument_count(tcx, b.trait_ref.path.span,
-                                                          parameters.types().len(), 0, 0);
+                                                          parameters.types().len(), &[]);
                             }
                             if !parameters.lifetimes().is_empty() {
                                 report_lifetime_number_error(tcx, b.trait_ref.path.span,
@@ -2225,7 +2152,9 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 }
 
 fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
-                             required: usize, accepted: usize) {
+                             ty_param_defs: &[ty::TypeParameterDef]) {
+    let accepted = ty_param_defs.len();
+    let required = ty_param_defs.iter().take_while(|x| x.default.is_none()) .count();
     if supplied < required {
         let expected = if required < accepted {
             "expected at least"
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b5018d51b7f..c41bb1930d4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -88,7 +88,7 @@ use hir::def::{Def, PathResolution};
 use hir::def_id::DefId;
 use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
-use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
+use rustc::ty::subst::{self, Subst, Substs};
 use rustc::traits::{self, Reveal};
 use rustc::ty::{GenericPredicates, TypeScheme};
 use rustc::ty::{ParamTy, ParameterEnvironment};
@@ -1702,7 +1702,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                      PathParamMode::Optional,
                                                      &type_scheme.generics,
                                                      path.segments.last().unwrap());
-        let substs = self.tcx.mk_substs(substs);
         debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs);
         let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
         let cause = traits::ObligationCause::new(path.span, self.body_id,
@@ -4158,7 +4157,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         assert!(!segments.is_empty());
 
         let mut ufcs_associated = None;
-        let mut segment_spaces: Vec<_>;
+        let mut type_segment = None;
+        let mut fn_segment = None;
         match def {
             // Case 1 and 1b. Reference to a *type* or *enum variant*.
             Def::SelfTy(..) |
@@ -4172,40 +4172,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::TyParam(..) => {
                 // Everything but the final segment should have no
                 // parameters at all.
-                segment_spaces = vec![None; segments.len() - 1];
-                segment_spaces.push(Some(subst::TypeSpace));
+                type_segment = segments.last();
             }
 
             // Case 2. Reference to a top-level value.
             Def::Fn(..) |
             Def::Const(..) |
             Def::Static(..) => {
-                segment_spaces = vec![None; segments.len() - 1];
-                segment_spaces.push(Some(subst::FnSpace));
-            }
-
-            // Case 3. Reference to a method.
-            Def::Method(def_id) => {
-                let container = self.tcx.impl_or_trait_item(def_id).container();
-                match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
-                    }
-                    ty::ImplContainer(_) => {}
-                }
-
-                if segments.len() >= 2 {
-                    segment_spaces = vec![None; segments.len() - 2];
-                    segment_spaces.push(Some(subst::TypeSpace));
-                    segment_spaces.push(Some(subst::FnSpace));
-                } else {
-                    // `<T>::method` will end up here, and so can `T::method`.
-                    let self_ty = opt_self_ty.expect("UFCS sugared method missing Self");
-                    segment_spaces = vec![Some(subst::FnSpace)];
-                    ufcs_associated = Some((container, self_ty));
-                }
+                fn_segment = segments.last();
             }
 
+            // Case 3. Reference to a method or associated const.
+            Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
                 let container = self.tcx.impl_or_trait_item(def_id).container();
                 match container {
@@ -4216,15 +4194,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 if segments.len() >= 2 {
-                    segment_spaces = vec![None; segments.len() - 2];
-                    segment_spaces.push(Some(subst::TypeSpace));
-                    segment_spaces.push(None);
+                    type_segment = Some(&segments[segments.len() - 2]);
                 } else {
-                    // `<T>::CONST` will end up here, and so can `T::CONST`.
-                    let self_ty = opt_self_ty.expect("UFCS sugared const missing Self");
-                    segment_spaces = vec![None];
+                    // `<T>::assoc` will end up here, and so can `T::assoc`.
+                    let self_ty = opt_self_ty.expect("UFCS sugared assoc missing Self");
                     ufcs_associated = Some((container, self_ty));
                 }
+                fn_segment = segments.last();
             }
 
             // Other cases. Various nonsense that really shouldn't show up
@@ -4234,51 +4210,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::ForeignMod(..) |
             Def::Local(..) |
             Def::Label(..) |
-            Def::Upvar(..) => {
-                segment_spaces = vec![None; segments.len()];
-            }
+            Def::Upvar(..) => {}
 
             Def::Err => {
                 self.set_tainted_by_errors();
-                segment_spaces = vec![None; segments.len()];
             }
         }
-        assert_eq!(segment_spaces.len(), segments.len());
 
         // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
         // `opt_self_ty` can also be Some for `Foo::method`, where Foo's
         // type parameters are not mandatory.
         let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none();
 
-        debug!("segment_spaces={:?}", segment_spaces);
-
-        // Next, examine the definition, and determine how many type
-        // parameters we expect from each space.
-        let type_defs = &type_scheme.generics.types;
-        let region_defs = &type_scheme.generics.regions;
+        debug!("type_segment={:?} fn_segment={:?}", type_segment, fn_segment);
 
         // Now that we have categorized what space the parameters for each
         // segment belong to, let's sort out the parameters that the user
         // provided (if any) into their appropriate spaces. We'll also report
         // errors if type parameters are provided in an inappropriate place.
-        let mut substs = Substs::empty();
-        for (&opt_space, segment) in segment_spaces.iter().zip(segments) {
-            if let Some(space) = opt_space {
-                self.push_explicit_parameters_from_segment_to_substs(space,
-                                                                     span,
-                                                                     type_defs,
-                                                                     region_defs,
-                                                                     segment,
-                                                                     &mut substs);
-            } else {
-                self.tcx.prohibit_type_params(slice::ref_slice(segment));
-            }
-        }
-        if let Some(self_ty) = opt_self_ty {
-            if type_defs.len(subst::SelfSpace) == 1 {
-                substs.types.push(subst::SelfSpace, self_ty);
-            }
-        }
+        let poly_segments = type_segment.is_some() as usize +
+                            fn_segment.is_some() as usize;
+        self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
 
         // Now we have to compare the types that the user *actually*
         // provided against the types that were *expected*. If the user
@@ -4286,19 +4238,77 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // variables. If the user provided some types, we may still need
         // to add defaults. If the user provided *too many* types, that's
         // a problem.
-        for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] {
-            self.adjust_type_parameters(span, space, type_defs,
-                                        require_type_space, &mut substs);
-            assert_eq!(substs.types.len(space), type_defs.len(space));
+        self.check_path_parameter_count(subst::TypeSpace,
+                                        span,
+                                        &type_scheme.generics,
+                                        !require_type_space,
+                                        &mut type_segment);
+        self.check_path_parameter_count(subst::FnSpace,
+                                        span,
+                                        &type_scheme.generics,
+                                        true,
+                                        &mut fn_segment);
+
+        let substs = Substs::from_generics(&type_scheme.generics, |def, _| {
+            let i = def.index as usize;
+            let segment = match def.space {
+                subst::SelfSpace => None,
+                subst::TypeSpace => type_segment,
+                subst::FnSpace => fn_segment
+            };
+            let lifetimes = match segment.map(|s| &s.parameters) {
+                Some(&hir::AngleBracketedParameters(ref data)) => &data.lifetimes[..],
+                Some(&hir::ParenthesizedParameters(_)) => bug!(),
+                None => &[]
+            };
 
-            self.adjust_region_parameters(span, space, region_defs, &mut substs);
-            assert_eq!(substs.regions.len(space), region_defs.len(space));
-        }
+            if let Some(ast_lifetime) = lifetimes.get(i) {
+                ast_region_to_region(self.tcx, ast_lifetime)
+            } else {
+                self.region_var_for_def(span, def)
+            }
+        }, |def, substs| {
+            let i = def.index as usize;
+            let segment = match def.space {
+                subst::SelfSpace => None,
+                subst::TypeSpace => type_segment,
+                subst::FnSpace => fn_segment
+            };
+            let types = match segment.map(|s| &s.parameters) {
+                Some(&hir::AngleBracketedParameters(ref data)) => &data.types[..],
+                Some(&hir::ParenthesizedParameters(_)) => bug!(),
+                None => &[]
+            };
+            let can_omit = def.space != subst::TypeSpace || !require_type_space;
+            let default = if can_omit && types.len() == 0 {
+                def.default
+            } else {
+                None
+            };
+
+            if def.space == subst::SelfSpace && opt_self_ty.is_some() {
+                // Self, which has been provided.
+                assert_eq!(i, 0);
+                opt_self_ty.unwrap()
+            } else if let Some(ast_ty) = types.get(i) {
+                // A provided type parameter.
+                self.to_ty(ast_ty)
+            } else if let Some(default) = default {
+                // No type parameter provided, but a default exists.
+                default.subst_spanned(self.tcx, substs, Some(span))
+            } else {
+                // No type parameters were provided, we can infer all.
+                // This can also be reached in some error cases:
+                // We prefer to use inference variables instead of
+                // TyError to let type inference recover somewhat.
+                self.type_var_for_def(span, def, substs)
+            }
+        });
 
         // The things we are substituting into the type should not contain
         // escaping late-bound regions, and nor should the base type scheme.
         let substs = self.tcx.mk_substs(substs);
-        assert!(!substs.has_regions_escaping_depth(0));
+        assert!(!substs.has_escaping_regions());
         assert!(!type_scheme.has_escaping_regions());
 
         // Add all the obligations that are required, substituting and
@@ -4349,246 +4359,79 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
-    /// Finds the parameters that the user provided and adds them to `substs`. If too many
-    /// parameters are provided, then reports an error and clears the output vector.
-    ///
-    /// We clear the output vector because that will cause the `adjust_XXX_parameters()` later to
-    /// use inference variables. This seems less likely to lead to derived errors.
-    ///
-    /// Note that we *do not* check for *too few* parameters here. Due to the presence of defaults
-    /// etc that is more complicated. I wanted however to do the reporting of *too many* parameters
-    /// here because we can easily use the precise span of the N+1'th parameter.
-    fn push_explicit_parameters_from_segment_to_substs(&self,
-        space: subst::ParamSpace,
-        span: Span,
-        type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
-        region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
-        segment: &hir::PathSegment,
-        substs: &mut Substs<'tcx>)
-    {
-        match segment.parameters {
-            hir::AngleBracketedParameters(ref data) => {
-                self.push_explicit_angle_bracketed_parameters_from_segment_to_substs(
-                    space, type_defs, region_defs, data, substs);
-            }
-
-            hir::ParenthesizedParameters(ref data) => {
-                span_err!(self.tcx.sess, span, E0238,
-                    "parenthesized parameters may only be used with a trait");
-                self.push_explicit_parenthesized_parameters_from_segment_to_substs(
-                    space, span, type_defs, data, substs);
-            }
-        }
-    }
-
-    fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(&self,
-        space: subst::ParamSpace,
-        type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
-        region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
-        data: &hir::AngleBracketedParameterData,
-        substs: &mut Substs<'tcx>)
-    {
-        {
-            let type_count = type_defs.len(space);
-            assert_eq!(substs.types.len(space), 0);
-            for (i, typ) in data.types.iter().enumerate() {
-                let t = self.to_ty(&typ);
-                if i < type_count {
-                    substs.types.push(space, t);
-                } else if i == type_count {
-                    struct_span_err!(self.tcx.sess, typ.span, E0087,
-                                     "too many type parameters provided: \
-                                      expected at most {} parameter{}, \
-                                      found {} parameter{}",
-                                     type_count,
-                                     if type_count == 1 {""} else {"s"},
-                                     data.types.len(),
-                                     if data.types.len() == 1 {""} else {"s"})
-                        .span_label(typ.span , &format!("expected {} parameter{}",
-                                    type_count,
-                                    if type_count == 1 {""} else {"s"})).emit();
-                    substs.types.truncate(space, 0);
-                    break;
-                }
+    /// Report errors if the provided parameters are too few or too many.
+    fn check_path_parameter_count(&self,
+                                  space: subst::ParamSpace,
+                                  span: Span,
+                                  generics: &ty::Generics<'tcx>,
+                                  can_omit: bool,
+                                  segment: &mut Option<&hir::PathSegment>) {
+        let (lifetimes, types, bindings) = match segment.map(|s| &s.parameters) {
+            Some(&hir::AngleBracketedParameters(ref data)) => {
+                (&data.lifetimes[..], &data.types[..], &data.bindings[..])
             }
-        }
-
-        if !data.bindings.is_empty() {
-            span_err!(self.tcx.sess, data.bindings[0].span, E0182,
-                      "unexpected binding of associated item in expression path \
-                       (only allowed in type paths)");
-        }
-
-        {
-            let region_count = region_defs.len(space);
-            assert_eq!(substs.regions.len(space), 0);
-            for (i, lifetime) in data.lifetimes.iter().enumerate() {
-                let r = ast_region_to_region(self.tcx, lifetime);
-                if i < region_count {
-                    substs.regions.push(space, r);
-                } else if i == region_count {
-                    span_err!(self.tcx.sess, lifetime.span, E0088,
-                        "too many lifetime parameters provided: \
-                         expected {} parameter{}, found {} parameter{}",
-                        region_count,
-                        if region_count == 1 {""} else {"s"},
-                        data.lifetimes.len(),
-                        if data.lifetimes.len() == 1 {""} else {"s"});
-                    substs.regions.truncate(space, 0);
-                    break;
-                }
+            Some(&hir::ParenthesizedParameters(_)) => {
+                span_bug!(span, "parenthesized parameters cannot appear in ExprPath");
             }
-        }
-    }
-
-    /// As with
-    /// `push_explicit_angle_bracketed_parameters_from_segment_to_substs`,
-    /// but intended for `Foo(A,B) -> C` form. This expands to
-    /// roughly the same thing as `Foo<(A,B),C>`. One important
-    /// difference has to do with the treatment of anonymous
-    /// regions, which are translated into bound regions (NYI).
-    fn push_explicit_parenthesized_parameters_from_segment_to_substs(&self,
-        space: subst::ParamSpace,
-        span: Span,
-        type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
-        data: &hir::ParenthesizedParameterData,
-        substs: &mut Substs<'tcx>)
-    {
-        let type_count = type_defs.len(space);
-        if type_count < 2 {
-            span_err!(self.tcx.sess, span, E0167,
-                      "parenthesized form always supplies 2 type parameters, \
-                      but only {} parameter(s) were expected",
-                      type_count);
-        }
-
-        let input_tys: Vec<Ty> =
-            data.inputs.iter().map(|ty| self.to_ty(&ty)).collect();
-
-        let tuple_ty = self.tcx.mk_tup(input_tys);
-
-        if type_count >= 1 {
-            substs.types.push(space, tuple_ty);
-        }
-
-        let output_ty: Option<Ty> =
-            data.output.as_ref().map(|ty| self.to_ty(&ty));
-
-        let output_ty =
-            output_ty.unwrap_or(self.tcx.mk_nil());
+            None => (&[][..], &[][..], &[][..])
+        };
 
-        if type_count >= 2 {
-            substs.types.push(space, output_ty);
-        }
-    }
+        let count = |n| {
+            format!("{} parameter{}", n, if n == 1 { "" } else { "s" })
+        };
 
-    fn adjust_type_parameters(&self,
-        span: Span,
-        space: ParamSpace,
-        defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
-        require_type_space: bool,
-        substs: &mut Substs<'tcx>)
-    {
-        let provided_len = substs.types.len(space);
-        let desired = defs.get_slice(space);
-        let required_len = desired.iter()
-                              .take_while(|d| d.default.is_none())
-                              .count();
-
-        debug!("adjust_type_parameters(space={:?}, \
-               provided_len={}, \
-               desired_len={}, \
-               required_len={})",
-               space,
-               provided_len,
-               desired.len(),
-               required_len);
-
-        // Enforced by `push_explicit_parameters_from_segment_to_substs()`.
-        assert!(provided_len <= desired.len());
-
-        // Nothing specified at all: supply inference variables for
-        // everything.
-        if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) {
-            substs.types.replace(space, Vec::new());
-            for def in desired {
-                let ty_var = self.type_var_for_def(span, def, substs);
-                substs.types.push(def.space, ty_var);
-            }
-            return;
+        // Check provided lifetime parameters.
+        let lifetime_defs = generics.regions.get_slice(space);
+        if lifetimes.len() > lifetime_defs.len() {
+            let span = lifetimes[lifetime_defs.len()].span;
+            span_err!(self.tcx.sess, span, E0088,
+                      "too many lifetime parameters provided: \
+                       expected {}, found {}",
+                      count(lifetime_defs.len()),
+                      count(lifetimes.len()));
+        } else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
+            span_err!(self.tcx.sess, span, E0090,
+                      "too few lifetime parameters provided: \
+                       expected {}, found {}",
+                      count(lifetime_defs.len()),
+                      count(lifetimes.len()));
         }
 
-        // Too few parameters specified: report an error and use Err
-        // for everything.
-        if provided_len < required_len {
+        // Check provided type parameters.
+        let type_defs = generics.types.get_slice(space);
+        let required_len = type_defs.iter()
+                                    .take_while(|d| d.default.is_none())
+                                    .count();
+        if types.len() > type_defs.len() {
+            let span = types[type_defs.len()].span;
+            struct_span_err!(self.tcx.sess, span, E0087,
+                             "too many type parameters provided: \
+                              expected at most {}, found {}",
+                             count(type_defs.len()),
+                             count(types.len()))
+                .span_label(span, &format!("expected {}",
+                            count(type_defs.len()))).emit();
+
+            // To prevent derived errors to accumulate due to extra
+            // type parameters, we force instantiate_value_path to
+            // use inference variables instead of the provided types.
+            *segment = None;
+        } else if !(can_omit && types.len() == 0) && types.len() < required_len {
             let qualifier =
-                if desired.len() != required_len { "at least " } else { "" };
+                if type_defs.len() != required_len { "at least " } else { "" };
             span_err!(self.tcx.sess, span, E0089,
-                "too few type parameters provided: expected {}{} parameter{}, \
-                 found {} parameter{}",
-                qualifier, required_len,
-                if required_len == 1 {""} else {"s"},
-                provided_len,
-                if provided_len == 1 {""} else {"s"});
-            substs.types.replace(space, vec![self.tcx.types.err; desired.len()]);
-            return;
-        }
-
-        // Otherwise, add in any optional parameters that the user
-        // omitted. The case of *too many* parameters is handled
-        // already by
-        // push_explicit_parameters_from_segment_to_substs(). Note
-        // that the *default* type are expressed in terms of all prior
-        // parameters, so we have to substitute as we go with the
-        // partial substitution that we have built up.
-        for i in provided_len..desired.len() {
-            let default = desired[i].default.unwrap();
-            let default = default.subst_spanned(self.tcx, substs, Some(span));
-            substs.types.push(space, default);
-        }
-        assert_eq!(substs.types.len(space), desired.len());
-
-        debug!("Final substs: {:?}", substs);
-    }
-
-    fn adjust_region_parameters(&self,
-        span: Span,
-        space: ParamSpace,
-        defs: &VecPerParamSpace<ty::RegionParameterDef>,
-        substs: &mut Substs)
-    {
-        let provided_len = substs.regions.len(space);
-        let desired = defs.get_slice(space);
-
-        // Enforced by `push_explicit_parameters_from_segment_to_substs()`.
-        assert!(provided_len <= desired.len());
-
-        // If nothing was provided, just use inference variables.
-        if provided_len == 0 {
-            substs.regions.replace(
-                space,
-                self.region_vars_for_defs(span, desired));
-            return;
+                      "too few type parameters provided: \
+                       expected {}{}, found {}",
+                      qualifier,
+                      count(required_len),
+                      count(types.len()));
         }
 
-        // If just the right number were provided, everybody is happy.
-        if provided_len == desired.len() {
-            return;
+        if !bindings.is_empty() {
+            span_err!(self.tcx.sess, bindings[0].span, E0182,
+                      "unexpected binding of associated item in expression path \
+                       (only allowed in type paths)");
         }
-
-        // Otherwise, too few were provided. Report an error and then
-        // use inference variables.
-        span_err!(self.tcx.sess, span, E0090,
-            "too few lifetime parameters provided: expected {} parameter{}, \
-             found {} parameter{}",
-            desired.len(),
-            if desired.len() == 1 {""} else {"s"},
-            provided_len,
-            if provided_len == 1 {""} else {"s"});
-
-        substs.regions.replace(
-            space,
-            self.region_vars_for_defs(span, desired));
     }
 
     fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 337b87ce994..fe1cb3d6bad 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4018,7 +4018,7 @@ register_diagnostics! {
 //  E0141,
 //  E0159, // use of trait `{}` as struct constructor
 //  E0163, // merged into E0071
-    E0167,
+//  E0167,
 //  E0168,
 //  E0173, // manual implementations of unboxed closure traits are experimental
 //  E0174,
@@ -4053,7 +4053,7 @@ register_diagnostics! {
 //  E0235, // structure constructor specifies a structure of type but
 //  E0236, // no lang item for range syntax
 //  E0237, // no lang item for range syntax
-    E0238, // parenthesized parameters may only be used with a trait
+//  E0238, // parenthesized parameters may only be used with a trait
 //  E0239, // `next` method of `Iterator` trait has unexpected type
 //  E0240,
 //  E0241,