Unify both conflicting default searches into one.

This commit is contained in:
Mark Simulacrum 2017-03-05 10:15:58 -07:00
parent 155ef41c84
commit 89fe4df9c7
1 changed files with 49 additions and 82 deletions

View File

@ -2007,37 +2007,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// we will rollback the inference context to its prior state so we can probe
// for conflicts and correctly report them.
let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
for ty in &unbound_tyvars {
if self.type_var_diverges(ty) {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
self.tcx.mk_diverging_default());
} else {
match self.type_is_unconstrained_numeric(ty) {
UnconstrainedInt => {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
}
Neither => {
if let Some(default) = default_map.get(ty) {
let default = default.clone();
let default_ty = self.normalize_associated_types_in(
default.origin_span, &default.ty);
match self.eq_types(false,
&self.misc(default.origin_span),
ty,
default_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => conflicts.push((*ty, default)),
}
}
}
}
}
}
conflicts.extend(
self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None)
);
// If there are conflicts we rollback, otherwise commit
if conflicts.len() > 0 {
@ -2047,37 +2020,41 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
});
if conflicts.len() > 0 {
// Loop through each conflicting default, figuring out the default that caused
// a unification failure and then report an error for each.
for (conflict, default) in conflicts {
let conflicting_default =
self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
.unwrap_or(type_variable::Default {
ty: self.next_ty_var(
TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
origin_span: syntax_pos::DUMMY_SP,
// what do I put here?
def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID)
});
// Loop through each conflicting default, figuring out the default that caused
// a unification failure and then report an error for each.
for (conflict, default) in conflicts {
let conflicting_default =
self.apply_defaults_and_return_conflicts(
&unbound_tyvars,
&default_map,
Some(conflict)
)
.last()
.map(|(_, tv)| tv)
.unwrap_or(type_variable::Default {
ty: self.next_ty_var(
TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
origin_span: syntax_pos::DUMMY_SP,
// what do I put here?
def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID)
});
// This is to ensure that we elimnate any non-determinism from the error
// reporting by fixing an order, it doesn't matter what order we choose
// just that it is consistent.
let (first_default, second_default) =
if default.def_id < conflicting_default.def_id {
(default, conflicting_default)
} else {
(conflicting_default, default)
};
// This is to ensure that we elimnate any non-determinism from the error
// reporting by fixing an order, it doesn't matter what order we choose
// just that it is consistent.
let (first_default, second_default) =
if default.def_id < conflicting_default.def_id {
(default, conflicting_default)
} else {
(conflicting_default, default)
};
self.report_conflicting_default_types(
first_default.origin_span,
self.body_id,
first_default,
second_default)
}
self.report_conflicting_default_types(
first_default.origin_span,
self.body_id,
first_default,
second_default)
}
}
@ -2088,39 +2065,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// apply the default that caused conflict first to a local version of the type variable
// table then apply defaults until we find a conflict. That default must be the one
// that caused conflict earlier.
fn find_conflicting_default(&self,
unbound_vars: &FxHashSet<Ty<'tcx>>,
default_map: &FxHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
conflict: Ty<'tcx>)
-> Option<type_variable::Default<'tcx>> {
fn apply_defaults_and_return_conflicts<'b>(
&'b self,
unbound_vars: &'b FxHashSet<Ty<'tcx>>,
default_map: &'b FxHashMap<&'b Ty<'tcx>, type_variable::Default<'tcx>>,
conflict: Option<Ty<'tcx>>,
) -> impl Iterator<Item=(Ty<'tcx>, type_variable::Default<'tcx>)> + 'b {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
// Ensure that we apply the conflicting default first
let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1);
unbound_tyvars.push(conflict);
unbound_tyvars.extend(unbound_vars.iter());
let mut result = None;
// We run the same code as above applying defaults in order, this time when
// we find the conflict we just return it for error reporting above.
// We also run this inside snapshot that never commits so we can do error
// reporting for more then one conflict.
for ty in &unbound_tyvars {
conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| {
if self.type_var_diverges(ty) {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
self.demand_eqtype(syntax_pos::DUMMY_SP, ty,
self.tcx.mk_diverging_default());
} else {
match self.type_is_unconstrained_numeric(ty) {
UnconstrainedInt => {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32)
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32)
},
UnconstrainedFloat => {
self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64)
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64)
},
Neither => {
if let Some(default) = default_map.get(ty) {
if let Some(default) = default_map.get(&ty) {
let default = default.clone();
let default_ty = self.normalize_associated_types_in(
default.origin_span, &default.ty);
@ -2130,16 +2097,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
default_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
result = Some(default);
return Some((ty, default));
}
}
}
}
}
}
}
return result;
None
})
}
fn select_all_obligations_or_error(&self) {