Skip to content

Commit bbcb13d

Browse files
jroeschJared Roesch
authored andcommitted
Implement Default TyParam fallback
This patch allows type parameter defaults to influence type inference. This is a possible breaking change since it effects the way type inference works and will have different behavior when mixing defaults and literal fallback.
1 parent 7276d8b commit bbcb13d

File tree

14 files changed

+340
-45
lines changed

14 files changed

+340
-45
lines changed

src/librustc/middle/infer/mod.rs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
9595
normalize: bool,
9696

9797
err_count_on_creation: usize,
98+
99+
// Default Type Parameter fallbacks
100+
pub defaults: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
98101
}
99102

100103
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
@@ -350,7 +353,8 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
350353
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
351354
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
352355
normalize: false,
353-
err_count_on_creation: tcx.sess.err_count()
356+
err_count_on_creation: tcx.sess.err_count(),
357+
defaults: RefCell::new(FnvHashMap()),
354358
}
355359
}
356360

@@ -653,6 +657,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
653657
}
654658
}
655659

660+
pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
661+
let mut variables = Vec::new();
662+
663+
let unbound_ty_vars = self.type_variables
664+
.borrow()
665+
.unsolved_variables()
666+
.into_iter().map(|t| self.tcx.mk_var(t));
667+
668+
let unbound_int_vars = self.int_unification_table
669+
.borrow_mut()
670+
.unsolved_variables()
671+
.into_iter().map(|v| self.tcx.mk_int_var(v));
672+
673+
let unbound_float_vars = self.float_unification_table
674+
.borrow_mut()
675+
.unsolved_variables()
676+
.into_iter().map(|v| self.tcx.mk_float_var(v));
677+
678+
variables.extend(unbound_ty_vars);
679+
variables.extend(unbound_int_vars);
680+
variables.extend(unbound_float_vars);
681+
return variables;
682+
}
683+
656684
fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
657685
-> CombineFields<'a, 'tcx> {
658686
CombineFields {infcx: self,
@@ -996,16 +1024,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
9961024
.collect()
9971025
}
9981026

1027+
pub fn type_vars_for_defs(&self,
1028+
defs: &[ty::TypeParameterDef<'tcx>])
1029+
-> Vec<ty::Ty<'tcx>> {
1030+
let mut vars = Vec::with_capacity(defs.len());
1031+
1032+
for def in defs.iter() {
1033+
let ty_var = self.next_ty_var();
1034+
match def.default {
1035+
None => {},
1036+
Some(default) => { self.defaults.borrow_mut().insert(ty_var, default); }
1037+
}
1038+
vars.push(ty_var)
1039+
}
1040+
1041+
vars
1042+
}
1043+
9991044
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
10001045
/// type/region parameter to a fresh inference variable.
10011046
pub fn fresh_substs_for_generics(&self,
10021047
span: Span,
10031048
generics: &ty::Generics<'tcx>)
10041049
-> subst::Substs<'tcx>
10051050
{
1006-
let type_params =
1007-
generics.types.map(
1008-
|_| self.next_ty_var());
1051+
let mut type_params = subst::VecPerParamSpace::empty();
1052+
1053+
for space in subst::ParamSpace::all().iter() {
1054+
type_params.replace(*space, self.type_vars_for_defs(generics.types.get_slice(*space)))
1055+
}
1056+
10091057
let region_params =
10101058
generics.regions.map(
10111059
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
@@ -1027,8 +1075,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10271075
assert!(generics.regions.len(subst::SelfSpace) == 0);
10281076
assert!(generics.regions.len(subst::FnSpace) == 0);
10291077

1030-
let type_parameter_count = generics.types.len(subst::TypeSpace);
1031-
let type_parameters = self.next_ty_vars(type_parameter_count);
1078+
let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
1079+
let type_parameters = self.type_vars_for_defs(type_parameter_defs);
10321080

10331081
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
10341082
let regions = self.region_vars_for_defs(span, region_param_defs);
@@ -1268,6 +1316,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12681316
self.report_and_explain_type_error(trace, err);
12691317
}
12701318

1319+
pub fn report_conflicting_default_types(&self,
1320+
span: Span,
1321+
expected: Ty<'tcx>,
1322+
actual: Ty<'tcx>) {
1323+
let trace = TypeTrace {
1324+
origin: Misc(span),
1325+
values: Types(ty::expected_found {
1326+
expected: expected,
1327+
found: actual
1328+
})
1329+
};
1330+
1331+
self.report_and_explain_type_error(trace, &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found {
1332+
expected: expected,
1333+
found: actual
1334+
}));
1335+
}
1336+
12711337
pub fn replace_late_bound_regions_with_fresh_var<T>(
12721338
&self,
12731339
span: Span,

src/librustc/middle/infer/type_variable.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
195195

196196
escaping_types
197197
}
198+
199+
pub fn unsolved_variables(&self) -> Vec<ty::TyVid> {
200+
self.values.iter().enumerate().filter_map(|(i, value)|
201+
match &value.value {
202+
&TypeVariableValue::Known(_) => None,
203+
&TypeVariableValue::Bounded(_) => Some(ty::TyVid { index: i as u32 })
204+
}
205+
).collect()
206+
}
198207
}
199208

200209
impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {

src/librustc/middle/ty.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,7 @@ pub enum TypeError<'tcx> {
20682068
ConvergenceMismatch(ExpectedFound<bool>),
20692069
ProjectionNameMismatched(ExpectedFound<ast::Name>),
20702070
ProjectionBoundsLength(ExpectedFound<usize>),
2071+
terr_ty_param_default_mismatch(expected_found<Ty<'tcx>>)
20712072
}
20722073

20732074
/// Bounds suitable for an existentially quantified type parameter
@@ -5080,6 +5081,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
50805081
write!(f, "expected {} associated type bindings, found {}",
50815082
values.expected,
50825083
values.found)
5084+
},
5085+
terr_ty_param_default_mismatch(ref values) => {
5086+
write!(f, "conflicting type parameter defaults {} {}",
5087+
values.expected,
5088+
values.found)
50835089
}
50845090
}
50855091
}
@@ -5437,6 +5443,11 @@ impl<'tcx> ctxt<'tcx> {
54375443
&format!("consider boxing your closure and/or \
54385444
using it as a trait object"));
54395445
}
5446+
},
5447+
terr_ty_param_default_mismatch(expected) => {
5448+
self.sess.span_note(sp,
5449+
&format!("found conflicting defaults {:?} {:?}",
5450+
expected.expected, expected.found))
54405451
}
54415452
_ => {}
54425453
}

