From 155ef41c8483277d4de106ea372b94da6b786539 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 4 Mar 2017 16:44:02 -0700 Subject: [PATCH 1/3] Fix normalization error. --- src/librustc_typeck/check/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8957bad098..5273b022ad2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2122,10 +2122,12 @@ fn find_conflicting_default(&self, 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) { + default_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { result = Some(default); From 89fe4df9c7095f3f449a89bae97d087e7df08fcb Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 5 Mar 2017 10:15:58 -0700 Subject: [PATCH 2/3] Unify both conflicting default searches into one. --- src/librustc_typeck/check/mod.rs | 131 ++++++++++++------------------- 1 file changed, 49 insertions(+), 82 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5273b022ad2..ae4cb48b7c6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2007,37 +2007,10 @@ fn new_select_all_obligations_and_apply_defaults(&self) { // 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 @@ fn new_select_all_obligations_and_apply_defaults(&self) { } }); - 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 @@ fn new_select_all_obligations_and_apply_defaults(&self) { // 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 @@ fn find_conflicting_default(&self, 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) { From 403ae37ce8f680e378dc77904a27453df0867b99 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 5 Mar 2017 10:36:31 -0700 Subject: [PATCH 3/3] Remove reference to Ty. --- src/librustc_typeck/check/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae4cb48b7c6..2b9ccf6d3e2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1935,10 +1935,10 @@ fn new_select_all_obligations_and_apply_defaults(&self) { // We must collect the defaults *before* we do any unification. Because we have // directly attached defaults to the type variables any unification that occurs // will erase defaults causing conflicting defaults to be completely ignored. - let default_map: FxHashMap<_, _> = + let default_map: FxHashMap, _> = unsolved_variables .iter() - .filter_map(|t| self.default(t).map(|d| (t, d))) + .filter_map(|t| self.default(t).map(|d| (*t, d))) .collect(); let mut unbound_tyvars = FxHashSet(); @@ -2068,7 +2068,7 @@ fn new_select_all_obligations_and_apply_defaults(&self) { fn apply_defaults_and_return_conflicts<'b>( &'b self, unbound_vars: &'b FxHashSet>, - default_map: &'b FxHashMap<&'b Ty<'tcx>, type_variable::Default<'tcx>>, + default_map: &'b FxHashMap, type_variable::Default<'tcx>>, conflict: Option>, ) -> impl Iterator, type_variable::Default<'tcx>)> + 'b { use rustc::ty::error::UnconstrainedNumeric::Neither; @@ -2087,7 +2087,7 @@ fn apply_defaults_and_return_conflicts<'b>( 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);