From 89fe4df9c7095f3f449a89bae97d087e7df08fcb Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 5 Mar 2017 10:15:58 -0700 Subject: [PATCH] Unify both conflicting default searches into one. --- src/librustc_typeck/check/mod.rs | 133 ++++++++++++------------------- 1 file changed, 50 insertions(+), 83 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5273b022ad21a..ae4cb48b7c60e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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) - }); - - // 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) - }; + // 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) + }; - 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>, - default_map: &FxHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, - conflict: Ty<'tcx>) - -> Option> { + fn apply_defaults_and_return_conflicts<'b>( + &'b self, + unbound_vars: &'b FxHashSet>, + default_map: &'b FxHashMap<&'b Ty<'tcx>, type_variable::Default<'tcx>>, + conflict: Option>, + ) -> impl Iterator, 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) {