From bfdfa1ce1d7275bbdb89ecb116bf765f19b204e1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 17 Aug 2016 04:05:00 +0300 Subject: [PATCH] rustc_typeck: use Substs::from_generics instead of manually building them. --- src/librustc/infer/mod.rs | 7 - src/librustc_typeck/astconv.rs | 383 ++++++++++-------------- src/librustc_typeck/check/mod.rs | 451 ++++++++++------------------- src/librustc_typeck/diagnostics.rs | 4 +- 4 files changed, 305 insertions(+), 540 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 951570679e08..1e360cd43da1 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 { - 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 ed4ea3c937b9..11ca012fdeda 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) - -> Substs<'tcx> + parameters: &hir::PathParameters, + self_ty: Option>) + -> (&'tcx Substs<'tcx>, Vec>) { 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>, - types_provided: Vec>, - region_substs: Substs<'tcx>) - -> Substs<'tcx> - { - let tcx = self.tcx(); - - 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); - } - assert!(type_substs.len() >= required_ty_param_count && - type_substs.len() <= formal_ty_param_count); - - let mut substs = region_substs; // 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()); + + // 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); + } 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 { + 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; + } + } + + 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. + // 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); - } + // We've already errored above about the mismatch. + tcx.types.err + } + }); + + 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 + })] + } + }; 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>, - param_mode: PathParamMode, - ty_param_defs: &[ty::TypeParameterDef<'tcx>], - mut substs: Substs<'tcx>, - self_ty: Option>) - -> Vec> - { - 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; - } - } - - true - }; - - 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 - } - } - - fn convert_angle_bracketed_parameters(&self, - rscope: &RegionScope, - span: Span, - decl_generics: &ty::Generics<'tcx>, - data: &hir::AngleBracketedParameterData) - -> (Substs<'tcx>, - Vec>, - Vec>) - { - 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, ®ion_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>, - Vec>) + -> (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, ®ion_substs, a_t)) - .collect::>>(); - + 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 b5018d51b7f5..c41bb1930d45 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 { - // `::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 { - // `::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]; + // `::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 `>::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); - self.adjust_region_parameters(span, space, region_defs, &mut substs); - assert_eq!(substs.regions.len(space), region_defs.len(space)); - } + 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 => &[] + }; + + 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>, - region_defs: &VecPerParamSpace, - 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); + /// 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[..]) } + Some(&hir::ParenthesizedParameters(_)) => { + span_bug!(span, "parenthesized parameters cannot appear in ExprPath"); + } + None => (&[][..], &[][..], &[][..]) + }; - 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); - } - } - } + let count = |n| { + format!("{} parameter{}", n, if n == 1 { "" } else { "s" }) + }; - fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(&self, - space: subst::ParamSpace, - type_defs: &VecPerParamSpace>, - region_defs: &VecPerParamSpace, - 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; - } - } + // 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())); } - if !data.bindings.is_empty() { - span_err!(self.tcx.sess, data.bindings[0].span, E0182, + // 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 type_defs.len() != required_len { "at least " } else { "" }; + span_err!(self.tcx.sess, span, E0089, + "too few type parameters provided: \ + expected {}{}, found {}", + qualifier, + count(required_len), + count(types.len())); + } + + 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)"); } - - { - 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; - } - } - } - } - - /// 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>, - 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 = - 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 = - data.output.as_ref().map(|ty| self.to_ty(&ty)); - - let output_ty = - output_ty.unwrap_or(self.tcx.mk_nil()); - - if type_count >= 2 { - substs.types.push(space, output_ty); - } - } - - fn adjust_type_parameters(&self, - span: Span, - space: ParamSpace, - defs: &VecPerParamSpace>, - 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; - } - - // Too few parameters specified: report an error and use Err - // for everything. - if provided_len < required_len { - let qualifier = - if desired.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, - 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; - } - - // If just the right number were provided, everybody is happy. - if provided_len == desired.len() { - return; - } - - // 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(&self, sp: Span, ty: Ty<'tcx>, f: F) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 337b87ce994a..fe1cb3d6badc 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,