src/librustc_data_structures/unify/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,5 +339,11 @@ impl<'tcx,K,V> UnificationTable<K>
339339
pub fn probe(&mut self, a_id: K) -> Option<V> {
340340
self.get(a_id).value.clone()
341341
}
342-
}
343342

343+
pub fn unsolved_variables(&mut self) -> Vec<K> {
344+
self.values
345+
.iter()
346+
.filter_map(|vv| if vv.value.is_some() { None } else { Some(vv.key()) })
347+
.collect()
348+
}
349+
}

src/librustc_typeck/check/method/confirm.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
309309
// If they were not explicitly supplied, just construct fresh
310310
// variables.
311311
let num_supplied_types = supplied_method_types.len();
312-
let num_method_types = pick.item.as_opt_method().unwrap()
313-
.generics.types.len(subst::FnSpace);
312+
let method = pick.item.as_opt_method().unwrap();
313+
let method_types = method.generics.types.get_slice(subst::FnSpace);
314+
let num_method_types = method_types.len();
315+
314316
let method_types = {
315317
if num_supplied_types == 0 {
316-
self.fcx.infcx().next_ty_vars(num_method_types)
318+
self.fcx.infcx().type_vars_for_defs(method_types)
317319
} else if num_method_types == 0 {
318320
span_err!(self.tcx().sess, self.span, E0035,
319321
"does not take type parameters");
320-
self.fcx.infcx().next_ty_vars(num_method_types)
322+
self.fcx.infcx().type_vars_for_defs(method_types)
321323
} else if num_supplied_types != num_method_types {
322324
span_err!(self.tcx().sess, self.span, E0036,
323325
"incorrect number of type parameters given for this method");

src/librustc_typeck/check/method/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,16 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
167167

168168
let trait_def = fcx.tcx().lookup_trait_def(trait_def_id);
169169

170-
let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace);
170+
let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
171+
let expected_number_of_input_types = type_parameter_defs.len();
171172
let input_types = match opt_input_types {
172173
Some(input_types) => {
173174
assert_eq!(expected_number_of_input_types, input_types.len());
174175
input_types
175176
}
176177

177178
None => {
178-
fcx.inh.infcx.next_ty_vars(expected_number_of_input_types)
179+
fcx.inh.infcx.type_vars_for_defs(type_parameter_defs)
179180
}
180181
};
181182

src/librustc_typeck/check/method/probe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,8 +1207,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
12071207
!method.generics.regions.is_empty_in(subst::FnSpace)
12081208
{
12091209
let method_types =
1210-
self.infcx().next_ty_vars(
1211-
method.generics.types.len(subst::FnSpace));
1210+
self.infcx().type_vars_for_defs(
1211+
method.generics.types.get_slice(subst::FnSpace));
12121212

12131213
// In general, during probe we erase regions. See
12141214
// `impl_self_ty()` for an explanation.

0 commit comments

Comments
 (0)