rustc_typeck: use Substs::from_generics instead of manually building them.

This commit is contained in:
Eduard Burtescu 2016-08-17 04:05:00 +03:00
parent 4b25f08512
commit bfdfa1ce1d
4 changed files with 305 additions and 540 deletions

View file

@ -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,

View file

@ -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();
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<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;
}
}
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<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"

View file

@ -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);
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<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);
/// 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<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;
}
}
// 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<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());
if type_count >= 2 {
substs.types.push(space, output_ty);
}
}
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;
}
// 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<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;
}
// 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<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)

View file

@ -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,