From 7e8509f23b746dcf5badec6db80d277247a02114 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 10 Aug 2015 17:56:02 -0700 Subject: [PATCH 01/35] Change fallback priorties to prefer user defaults --- src/librustc_typeck/check/mod.rs | 209 ++++++++++++++++++ .../run-pass/default_over_literal_fallback.rs | 15 ++ 2 files changed, 224 insertions(+) create mode 100755 src/test/run-pass/default_over_literal_fallback.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 09dd334a62d8a..582a764202c73 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2185,6 +2185,215 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); } + fn new_select_all_obligations_and_apply_defaults(&self) { + use middle::ty::error::UnconstrainedNumeric::Neither; + use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + // For the time being this errs on the side of being memory wasteful but provides better + // error reporting. + // let type_variables = self.infcx().type_variables.clone(); + + // It is a possible that this algorithm will have to run an arbitrary number of times + // to terminate so we bound it by the compiler's recursion limit. + for _ in (0..self.tcx().sess.recursion_limit.get()) { + // First we try to solve all obligations, it is possible that the last iteration + // has made it possible to make more progress. + self.select_obligations_where_possible(); + + let mut conflicts = Vec::new(); + + // Collect all unsolved type, integral and floating point variables. + let unsolved_variables = self.inh.infcx.unsolved_variables(); + + // 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: FnvHashMap<_, _> = + unsolved_variables + .iter() + .filter_map(|t| self.infcx().default(t).map(|d| (t, d))) + .collect(); + + let mut unbound_tyvars = HashSet::new(); + + debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); + + // Examine all unsolved variables, and narrow them to the set that have applicable + // defaults. We want to process any unsolved variables that have either an explicit + // user default, literal fallback, or are diverging. + for ty in &unsolved_variables { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if let Some(_default) = default_map.get(ty) { + + debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + ty, _default); + + match resolved.sty { + ty::TyInfer(_) => { + unbound_tyvars.insert(*ty); + } + _ => {} + } + } else { + if self.infcx().type_var_diverges(resolved) { + unbound_tyvars.insert(ty); + } else { + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt | UnconstrainedFloat => { + unbound_tyvars.insert(ty); + }, + Neither => {} + } + } + } + } + + // If there are no more fallbacks to apply at this point we have applied all possible + // defaults and type inference will procede as normal. + if unbound_tyvars.is_empty() { + break; + } + + // Finally we loop through each of the unbound type variables and unify them with + // the proper fallback, reporting a conflicting default error if any of the + // unifications fail. + // + // We know that a conflict must be due to multiple applicable defaults, because the + // variable would only be in `unbound_tyvars` and have been previously unified with + // another type if we had applied a default. + + // We wrap all of this in a transaction for error reporting. If we detect a conflict + // we will rollback to the previous state so we can check what conflicts and + // correctly report them. + let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { + for ty in &unbound_tyvars { + if let Some(default) = default_map.get(ty) { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + conflicts.push((*ty, default)); + } + } + } else { + match self.infcx().type_is_unconstrained_numeric(ty) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => {} + } + } + } + + + // If there are conflicts we rollback, otherwise commit + if conflicts.len() > 0 { + Err(()) + } else { + Ok(()) + } + }); + + // Finally for any leftover variables that diverage we should apply the unit fallback rules. + for ty in &unbound_tyvars { + if self.infcx().type_var_diverges(ty) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } + } + + 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.infcx().next_ty_var(), + origin_span: codemap::DUMMY_SP, + def_id: DefId::local(0) // what do I put here? + }); + + // 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.infcx().report_conflicting_default_types( + first_default.origin_span, + first_default, + second_default) + } + } + } + + self.select_obligations_where_possible(); + } + + // For use in error handling related to default type parameter fallback. We explicitly + // 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: &HashSet>, + default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, + conflict: Ty<'tcx>) + -> Option> { + use middle::ty::error::UnconstrainedNumeric::Neither; + use middle::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 { + if self.infcx().type_var_diverges(ty) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(ty) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + }, + Neither => { + if let Some(default) = default_map.get(ty) { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + result = Some(default); + } + } + } + } + } + } + } + + return result; + } + fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); diff --git a/src/test/run-pass/default_over_literal_fallback.rs b/src/test/run-pass/default_over_literal_fallback.rs new file mode 100755 index 0000000000000..bc5478240a272 --- /dev/null +++ b/src/test/run-pass/default_over_literal_fallback.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +fn foo(t: T) -> usize { std::mem::size_of_val(&t) } + +fn main() { assert_eq!(foo(22), std::mem::size_of::()) } From f20a4d8186ac1e3bf177701a797b1b2860cb056a Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 19 Aug 2015 00:42:09 -0700 Subject: [PATCH 02/35] Refactor default type parameter fallback The previous implementation was not very clear, this commit attempts to clarify and clean up the code that applies all defaults. --- src/librustc_typeck/check/mod.rs | 188 +++++++++++++++---------------- 1 file changed, 89 insertions(+), 99 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 582a764202c73..076f8ef58ba30 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -91,6 +91,7 @@ use rustc_back::slice::ref_slice; use namespace::Namespace; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; +use rustc::infer::type_variable::Default; use rustc::middle::region; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; @@ -1641,9 +1642,27 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { }; Some(self.next_region_var(v)) } + fn ty_infer(&self, + ty_param_def: Option>, + substs: Option<&mut subst::Substs<'tcx>>, + space: Option, + span: Span) -> Ty<'tcx> { + // Grab the default doing subsitution + let default = ty_param_def.and_then(|def| { + def.default.map(|ty| type_variable::UserDefault { + ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), + origin_span: span, + def_id: def.default_def_id + }) + }); + + let ty_var = self.infcx().next_ty_var_with_default(default); - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.next_ty_var(TypeVariableOrigin::TypeInference(span)) + // Finally we add the type variable to the substs + match substs { + None => ty_var, + Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var } + } } fn ty_infer_for_def(&self, @@ -2203,54 +2222,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut conflicts = Vec::new(); // Collect all unsolved type, integral and floating point variables. - let unsolved_variables = self.inh.infcx.unsolved_variables(); + let unsolved_variables = self.inh.infcx.candidates_for_defaulting(); - // 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: FnvHashMap<_, _> = - unsolved_variables - .iter() - .filter_map(|t| self.infcx().default(t).map(|d| (t, d))) - .collect(); - - let mut unbound_tyvars = HashSet::new(); - - debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); + let mut has_user_default = HashSet::new(); + let mut has_literal_fallback = HashSet::new(); + let mut is_diverging = HashSet::new(); // Examine all unsolved variables, and narrow them to the set that have applicable // defaults. We want to process any unsolved variables that have either an explicit // user default, literal fallback, or are diverging. - for ty in &unsolved_variables { + for &(ref ty, ref default) in &unsolved_variables { let resolved = self.infcx().resolve_type_vars_if_possible(ty); - if let Some(_default) = default_map.get(ty) { - - debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", - ty, _default); + match default { + &Default::User(ref user_default) => { + debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + ty, default); - match resolved.sty { - ty::TyInfer(_) => { - unbound_tyvars.insert(*ty); - } - _ => {} + has_user_default.insert((*ty, user_default.clone())); + }, + &Default::Float | + &Default::Integer => { + has_literal_fallback.insert(*ty); } - } else { - if self.infcx().type_var_diverges(resolved) { - unbound_tyvars.insert(ty); - } else { - match self.infcx().type_is_unconstrained_numeric(resolved) { - UnconstrainedInt | UnconstrainedFloat => { - unbound_tyvars.insert(ty); - }, - Neither => {} - } + &Default::Diverging => { + is_diverging.insert(*ty); } + &Default::None => {} } } // If there are no more fallbacks to apply at this point we have applied all possible // defaults and type inference will procede as normal. - if unbound_tyvars.is_empty() { + if has_user_default.len() == 0 && + has_literal_fallback.len() == 0 && + is_diverging.len() == 0 { break; } @@ -2266,26 +2271,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we will rollback to the previous state so we can check what conflicts and // correctly report them. let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { - for ty in &unbound_tyvars { - if let Some(default) = default_map.get(ty) { - let default = default.clone(); - match infer::mk_eqty(self.infcx(), false, - infer::Misc(default.origin_span), - ty, default.ty) { - Ok(()) => {} - Err(_) => { - conflicts.push((*ty, default)); - } - } - } else { - match self.infcx().type_is_unconstrained_numeric(ty) { - UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) - }, - UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) - } - Neither => {} + for &(ref ty, ref default) in &has_user_default { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(codemap::DUMMY_SP), // default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + conflicts.push((*ty, default)); } } } @@ -2299,25 +2292,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); - // Finally for any leftover variables that diverage we should apply the unit fallback rules. - for ty in &unbound_tyvars { - if self.infcx().type_var_diverges(ty) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); - } - } - 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 { + for conflict in conflicts { let conflicting_default = - self.find_conflicting_default(&unbound_tyvars, &default_map, conflict) - .unwrap_or(type_variable::Default { + self.find_conflicting_default(&has_user_default, &conflict) + .unwrap_or(type_variable::UserDefault { ty: self.infcx().next_ty_var(), origin_span: codemap::DUMMY_SP, def_id: DefId::local(0) // what do I put here? }); + let default = conflict.1; + // 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. @@ -2335,6 +2323,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { second_default) } } + + for ty in &has_literal_fallback { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => {} + } + } + + // Finally for any leftover variables that diverage + // we should apply the unit fallback rules. + for ty in &is_diverging { + if self.infcx().type_var_diverges(ty) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } + } } self.select_obligations_where_possible(); @@ -2345,17 +2354,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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: &HashSet>, - default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, - conflict: Ty<'tcx>) - -> Option> { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - + tys_with_defaults: &HashSet<(Ty<'tcx>, type_variable::UserDefault<'tcx>)>, + conflict: &(Ty<'tcx>, type_variable::UserDefault<'tcx>)) + -> Option> { // Ensure that we apply the conflicting default first - let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1); + let mut unbound_tyvars = Vec::with_capacity(tys_with_defaults.len() + 1); unbound_tyvars.push(conflict); - unbound_tyvars.extend(unbound_vars.iter()); + unbound_tyvars.extend(tys_with_defaults.iter()); let mut result = None; // We run the same code as above applying defaults in order, this time when @@ -2363,30 +2368,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 { - if self.infcx().type_var_diverges(ty) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); - } else { - match self.infcx().type_is_unconstrained_numeric(ty) { - UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) - }, - UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) - }, - Neither => { - if let Some(default) = default_map.get(ty) { - let default = default.clone(); - match infer::mk_eqty(self.infcx(), false, - infer::Misc(default.origin_span), - ty, default.ty) { - Ok(()) => {} - Err(_) => { - result = Some(default); - } - } - } - } + for &(ref ty, ref default) in tys_with_defaults { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(codemap::DUMMY_SP), // default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + result = Some(default); + break; } } } From 9b07e1b4a7f0df0971479f50b8f47fcf8c0152b2 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 19 Aug 2015 00:48:23 -0700 Subject: [PATCH 03/35] Address nits and add assertation --- src/librustc_typeck/check/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 076f8ef58ba30..c86b7abdf4d49 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2222,7 +2222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut conflicts = Vec::new(); // Collect all unsolved type, integral and floating point variables. - let unsolved_variables = self.inh.infcx.candidates_for_defaulting(); + let defaults_to_apply = self.inh.infcx.candidates_for_defaulting(); let mut has_user_default = HashSet::new(); let mut has_literal_fallback = HashSet::new(); @@ -2231,8 +2231,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Examine all unsolved variables, and narrow them to the set that have applicable // defaults. We want to process any unsolved variables that have either an explicit // user default, literal fallback, or are diverging. - for &(ref ty, ref default) in &unsolved_variables { - let resolved = self.infcx().resolve_type_vars_if_possible(ty); + for &(ref ty, ref default) in &defaults_to_apply { + // We should NEVER process anything but a TyInfer. + assert!(match ty.sty { ty::TyInfer(_) => true, _ => false }); match default { &Default::User(ref user_default) => { debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", @@ -2324,6 +2325,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + // Apply integer and floating point fallbacks to any variables that + // weren't solved by the previous phase where we applied user defaults. for ty in &has_literal_fallback { let resolved = self.infcx().resolve_type_vars_if_possible(ty); match self.infcx().type_is_unconstrained_numeric(resolved) { From b29ba68b979e632811456ef4b36abc3dd47a8cc2 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 19 Aug 2015 01:09:41 -0700 Subject: [PATCH 04/35] Fix tidy --- src/librustc_typeck/check/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c86b7abdf4d49..1822c425d3d05 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2234,10 +2234,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for &(ref ty, ref default) in &defaults_to_apply { // We should NEVER process anything but a TyInfer. assert!(match ty.sty { ty::TyInfer(_) => true, _ => false }); + match default { &Default::User(ref user_default) => { - debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", - ty, default); + debug!("select_all_obligations_and_apply_defaults: \ + ty: {:?} with default: {:?}", ty, default); has_user_default.insert((*ty, user_default.clone())); }, @@ -2357,9 +2358,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // table then apply defaults until we find a conflict. That default must be the one // that caused conflict earlier. fn find_conflicting_default(&self, - tys_with_defaults: &HashSet<(Ty<'tcx>, type_variable::UserDefault<'tcx>)>, - conflict: &(Ty<'tcx>, type_variable::UserDefault<'tcx>)) - -> Option> { + tys_with_defaults: &HashSet<(Ty<'tcx>, type_variable::UserDefault<'tcx>)>, + conflict: &(Ty<'tcx>, type_variable::UserDefault<'tcx>)) + -> Option> { // Ensure that we apply the conflicting default first let mut unbound_tyvars = Vec::with_capacity(tys_with_defaults.len() + 1); unbound_tyvars.push(conflict); From 233397e050357a11b14f2dde4a931fcfad8ff3d5 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 24 Aug 2015 23:42:30 -0700 Subject: [PATCH 05/35] Ensure defaults are normalized after application Thanks to @eddyb for bringing this bug to my attention. --- src/librustc_typeck/check/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1822c425d3d05..5093b0f9100a1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2275,9 +2275,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { for &(ref ty, ref default) in &has_user_default { let default = default.clone(); + let normalized_default = self.inh.normalize_associated_types_in(codemap::DUMMY_SP, 0, &default.ty); match infer::mk_eqty(self.infcx(), false, infer::Misc(codemap::DUMMY_SP), // default.origin_span), - ty, default.ty) { + ty, normalized_default) { Ok(()) => {} Err(_) => { conflicts.push((*ty, default)); @@ -2374,9 +2375,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // reporting for more then one conflict. for &(ref ty, ref default) in tys_with_defaults { let default = default.clone(); + let normalized_default = self.inh.normalize_associated_types_in(codemap::DUMMY_SP, 0, &default.ty); match infer::mk_eqty(self.infcx(), false, infer::Misc(codemap::DUMMY_SP), // default.origin_span), - ty, default.ty) { + ty, normalized_default) { Ok(()) => {} Err(_) => { result = Some(default); From bff6d6b99f6f6d65cb3bdccef43df8d91077db67 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 3 Sep 2015 15:24:41 -0700 Subject: [PATCH 06/35] Address nits and fix tidy ... again --- src/librustc_typeck/check/mod.rs | 17 +++++--- .../default_ty_param_fallback_conflict.rs | 32 +++++++++++++++ ..._ty_param_fallback_conflict_cross_crate.rs | 29 ++++++++++++++ ...lback_default_dependent_associated_type.rs | 36 +++++++++++++++++ ...fallback_default_over_literal_fallback.rs} | 0 ...lt_ty_param_fallback_dependent_defaults.rs | 19 +++++++++ ..._ty_param_fallback_ensure_normalization.rs | 16 ++++++++ ...ault_ty_param_fallback_method_call_test.rs | 24 +++++++++++ .../default_ty_param_fallback_struct.rs | 23 +++++++++++ ...ty_param_fallback_struct_and_type_alias.rs | 40 +++++++++++++++++++ .../default_ty_param_fallback_trait_impl.rs | 25 ++++++++++++ ...ult_ty_param_fallback_trait_impl_simple.rs | 26 ++++++++++++ .../default_ty_param_fallback_type_alias.rs | 19 +++++++++ 13 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/default_ty_param_fallback_conflict.rs create mode 100644 src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs rename src/test/run-pass/{default_over_literal_fallback.rs => default_ty_param_fallback_default_over_literal_fallback.rs} (100%) create mode 100644 src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_method_call_test.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_struct.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_trait_impl.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs create mode 100644 src/test/run-pass/default_ty_param_fallback_type_alias.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5093b0f9100a1..e4672abfba705 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2275,9 +2275,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { for &(ref ty, ref default) in &has_user_default { let default = default.clone(); - let normalized_default = self.inh.normalize_associated_types_in(codemap::DUMMY_SP, 0, &default.ty); + + let normalized_default = self.inh.normalize_associated_types_in( + default.origin_span, + 0, &default.ty); + match infer::mk_eqty(self.infcx(), false, - infer::Misc(codemap::DUMMY_SP), // default.origin_span), + infer::Misc(default.origin_span), ty, normalized_default) { Ok(()) => {} Err(_) => { @@ -2286,7 +2290,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - // If there are conflicts we rollback, otherwise commit if conflicts.len() > 0 { Err(()) @@ -2375,9 +2378,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // reporting for more then one conflict. for &(ref ty, ref default) in tys_with_defaults { let default = default.clone(); - let normalized_default = self.inh.normalize_associated_types_in(codemap::DUMMY_SP, 0, &default.ty); + + let normalized_default = self.inh.normalize_associated_types_in( + default.origin_span, 0, + &default.ty); + match infer::mk_eqty(self.infcx(), false, - infer::Misc(codemap::DUMMY_SP), // default.origin_span), + infer::Misc(default.origin_span), ty, normalized_default) { Ok(()) => {} Err(_) => { diff --git a/src/test/compile-fail/default_ty_param_fallback_conflict.rs b/src/test/compile-fail/default_ty_param_fallback_conflict.rs new file mode 100644 index 0000000000000..48c5cd1ff7706 --- /dev/null +++ b/src/test/compile-fail/default_ty_param_fallback_conflict.rs @@ -0,0 +1,32 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::fmt::Debug; + +// Example from the RFC +fn foo() -> F { F::default() } +//~^ NOTE: a default was defined here... + +fn bar(b: B) { println!("{:?}", b); } +//~^ NOTE: a second default was defined here... + +fn main() { + // Here, F is instantiated with $0=uint + let x = foo(); + //~^ ERROR: mismatched types + //~| NOTE: conflicting type parameter defaults `usize` and `isize` + //~| NOTE: ...that was applied to an unconstrained type variable here + + // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. + bar(x); + //~^ NOTE: ...that also applies to the same type variable here +} diff --git a/src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs new file mode 100644 index 0000000000000..4d60724372ada --- /dev/null +++ b/src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs @@ -0,0 +1,29 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +//aux-build:default_ty_param_cross_crate_crate.rs + +#![feature(default_type_parameter_fallback)] + +extern crate default_param_test; + +use default_param_test::{Foo, bleh}; + +fn meh(x: Foo) {} +//~^ NOTE: a default was defined here... + +fn main() { + let foo = bleh(); + //~^ NOTE: ...that also applies to the same type variable here + + meh(foo); + //~^ ERROR: mismatched types: + //~| NOTE: conflicting type parameter defaults `bool` and `char` +} diff --git a/src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs new file mode 100644 index 0000000000000..8fc2c2e6bce70 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +trait Id { + type This; +} + +impl Id for A { + type This = A; +} + +struct Foo::This> { + data: PhantomData<(X, Y)> +} + +impl Foo { + fn new() -> Foo { + Foo { data: PhantomData } + } +} + +fn main() { + let foo = Foo::new(); +} diff --git a/src/test/run-pass/default_over_literal_fallback.rs b/src/test/run-pass/default_ty_param_fallback_default_over_literal_fallback.rs similarity index 100% rename from src/test/run-pass/default_over_literal_fallback.rs rename to src/test/run-pass/default_ty_param_fallback_default_over_literal_fallback.rs diff --git a/src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs b/src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs new file mode 100644 index 0000000000000..ac833d0f54744 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] +use std::marker::PhantomData; + +struct Foo { t: T, data: PhantomData } + +fn main() { + let foo = Foo { t: 'a', data: PhantomData }; +} diff --git a/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs b/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs new file mode 100644 index 0000000000000..bc9e309563ef6 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] +#![feature(iter_arith)] + +fn main() { + print!("{}", (1..4).sum()); +} diff --git a/src/test/run-pass/default_ty_param_fallback_method_call_test.rs b/src/test/run-pass/default_ty_param_fallback_method_call_test.rs new file mode 100644 index 0000000000000..e8d93092ec53d --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_method_call_test.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +struct Foo; + +impl Foo { + fn method(&self) -> A { + A::default() + } +} + +fn main() { + let f = Foo.method(); + println!("{}", f); +} diff --git a/src/test/run-pass/default_ty_param_fallback_struct.rs b/src/test/run-pass/default_ty_param_fallback_struct.rs new file mode 100644 index 0000000000000..d9ac51fc23b02 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_struct.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +struct Foo(A); + +impl Foo { + fn new() -> Foo { + Foo(A::default()) + } +} + +fn main() { + let foo = Foo::new(); +} diff --git a/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs new file mode 100644 index 0000000000000..6e3e60a02e5e2 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +struct DeterministicHasher; +struct RandomHasher; + + +struct MyHashMap { + data: PhantomData<(K, V, H)> +} + +impl MyHashMap { + fn new() -> MyHashMap { + MyHashMap { data: PhantomData } + } +} + +mod mystd { + use super::{MyHashMap, RandomHasher}; + pub type HashMap = MyHashMap; +} + +fn try_me(hash_map: mystd::HashMap) {} + +fn main() { + let hash_map = mystd::HashMap::new(); + try_me(hash_map); +} diff --git a/src/test/run-pass/default_ty_param_fallback_trait_impl.rs b/src/test/run-pass/default_ty_param_fallback_trait_impl.rs new file mode 100644 index 0000000000000..c67d3a49aff3d --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_trait_impl.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// Another example from the RFC +trait Foo { } +trait Bar { } + +impl Foo for Vec {} +impl Bar for usize {} + +fn takes_foo(f: F) {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + takes_foo(x); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs new file mode 100644 index 0000000000000..067ad524922c0 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// An example from the RFC +trait Foo { fn takes_foo(&self); } +trait Bar { } + +impl Foo for Vec { + fn takes_foo(&self) {} +} + +impl Bar for usize {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + x.takes_foo(); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/run-pass/default_ty_param_fallback_type_alias.rs b/src/test/run-pass/default_ty_param_fallback_type_alias.rs new file mode 100644 index 0000000000000..1b4747406d0c6 --- /dev/null +++ b/src/test/run-pass/default_ty_param_fallback_type_alias.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::collections::HashMap; + +type IntMap = HashMap; + +fn main() { + let x = IntMap::new(); +} From 28609d5bf084f59ee74cf92c2c5f25444f008ddd Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 16 Sep 2015 13:50:19 -0700 Subject: [PATCH 07/35] Rebase fixes --- src/librustc_typeck/check/mod.rs | 43 ++++++++------------------------ 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e4672abfba705..98a46fef02360 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2150,37 +2150,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether - /// feature(never_type) is enabled), unconstrained ints with i32, and - /// unconstrained floats with f64. fn default_type_parameters(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. Therefore, if we think we saw - // some errors in this function, just resolve all uninstanted type - // varibles to TyError. - if self.is_tainted_by_errors() { - for ty in &self.unsolved_variables() { - if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } - } - return; - } - - for ty in &self.unsolved_variables() { - let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); + use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + let unsolved_variables = self.infcx().candidates_for_defaulting(); + for &(ref ty, _) in &unsolved_variables { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + let diverges = self.infcx().type_var_diverges(resolved); + if diverges { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { - match self.type_is_unconstrained_numeric(resolved) { + let unconstrained = + self.infcx().type_is_unconstrained_numeric(resolved); + match unconstrained { UnconstrainedInt => { debug!("default_type_parameters: defaulting `{:?}` to `i32`", resolved); @@ -2208,10 +2189,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { use middle::ty::error::UnconstrainedNumeric::Neither; use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - // For the time being this errs on the side of being memory wasteful but provides better - // error reporting. - // let type_variables = self.infcx().type_variables.clone(); - // It is a possible that this algorithm will have to run an arbitrary number of times // to terminate so we bound it by the compiler's recursion limit. for _ in (0..self.tcx().sess.recursion_limit.get()) { From 978bbca8cc9c39c78f5ce98133b03b4798ee66ca Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 10 Mar 2016 10:00:36 -0500 Subject: [PATCH 08/35] wip --- src/librustc_typeck/check/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 98a46fef02360..7bfc6e3f2c45c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -107,7 +107,7 @@ use session::{CompileIncomplete, Session}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap}; +use util::nodemap::{DefIdMap, DefIdSet, FnvHashSet, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::rc::Rc; @@ -2201,9 +2201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Collect all unsolved type, integral and floating point variables. let defaults_to_apply = self.inh.infcx.candidates_for_defaulting(); - let mut has_user_default = HashSet::new(); - let mut has_literal_fallback = HashSet::new(); - let mut is_diverging = HashSet::new(); + let mut has_user_default = FnvHashSet(); + let mut has_literal_fallback = FnvHashSet(); + let mut is_diverging = FnvHashSet(); // Examine all unsolved variables, and narrow them to the set that have applicable // defaults. We want to process any unsolved variables that have either an explicit @@ -2232,9 +2232,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If there are no more fallbacks to apply at this point we have applied all possible // defaults and type inference will procede as normal. - if has_user_default.len() == 0 && - has_literal_fallback.len() == 0 && - is_diverging.len() == 0 { + if + has_user_default.is_empty() && + has_literal_fallback.is_empty() && + is_diverging.is_empty() + { break; } @@ -2343,9 +2345,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { conflict: &(Ty<'tcx>, type_variable::UserDefault<'tcx>)) -> Option> { // Ensure that we apply the conflicting default first - let mut unbound_tyvars = Vec::with_capacity(tys_with_defaults.len() + 1); - unbound_tyvars.push(conflict); - unbound_tyvars.extend(tys_with_defaults.iter()); + let unbound_tyvars: Vec<_> = Some(conflict).chain(tys_with_defaults).collect(); let mut result = None; // We run the same code as above applying defaults in order, this time when From f279dd61a8b806471080811ff08fdc8887cb99fd Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 20 Nov 2017 14:43:41 -0200 Subject: [PATCH 09/35] Manually merge moved files infer/mod.rs, infer/type_variable.rs and error.rs were manually rebased due to being moved from librustc/middle/infer/ to librustc/infer --- src/librustc/infer/mod.rs | 48 +++++++++++++------ src/librustc/infer/type_variable.rs | 71 +++++++++++++++++++---------- src/librustc/ty/error.rs | 2 +- 3 files changed, 83 insertions(+), 38 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 7302bad0ca166..1a3f0e360e3a6 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -697,40 +697,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Returns a type variable's default fallback if any exists. A default /// must be attached to the variable when created, if it is created - /// without a default, this will return None. + /// without a default, this will return NoDefault. /// /// This code does not apply to integral or floating point variables, /// only to use declared defaults. /// /// See `new_ty_var_with_default` to create a type variable with a default. /// See `type_variable::Default` for details about what a default entails. - pub fn default(&self, ty: Ty<'tcx>) -> Option> { + pub fn default(&self, ty: Ty<'tcx>) -> type_variable::Default<'tcx> { match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), - _ => None + ty::TyInfer(ty::TyVar(vid)) => self.type_variables + .borrow() + .default(vid) + .clone(), + _ => type_variable::Default::None, } } - pub fn unsolved_variables(&self) -> Vec> { + // Returns a vector containing all type variables that have an applicable default, + // along with their defaults. + // + // NB: You must be careful to only apply defaults once, if a variable is unififed + // it many no longer be unsolved and apply a second default will mostly likely + // result in a type error. + pub fn candidates_for_defaulting(&self) + -> Vec<(ty::Ty<'tcx>, type_variable::Default<'tcx>)> { let mut variables = Vec::new(); let unbound_ty_vars = self.type_variables .borrow_mut() - .unsolved_variables() + .candidates_for_defaulting() .into_iter() - .map(|t| self.tcx.mk_var(t)); + .map(|(t, d)| (self.tcx.mk_var(t), d)); let unbound_int_vars = self.int_unification_table .borrow_mut() .unsolved_variables() .into_iter() - .map(|v| self.tcx.mk_int_var(v)); + .map(|v| (self.tcx.mk_int_var(v), + type_variable::Default::Integer)); let unbound_float_vars = self.float_unification_table .borrow_mut() .unsolved_variables() .into_iter() - .map(|v| self.tcx.mk_float_var(v)); + .map(|v| (self.tcx.mk_float_var(v), + type_variable::Default::Float)); variables.extend(unbound_ty_vars); variables.extend(unbound_int_vars); @@ -1032,6 +1044,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .new_var(diverging, origin, None) } + pub fn next_ty_var_with_default(&self, + default: Option>, + origin: TypeVariableOrigin) -> Ty<'tcx> { + let ty_var_id = self.type_variables + .borrow_mut() + .new_var(false, origin, default); + + self.tcx.mk_var(ty_var_id) + } + pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(false, origin)) } @@ -1093,7 +1115,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> Ty<'tcx> { let default = if def.has_default { let default = self.tcx.type_of(def.def_id); - Some(type_variable::Default { + Some(type_variable::UserDefault { ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, def_id: def.def_id @@ -1361,13 +1383,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_conflicting_default_types(&self, span: Span, body_id: ast::NodeId, - expected: type_variable::Default<'tcx>, - actual: type_variable::Default<'tcx>) { + expected: type_variable::UserDefault<'tcx>, + actual: type_variable::UserDefault<'tcx>) { let trace = TypeTrace { cause: ObligationCause::misc(span, body_id), values: Types(ExpectedFound { expected: expected.ty, - found: actual.ty + found: actual.ty, }) }; diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 6aa094d2cd6d7..7e5425f7e1981 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -75,7 +75,7 @@ pub type TypeVariableMap = FxHashMap; struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, origin: TypeVariableOrigin, - diverging: bool + default: Default<'tcx>, } enum TypeVariableValue<'tcx> { @@ -85,10 +85,20 @@ enum TypeVariableValue<'tcx> { } } -// We will use this to store the required information to recapitulate what happened when -// an error occurs. #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Default<'tcx> { +pub enum Default<'tcx> { + User(UserDefault<'tcx>), + Integer, + Float, + Diverging, + None, +} + +// We will use this to store the required information to recapitulate +// what happened when an error occurs. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct UserDefault<'tcx> { + /// The default type provided by the user pub ty: Ty<'tcx>, /// The span where the default was incurred pub origin_span: Span, @@ -118,15 +128,15 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - pub fn default(&self, vid: ty::TyVid) -> Option> { - match &self.values.get(vid.index as usize).value { - &Known(_) => None, - &Bounded { ref default, .. } => default.clone() - } + pub fn default(&self, vid: ty::TyVid) -> &Default<'tcx> { + &self.values.get(vid.index as usize).default } pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging + match self.values.get(vid.index as usize).default { + Default::Diverging => true, + _ => false, + } } pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { @@ -178,14 +188,22 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn new_var(&mut self, diverging: bool, origin: TypeVariableOrigin, - default: Option>,) -> ty::TyVid { + default: Option>,) -> ty::TyVid { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); self.sub_relations.new_key(()); + + let default = if diverging { + Default::Diverging + } else { + default.map(|u| Default::User(u)) + .unwrap_or(Default::None) + }; + let index = self.values.push(TypeVariableData { - value: Bounded { default: default }, + value: Bounded { default: Some(default) }, origin, - diverging, + default, }); let v = ty::TyVid { index: index as u32 }; debug!("new_var: diverging={:?} index={:?}", diverging, v); @@ -351,17 +369,22 @@ impl<'tcx> TypeVariableTable<'tcx> { escaping_types } - pub fn unsolved_variables(&mut self) -> Vec { - (0..self.values.len()) - .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; - if self.probe(vid).is_some() { - None - } else { - Some(vid) - } - }) - .collect() + pub fn candidates_for_defaulting(&self) -> Vec<(ty::TyVid, Default<'tcx>)> { + self.values + .iter() + .enumerate() + .filter_map(|(i, value)| { + let vid = match &value.value { + &TypeVariableValue::Bounded { .. } => Some(ty::TyVid { index: i as u32 }), + &TypeVariableValue::Known(v) => match v.sty { + ty::TyInfer(ty::FloatVar(_)) | ty::TyInfer(ty::IntVar(_)) => + Some(ty::TyVid { index: i as u32 }), + _ => None + } + }; + vid.map(|v| (v, value.default.clone())) + }) + .collect() } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index cb68e576e5af9..912c2e5bd8b80 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -56,7 +56,7 @@ pub enum TypeError<'tcx> { CyclicTy(Ty<'tcx>), ProjectionMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>), + TyParamDefaultMismatch(ExpectedFound>), ExistentialMismatch(ExpectedFound<&'tcx ty::Slice>>), OldStyleLUB(Box>), From d4654b12dcbf3b42e2e23134630fa99c9bc135d9 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 20 Nov 2017 17:24:41 -0200 Subject: [PATCH 10/35] Fix rebase of default-type-param-fallback branch Had screwed up the rebase of `check/mod.rs`. The error handling code is commented out because I don't know how to rebase it. --- src/librustc/infer/type_variable.rs | 2 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc_typeck/check/mod.rs | 117 +++++++++--------- ...ty_param_fallback_default_over_literal.rs} | 0 4 files changed, 62 insertions(+), 65 deletions(-) rename src/test/run-pass/{default_ty_param_fallback_default_over_literal_fallback.rs => default_ty_param_fallback_default_over_literal.rs} (100%) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 7e5425f7e1981..7ab2539719ac7 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -201,7 +201,7 @@ impl<'tcx> TypeVariableTable<'tcx> { }; let index = self.values.push(TypeVariableData { - value: Bounded { default: Some(default) }, + value: Bounded { default: Some(default.clone()) }, origin, default, }); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 438511281ba47..72170ad37492f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -548,8 +548,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound { } BraceStructLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> { - type Lifted = type_variable::Default<'tcx>; + impl<'a, 'tcx> Lift<'tcx> for type_variable::UserDefault<'a> { + type Lifted = type_variable::UserDefault<'tcx>; ty, origin_span, def_id } } @@ -1172,9 +1172,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun } } -impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for type_variable::UserDefault<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - type_variable::Default { + type_variable::UserDefault { ty: self.ty.fold_with(folder), origin_span: self.origin_span, def_id: self.def_id diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7bfc6e3f2c45c..4e843335ecd1a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,8 +90,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; use namespace::Namespace; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; -use rustc::infer::type_variable::{TypeVariableOrigin}; -use rustc::infer::type_variable::Default; +use rustc::infer::type_variable::{TypeVariableOrigin, Default}; use rustc::middle::region; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; @@ -107,7 +106,7 @@ use session::{CompileIncomplete, Session}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, DefIdSet, FnvHashSet, FxHashMap, NodeMap}; +use util::nodemap::{DefIdMap, DefIdSet, FxHashSet, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::rc::Rc; @@ -1642,27 +1641,9 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { }; Some(self.next_region_var(v)) } - fn ty_infer(&self, - ty_param_def: Option>, - substs: Option<&mut subst::Substs<'tcx>>, - space: Option, - span: Span) -> Ty<'tcx> { - // Grab the default doing subsitution - let default = ty_param_def.and_then(|def| { - def.default.map(|ty| type_variable::UserDefault { - ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), - origin_span: span, - def_id: def.default_def_id - }) - }); - - let ty_var = self.infcx().next_ty_var_with_default(default); - // Finally we add the type variable to the substs - match substs { - None => ty_var, - Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var } - } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { + self.next_ty_var(TypeVariableOrigin::TypeInference(span)) } fn ty_infer_for_def(&self, @@ -2151,16 +2132,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn default_type_parameters(&self) { - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - let unsolved_variables = self.infcx().candidates_for_defaulting(); + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + let unsolved_variables = self.infcx.candidates_for_defaulting(); for &(ref ty, _) in &unsolved_variables { - let resolved = self.infcx().resolve_type_vars_if_possible(ty); - let diverges = self.infcx().type_var_diverges(resolved); + let resolved = self.infcx.resolve_type_vars_if_possible(ty); + let diverges = self.infcx.type_var_diverges(resolved); if diverges { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { let unconstrained = - self.infcx().type_is_unconstrained_numeric(resolved); + self.infcx.type_is_unconstrained_numeric(resolved); match unconstrained { UnconstrainedInt => { debug!("default_type_parameters: defaulting `{:?}` to `i32`", @@ -2185,25 +2168,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); } + #[allow(dead_code)] fn new_select_all_obligations_and_apply_defaults(&self) { - use middle::ty::error::UnconstrainedNumeric::Neither; - use middle::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; // It is a possible that this algorithm will have to run an arbitrary number of times // to terminate so we bound it by the compiler's recursion limit. - for _ in (0..self.tcx().sess.recursion_limit.get()) { + for _ in 0..self.tcx().sess.recursion_limit.get() { // First we try to solve all obligations, it is possible that the last iteration // has made it possible to make more progress. self.select_obligations_where_possible(); - let mut conflicts = Vec::new(); + // QUESTION(leodasvacas): Don't know how to rebase the whole error reporting strategy. + // let mut conflicts = Vec::new(); // Collect all unsolved type, integral and floating point variables. let defaults_to_apply = self.inh.infcx.candidates_for_defaulting(); - let mut has_user_default = FnvHashSet(); - let mut has_literal_fallback = FnvHashSet(); - let mut is_diverging = FnvHashSet(); + let mut has_user_default = FxHashSet(); + let mut has_literal_fallback = FxHashSet(); + let mut is_diverging = FxHashSet(); // Examine all unsolved variables, and narrow them to the set that have applicable // defaults. We want to process any unsolved variables that have either an explicit @@ -2251,40 +2236,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We wrap all of this in a transaction for error reporting. If we detect a conflict // we will rollback to the previous state so we can check what conflicts and // correctly report them. - let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { + //let _ = self.infcx.commit_if_ok(|_: &infer::CombinedSnapshot| { for &(ref ty, ref default) in &has_user_default { let default = default.clone(); - let normalized_default = self.inh.normalize_associated_types_in( + let normalized_default = self.normalize_associated_types_in( default.origin_span, - 0, &default.ty); + &default.ty); + + // QUESTION(leodasvacas): mk_eqty was removed, + // replaced it with demand but I don't know the difference. + self.demand_eqtype(default.origin_span, *ty, normalized_default); - match infer::mk_eqty(self.infcx(), false, + // QUESTION(leodasvacas): This means conflict is always empty + // and the error reporting is broken. + /*match infer::mk_eqty(self.infcx, false, infer::Misc(default.origin_span), ty, normalized_default) { Ok(()) => {} Err(_) => { conflicts.push((*ty, default)); } - } + }*/ } // If there are conflicts we rollback, otherwise commit + /* if conflicts.len() > 0 { Err(()) } else { Ok(()) - } - }); + }*/ + //}); + /* Consequence of commenting of find_conflicting_default 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 in conflicts { let conflicting_default = self.find_conflicting_default(&has_user_default, &conflict) - .unwrap_or(type_variable::UserDefault { - ty: self.infcx().next_ty_var(), + .unwrap_or(UserDefault { + ty: self.infcx.next_ty_var(), origin_span: codemap::DUMMY_SP, def_id: DefId::local(0) // what do I put here? }); @@ -2302,23 +2295,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; - self.infcx().report_conflicting_default_types( + self.infcx.report_conflicting_default_types( first_default.origin_span, + 0, // QUESTION(leodasvacas): What to put here as `body_id: ast::NodeId` first_default, second_default) } - } + }*/ // Apply integer and floating point fallbacks to any variables that // weren't solved by the previous phase where we applied user defaults. for ty in &has_literal_fallback { - let resolved = self.infcx().resolve_type_vars_if_possible(ty); - match self.infcx().type_is_unconstrained_numeric(resolved) { + let resolved = self.infcx.resolve_type_vars_if_possible(ty); + match self.infcx.type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => {} } @@ -2327,8 +2321,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Finally for any leftover variables that diverage // we should apply the unit fallback rules. for ty in &is_diverging { - if self.infcx().type_var_diverges(ty) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + if self.infcx.type_var_diverges(ty) { + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } } } @@ -2340,10 +2334,12 @@ 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. + // QUESTION(leodasvacas): Commented out because of rebase problems I don't know how to solve. + /* fn find_conflicting_default(&self, - tys_with_defaults: &HashSet<(Ty<'tcx>, type_variable::UserDefault<'tcx>)>, - conflict: &(Ty<'tcx>, type_variable::UserDefault<'tcx>)) - -> Option> { + tys_with_defaults: &FxHashSet<(Ty<'tcx>, UserDefault<'tcx>)>, + conflict: &(Ty<'tcx>, UserDefault<'tcx>)) + -> Option> { // Ensure that we apply the conflicting default first let unbound_tyvars: Vec<_> = Some(conflict).chain(tys_with_defaults).collect(); @@ -2353,14 +2349,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We also run this inside snapshot that never commits so we can do error // reporting for more then one conflict. + // QUESTION(leodasvacas): Again don't know what to do with this and `mk_eqty`. for &(ref ty, ref default) in tys_with_defaults { let default = default.clone(); - let normalized_default = self.inh.normalize_associated_types_in( - default.origin_span, 0, + let normalized_default = self.normalize_associated_types_in( + default.origin_span, &default.ty); - match infer::mk_eqty(self.infcx(), false, + match infer::mk_eqty(self.infcx, false, infer::Misc(default.origin_span), ty, normalized_default) { Ok(()) => {} @@ -2372,7 +2369,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } return result; - } + }*/ fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); diff --git a/src/test/run-pass/default_ty_param_fallback_default_over_literal_fallback.rs b/src/test/run-pass/default_ty_param_fallback_default_over_literal.rs similarity index 100% rename from src/test/run-pass/default_ty_param_fallback_default_over_literal_fallback.rs rename to src/test/run-pass/default_ty_param_fallback_default_over_literal.rs From ad30796d5477ab92a9027b8459d00cefcaa47f4e Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 20 Nov 2017 21:46:25 -0200 Subject: [PATCH 11/35] trying stuff out --- src/librustc_typeck/check/mod.rs | 73 ++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4e843335ecd1a..e56ee9b6f454f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2131,7 +2131,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn default_type_parameters(&self) { + fn apply_diverging_and_numeric_type_parameter_fallback(&self) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2161,13 +2161,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + #[allow(dead_code)] + fn apply_user_type_parameter_fallback(&self) { + debug!("Applying user defaults"); + // It is a possible that this algorithm will have to run an arbitrary number of times + // to terminate so we bound it by the compiler's recursion limit. + // TODO: detect fixed point. + for _ in 0..5 {//self.tcx().sess.recursion_limit.get() { + self.select_obligations_where_possible(); + // Collect all unsolved type variables. + let unsolved = self.inh.infcx.candidates_for_defaulting(); + + let mut has_user_default = FxHashSet(); + + // Examine all unsolved variables, applying user defaults. + // If no default is provided, then the variable will be unable to unify with anything. + for &(ref ty, ref default) in &unsolved { + if let &Default::User(ref user_default) = default { + println!("apply_user_type_parameter_fallback: \ + ty: {:?} with default: {:?}", ty, user_default); + has_user_default.insert((*ty, user_default.clone())); + + let normalized_default = self.normalize_associated_types_in( + user_default.origin_span, + &user_default.ty); + self.demand_eqtype(user_default.origin_span, *ty, normalized_default); + } else { + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err); + } + } + } + } + // Implements type inference fallback algorithm fn select_all_obligations_and_apply_defaults(&self) { self.select_obligations_where_possible(); - self.default_type_parameters(); + self.apply_diverging_and_numeric_type_parameter_fallback(); self.select_obligations_where_possible(); } - + #[allow(dead_code)] fn new_select_all_obligations_and_apply_defaults(&self) { use rustc::ty::error::UnconstrainedNumeric::Neither; @@ -2225,6 +2257,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { break; } + // First apply integer and floating point fallbacks. + for ty in &has_literal_fallback { + let resolved = self.infcx.resolve_type_vars_if_possible(ty); + match self.infcx.type_is_unconstrained_numeric(resolved) { + UnconstrainedInt => { + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => {} + } + } + // Finally we loop through each of the unbound type variables and unify them with // the proper fallback, reporting a conflicting default error if any of the // unifications fail. @@ -2303,21 +2349,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }*/ - // Apply integer and floating point fallbacks to any variables that - // weren't solved by the previous phase where we applied user defaults. - for ty in &has_literal_fallback { - let resolved = self.infcx.resolve_type_vars_if_possible(ty); - match self.infcx.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) - }, - UnconstrainedFloat => { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) - } - Neither => {} - } - } - // Finally for any leftover variables that diverage // we should apply the unit fallback rules. for ty in &is_diverging { @@ -2382,6 +2413,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); + if fulfillment_cx.select_where_possible(self).is_err() { + self.apply_user_type_parameter_fallback(); + // FIXME: Probably uneccessary. + self.select_obligations_where_possible(); + } + match fulfillment_cx.select_all_or_error(self) { Ok(()) => { } Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } From e1ef32412206bc6282c956c66adb66e8b0cf254e Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 21 Nov 2017 13:17:39 -0200 Subject: [PATCH 12/35] downgrade verbose logs from `debug!` to `trace!` --- src/librustc/hir/map/definitions.rs | 4 ++-- src/libsyntax/codemap.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index dfa675f2e9351..d73ddaec0bbb0 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -279,10 +279,10 @@ impl DefPath { let mut data = vec![]; let mut index = Some(start_index); loop { - debug!("DefPath::make: krate={:?} index={:?}", krate, index); + trace!("DefPath::make: krate={:?} index={:?}", krate, index); let p = index.unwrap(); let key = get_key(p); - debug!("DefPath::make: key={:?}", key); + trace!("DefPath::make: key={:?}", key); match key.disambiguated_data.data { DefPathData::CrateRoot => { assert!(key.parent.is_none()); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3464db2a81111..18e181123c4b4 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -321,11 +321,11 @@ impl CodeMap { .sum(); col.0 - special_chars + non_narrow }; - debug!("byte pos {:?} is on the line at byte pos {:?}", + trace!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", + trace!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos); - debug!("byte is on line: {}", line); + trace!("byte is on line: {}", line); assert!(chpos >= linechpos); Loc { file: f, From b9e9f0f05c2d88875abdf304a827dec80111730b Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 21 Nov 2017 19:07:50 -0200 Subject: [PATCH 13/35] Combine propagates defaults. --- src/librustc/infer/combine.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 50a37e12531a7..9f618b41ede1b 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -46,6 +46,7 @@ use ty::error::TypeError; use ty::relate::{self, Relate, RelateResult, TypeRelation}; use ty::subst::Substs; use traits::{Obligation, PredicateObligations}; +use infer::type_variable::Default; use syntax::ast; use syntax_pos::Span; @@ -424,7 +425,13 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } let origin = variables.origin(vid); - let new_var_id = variables.new_var(false, origin, None); + let orig_default = variables.default(vid).clone(); + let default = if let Default::User(user_default) = orig_default { + Some(user_default) + } else { + None + }; + let new_var_id = variables.new_var(false, origin, default); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); From ce861ae050dc84f65cbd95ca61e8d655a227d5af Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 09:54:12 -0200 Subject: [PATCH 14/35] Conservative default type param fallback. User fallbacks are applied as a last ditch attempt at inference. If a type variable could gain a fallback in the future, it may not unify with anything, for future-proofing. This means adding a default is always backwards-compatible. Check `apply_user_type_parameter_fallback` for the algorithm. --- src/librustc/infer/type_variable.rs | 9 +++ src/librustc/traits/fulfill.rs | 15 ++++- .../obligation_forest/mod.rs | 12 ++++ src/librustc_typeck/check/mod.rs | 64 ++++++++++--------- 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 7ab2539719ac7..bb7bbe03c0ea6 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -132,6 +132,15 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).default } + /// Can an user-supplied default exist for this variable? + pub fn is_user_defaultible(&self, vid: ty::TyVid) -> bool { + if let TypeVariableOrigin::TypeParameterDefinition(..) = self.var_origin(vid) { + true + } else { + false + } + } + pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { match self.values.get(vid.index as usize).default { Default::Diverging => true, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6b681322c9bf5..1d00ee9209a24 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -9,12 +9,13 @@ // except according to those terms. use infer::{RegionObligation, InferCtxt, InferOk}; -use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; +use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate, InferTy, TypeVariants}; use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; use hir::def_id::DefId; +use util::nodemap::FxHashSet; use super::CodeAmbiguity; use super::CodeProjectionError; @@ -179,6 +180,18 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { self.predicates.pending_obligations() } + pub fn vars_in_unsolved_obligations(&self) -> FxHashSet { + let mut vars = FxHashSet(); + for p in self.predicates.unsolved_obligations() { + for ty in p.obligation.predicate.walk_tys() { + if let TypeVariants::TyInfer(InferTy::TyVar(vid)) = ty.sty { + vars.insert(vid); + } + } + } + vars + } + /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it /// only attempts to select obligations that haven't been seen before. fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 02cae52166ac3..3292b88c9780b 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -244,6 +244,18 @@ impl ObligationForest { .collect() } + /// Returns the set of obligations that are in a pending or waiting state. + pub fn unsolved_obligations(&self) -> Vec + where O: Clone + { + self.nodes + .iter() + .filter(|n| n.state.get() == NodeState::Pending || + n.state.get() == NodeState::Waiting) + .map(|n| n.obligation.clone()) + .collect() + } + /// Perform a pass through the obligation list. This must /// be called in a loop until `outcome.stalled` is false. /// diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e56ee9b6f454f..e289135afdbcb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2161,33 +2161,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - #[allow(dead_code)] fn apply_user_type_parameter_fallback(&self) { - debug!("Applying user defaults"); - // It is a possible that this algorithm will have to run an arbitrary number of times - // to terminate so we bound it by the compiler's recursion limit. - // TODO: detect fixed point. - for _ in 0..5 {//self.tcx().sess.recursion_limit.get() { - self.select_obligations_where_possible(); - // Collect all unsolved type variables. - let unsolved = self.inh.infcx.candidates_for_defaulting(); - - let mut has_user_default = FxHashSet(); - - // Examine all unsolved variables, applying user defaults. - // If no default is provided, then the variable will be unable to unify with anything. - for &(ref ty, ref default) in &unsolved { - if let &Default::User(ref user_default) = default { - println!("apply_user_type_parameter_fallback: \ - ty: {:?} with default: {:?}", ty, user_default); - has_user_default.insert((*ty, user_default.clone())); - + // Collect variables that are unsolved and defaultible, + // partitioned by subtyping equivalence. + let mut partition = FxHashMap(); + for vid in self.fulfillment_cx.borrow().vars_in_unsolved_obligations() { + let mut type_variables = self.infcx.type_variables.borrow_mut(); + let not_known = type_variables.probe(vid).is_none(); + let defaultible = type_variables.is_user_defaultible(vid); + if defaultible && not_known { + let root = type_variables.sub_root_var(vid); + partition.entry(root).or_insert(Vec::new()).push(vid); + } + } + + // For future-proofing against conflicting defaults, + // we do not allow variables with no default to be unified. + 'parts: for part in partition.values() { + for &vid in part { + match self.infcx.type_variables.borrow().default(vid) { + &Default::User(_) => {}, + _ => continue 'parts, + } + } + for &vid in part { + // If future-proof, then all vars have defaults. + let default = self.infcx.type_variables.borrow().default(vid).clone(); + let ty = self.tcx.mk_var(vid); + debug!("apply_user_type_parameter_fallback: \ + ty: {:?} with default: {:?}", ty, default); + if let Default::User(user_default) = default { let normalized_default = self.normalize_associated_types_in( - user_default.origin_span, - &user_default.ty); - self.demand_eqtype(user_default.origin_span, *ty, normalized_default); - } else { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err); + user_default.origin_span, + &user_default.ty); + self.demand_eqtype(user_default.origin_span, &ty, normalized_default); } } } @@ -2410,15 +2417,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(self.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); + self.apply_user_type_parameter_fallback(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); - if fulfillment_cx.select_where_possible(self).is_err() { - self.apply_user_type_parameter_fallback(); - // FIXME: Probably uneccessary. - self.select_obligations_where_possible(); - } - match fulfillment_cx.select_all_or_error(self) { Ok(()) => { } Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } From 8b44ca57dfa8edede6e9805d06a93bdc57d8c141 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 10:32:52 -0200 Subject: [PATCH 15/35] Fix regression on diverging fallback, remove old user fallback implementation. Regression fixed by reverting from rebased version to `default_type_parameters` in master. Renamed it to `apply_diverging_and_numeric_type_parameter_fallback`. Removed the previous algorithm for user fallback. --- src/librustc/infer/mod.rs | 15 +- src/librustc/infer/type_variable.rs | 27 ++-- src/librustc_typeck/check/mod.rs | 239 ++++------------------------ 3 files changed, 44 insertions(+), 237 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1a3f0e360e3a6..53d0c368ee69b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -720,36 +720,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // NB: You must be careful to only apply defaults once, if a variable is unififed // it many no longer be unsolved and apply a second default will mostly likely // result in a type error. - pub fn candidates_for_defaulting(&self) - -> Vec<(ty::Ty<'tcx>, type_variable::Default<'tcx>)> { + pub fn candidates_for_fallback(&self) -> Vec> { let mut variables = Vec::new(); let unbound_ty_vars = self.type_variables .borrow_mut() - .candidates_for_defaulting() + .unsolved_variables() .into_iter() - .map(|(t, d)| (self.tcx.mk_var(t), d)); + .map(|t| self.tcx.mk_var(t)); let unbound_int_vars = self.int_unification_table .borrow_mut() .unsolved_variables() .into_iter() - .map(|v| (self.tcx.mk_int_var(v), - type_variable::Default::Integer)); + .map(|v| self.tcx.mk_int_var(v)); let unbound_float_vars = self.float_unification_table .borrow_mut() .unsolved_variables() .into_iter() - .map(|v| (self.tcx.mk_float_var(v), - type_variable::Default::Float)); + .map(|v| self.tcx.mk_float_var(v)); variables.extend(unbound_ty_vars); variables.extend(unbound_int_vars); variables.extend(unbound_float_vars); return variables; - } +} fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) -> CombineFields<'a, 'gcx, 'tcx> { diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index bb7bbe03c0ea6..9b8d9b0118b61 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -378,22 +378,17 @@ impl<'tcx> TypeVariableTable<'tcx> { escaping_types } - pub fn candidates_for_defaulting(&self) -> Vec<(ty::TyVid, Default<'tcx>)> { - self.values - .iter() - .enumerate() - .filter_map(|(i, value)| { - let vid = match &value.value { - &TypeVariableValue::Bounded { .. } => Some(ty::TyVid { index: i as u32 }), - &TypeVariableValue::Known(v) => match v.sty { - ty::TyInfer(ty::FloatVar(_)) | ty::TyInfer(ty::IntVar(_)) => - Some(ty::TyVid { index: i as u32 }), - _ => None - } - }; - vid.map(|v| (v, value.default.clone())) - }) - .collect() + pub fn unsolved_variables(&mut self) -> Vec { + (0..self.values.len()) + .filter_map(|i| { + let vid = ty::TyVid { index: i as u32 }; + if self.probe(vid).is_some() { + None + } else { + Some(vid) + } + }) + .collect() } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e289135afdbcb..d291a4a2ffcad 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,7 +106,7 @@ use session::{CompileIncomplete, Session}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, DefIdSet, FxHashSet, FxHashMap, NodeMap}; +use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::rc::Rc; @@ -2131,20 +2131,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// Apply divering and numeric fallbacks. + /// Diverging types get replaced with ! or () (depending on whether + /// feature(never_type) is enabled), unconstrained ints with i32, and + /// unconstrained floats with f64. fn apply_diverging_and_numeric_type_parameter_fallback(&self) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - let unsolved_variables = self.infcx.candidates_for_defaulting(); - for &(ref ty, _) in &unsolved_variables { - let resolved = self.infcx.resolve_type_vars_if_possible(ty); - let diverges = self.infcx.type_var_diverges(resolved); - if diverges { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. Therefore, if we think we saw + // some errors in this function, just resolve all uninstanted type + // varibles to TyError. + if self.is_tainted_by_errors() { + for ty in &self.candidates_for_fallback() { + if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); + } + } + return; + } + + for ty in &self.candidates_for_fallback() { + let resolved = self.resolve_type_vars_if_possible(ty); + if self.type_var_diverges(resolved) { + debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", + resolved); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, + self.tcx.mk_diverging_default()); } else { - let unconstrained = - self.infcx.type_is_unconstrained_numeric(resolved); - match unconstrained { + match self.type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { debug!("default_type_parameters: defaulting `{:?}` to `i32`", resolved); @@ -2206,208 +2223,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.apply_diverging_and_numeric_type_parameter_fallback(); self.select_obligations_where_possible(); } - - #[allow(dead_code)] - fn new_select_all_obligations_and_apply_defaults(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - // It is a possible that this algorithm will have to run an arbitrary number of times - // to terminate so we bound it by the compiler's recursion limit. - for _ in 0..self.tcx().sess.recursion_limit.get() { - // First we try to solve all obligations, it is possible that the last iteration - // has made it possible to make more progress. - self.select_obligations_where_possible(); - - // QUESTION(leodasvacas): Don't know how to rebase the whole error reporting strategy. - // let mut conflicts = Vec::new(); - - // Collect all unsolved type, integral and floating point variables. - let defaults_to_apply = self.inh.infcx.candidates_for_defaulting(); - - let mut has_user_default = FxHashSet(); - let mut has_literal_fallback = FxHashSet(); - let mut is_diverging = FxHashSet(); - - // Examine all unsolved variables, and narrow them to the set that have applicable - // defaults. We want to process any unsolved variables that have either an explicit - // user default, literal fallback, or are diverging. - for &(ref ty, ref default) in &defaults_to_apply { - // We should NEVER process anything but a TyInfer. - assert!(match ty.sty { ty::TyInfer(_) => true, _ => false }); - - match default { - &Default::User(ref user_default) => { - debug!("select_all_obligations_and_apply_defaults: \ - ty: {:?} with default: {:?}", ty, default); - - has_user_default.insert((*ty, user_default.clone())); - }, - &Default::Float | - &Default::Integer => { - has_literal_fallback.insert(*ty); - } - &Default::Diverging => { - is_diverging.insert(*ty); - } - &Default::None => {} - } - } - - // If there are no more fallbacks to apply at this point we have applied all possible - // defaults and type inference will procede as normal. - if - has_user_default.is_empty() && - has_literal_fallback.is_empty() && - is_diverging.is_empty() - { - break; - } - - // First apply integer and floating point fallbacks. - for ty in &has_literal_fallback { - let resolved = self.infcx.resolve_type_vars_if_possible(ty); - match self.infcx.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) - }, - UnconstrainedFloat => { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) - } - Neither => {} - } - } - - // Finally we loop through each of the unbound type variables and unify them with - // the proper fallback, reporting a conflicting default error if any of the - // unifications fail. - // - // We know that a conflict must be due to multiple applicable defaults, because the - // variable would only be in `unbound_tyvars` and have been previously unified with - // another type if we had applied a default. - - // We wrap all of this in a transaction for error reporting. If we detect a conflict - // we will rollback to the previous state so we can check what conflicts and - // correctly report them. - //let _ = self.infcx.commit_if_ok(|_: &infer::CombinedSnapshot| { - for &(ref ty, ref default) in &has_user_default { - let default = default.clone(); - - let normalized_default = self.normalize_associated_types_in( - default.origin_span, - &default.ty); - - // QUESTION(leodasvacas): mk_eqty was removed, - // replaced it with demand but I don't know the difference. - self.demand_eqtype(default.origin_span, *ty, normalized_default); - - // QUESTION(leodasvacas): This means conflict is always empty - // and the error reporting is broken. - /*match infer::mk_eqty(self.infcx, false, - infer::Misc(default.origin_span), - ty, normalized_default) { - Ok(()) => {} - Err(_) => { - conflicts.push((*ty, default)); - } - }*/ - } - - // If there are conflicts we rollback, otherwise commit - /* - if conflicts.len() > 0 { - Err(()) - } else { - Ok(()) - }*/ - //}); - - /* Consequence of commenting of find_conflicting_default - 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 in conflicts { - let conflicting_default = - self.find_conflicting_default(&has_user_default, &conflict) - .unwrap_or(UserDefault { - ty: self.infcx.next_ty_var(), - origin_span: codemap::DUMMY_SP, - def_id: DefId::local(0) // what do I put here? - }); - - let default = conflict.1; - - // 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.infcx.report_conflicting_default_types( - first_default.origin_span, - 0, // QUESTION(leodasvacas): What to put here as `body_id: ast::NodeId` - first_default, - second_default) - } - }*/ - - // Finally for any leftover variables that diverage - // we should apply the unit fallback rules. - for ty in &is_diverging { - if self.infcx.type_var_diverges(ty) { - self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); - } - } - } - - self.select_obligations_where_possible(); - } - - // For use in error handling related to default type parameter fallback. We explicitly - // 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. - // QUESTION(leodasvacas): Commented out because of rebase problems I don't know how to solve. - /* - fn find_conflicting_default(&self, - tys_with_defaults: &FxHashSet<(Ty<'tcx>, UserDefault<'tcx>)>, - conflict: &(Ty<'tcx>, UserDefault<'tcx>)) - -> Option> { - // Ensure that we apply the conflicting default first - let unbound_tyvars: Vec<_> = Some(conflict).chain(tys_with_defaults).collect(); - - 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. - // QUESTION(leodasvacas): Again don't know what to do with this and `mk_eqty`. - for &(ref ty, ref default) in tys_with_defaults { - let default = default.clone(); - - let normalized_default = self.normalize_associated_types_in( - default.origin_span, - &default.ty); - - match infer::mk_eqty(self.infcx, false, - infer::Misc(default.origin_span), - ty, normalized_default) { - Ok(()) => {} - Err(_) => { - result = Some(default); - break; - } - } - } - - return result; - }*/ fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); From 923923384f36c7eb3df54538bf76c144ef6af19c Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 15:06:45 -0200 Subject: [PATCH 16/35] Give priority to defaults in fns and impls over defaults in types. The origin of the type parameter had to be plumbed down to typeck, maybe there is a better way to do it? --- src/librustc/ich/impls_ty.rs | 8 +++ .../infer/error_reporting/need_type_info.rs | 4 +- src/librustc/infer/mod.rs | 11 ++-- src/librustc/infer/type_variable.rs | 15 ++---- src/librustc/traits/error_reporting.rs | 6 ++- src/librustc/ty/mod.rs | 9 ++++ src/librustc_typeck/check/mod.rs | 50 ++++++++++++++----- src/librustc_typeck/collect.rs | 17 ++++++- 8 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 9609ae5a0beb8..1b8073b15b189 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -462,11 +462,19 @@ for ty::RegionParameterDef { } } +impl_stable_hash_for!(enum ty::OriginOfTyParam { + Fn, + Impl, + TyDef, + Other +}); + impl_stable_hash_for!(struct ty::TypeParameterDef { name, def_id, index, has_default, + origin, object_lifetime_default, pure_wrt_drop, synthetic diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index ea3c0a8ddb450..1d33c3aefac72 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty { let ty_vars = self.type_variables.borrow(); - if let TypeVariableOrigin::TypeParameterDefinition(_, name) = - *ty_vars.var_origin(ty_vid) { + if let TypeVariableOrigin::TypeParameterDefinition(_, name, _) = + ty_vars.var_origin(ty_vid) { name.to_string() } else { ty.to_string() diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 53d0c368ee69b..a8f6f378c2eb8 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1121,14 +1121,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { None }; + let origin = TypeVariableOrigin::TypeParameterDefinition(span, + def.name, + def.origin); - let ty_var_id = self.type_variables - .borrow_mut() - .new_var(false, - TypeVariableOrigin::TypeParameterDefinition(span, def.name), - default); - - self.tcx.mk_var(ty_var_id) + self.tcx.mk_var(self.type_variables.borrow_mut().new_var(false, origin, default)) } /// Given a set of generics defined on a type or impl, returns a substitution mapping each diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9b8d9b0118b61..8e98fbdd9617e 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -55,7 +55,7 @@ pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), TypeInference(Span), - TypeParameterDefinition(Span, ast::Name), + TypeParameterDefinition(Span, ast::Name, ty::OriginOfTyParam), /// one of the upvars or closure kind parameters in a `ClosureSubsts` /// (before it has been determined) @@ -132,15 +132,6 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).default } - /// Can an user-supplied default exist for this variable? - pub fn is_user_defaultible(&self, vid: ty::TyVid) -> bool { - if let TypeVariableOrigin::TypeParameterDefinition(..) = self.var_origin(vid) { - true - } else { - false - } - } - pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { match self.values.get(vid.index as usize).default { Default::Diverging => true, @@ -148,8 +139,8 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).origin + pub fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + self.values.get(vid.index as usize).origin } /// Records that `a == b`, depending on `dir`. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 46ec2be4a1f9b..8cabd2ebce116 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,7 +36,7 @@ use middle::const_val; use std::fmt; use syntax::ast; use session::DiagnosticMessageId; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, OriginOfTyParam, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -1134,7 +1134,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let infcx = self.infcx; self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var( - TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name))) + TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, + name, + OriginOfTyParam::Other))) } else { ty.super_fold_with(self) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 583dcb46f000c..d03df792353e5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -671,12 +671,21 @@ pub enum IntVarValue { UintType(ast::UintTy), } +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum OriginOfTyParam { + Fn, + Impl, + TyDef, + Other, +} + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef { pub name: Name, pub def_id: DefId, pub index: u32, pub has_default: bool, + pub origin: OriginOfTyParam, pub object_lifetime_default: ObjectLifetimeDefault, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d291a4a2ffcad..55c6fa6ce57ba 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2179,29 +2179,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn apply_user_type_parameter_fallback(&self) { - // Collect variables that are unsolved and defaultible, - // partitioned by subtyping equivalence. - let mut partition = FxHashMap(); + use self::TypeVariableOrigin::TypeParameterDefinition; + use ty::OriginOfTyParam; + + // Collect variables that are unsolved and support fallback, + // grouped by subtyping equivalence. + let mut bags = FxHashMap(); for vid in self.fulfillment_cx.borrow().vars_in_unsolved_obligations() { let mut type_variables = self.infcx.type_variables.borrow_mut(); let not_known = type_variables.probe(vid).is_none(); - let defaultible = type_variables.is_user_defaultible(vid); - if defaultible && not_known { + let supports_fallback = match type_variables.var_origin(vid) { + TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | + TypeParameterDefinition(_, _, OriginOfTyParam::Impl) | + TypeParameterDefinition(_, _, OriginOfTyParam::TyDef) => true, + _ => false + }; + if supports_fallback && not_known { let root = type_variables.sub_root_var(vid); - partition.entry(root).or_insert(Vec::new()).push(vid); + bags.entry(root).or_insert(Vec::new()).push(vid); } } - // For future-proofing against conflicting defaults, - // we do not allow variables with no default to be unified. - 'parts: for part in partition.values() { - for &vid in part { + 'bags: for (_, mut bag) in bags.into_iter() { + // Partition the bag by the origin of the default. + let (fn_or_impl, ty_def) = bag.into_iter().partition(|&v| { + match self.infcx.type_variables.borrow().var_origin(v) { + TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | + TypeParameterDefinition(_, _, OriginOfTyParam::Impl) => true, + TypeParameterDefinition(_, _, OriginOfTyParam::TyDef) => false, + _ => bug!("type var does not support fallback") + } + }); + // Params from fns or impls take priority, if they exist ignore the rest of the bag. + bag = fn_or_impl; + if bag.is_empty() { + bag = ty_def; + } + // For future-proofing against conflicting defaults, + // if one of the variables has no default, nothing is unified. + for &vid in &bag { match self.infcx.type_variables.borrow().default(vid) { &Default::User(_) => {}, - _ => continue 'parts, + _ => continue 'bags, } } - for &vid in part { + for &vid in &bag { // If future-proof, then all vars have defaults. let default = self.infcx.type_variables.borrow().default(vid).clone(); let ty = self.tcx.mk_var(vid); @@ -2211,6 +2233,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let normalized_default = self.normalize_associated_types_in( user_default.origin_span, &user_default.ty); + // QUESTION(leodasvacas): + // This will emit "expected type mismatch" on conflicting defaults, which is bad. + // I'd be happy to somehow detect or rollback this demand on conflict defaults + // so we would emit "type annotations needed" instead. self.demand_eqtype(user_default.origin_span, &ty, normalized_default); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7de29868d4341..2438f6f66ccea 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -872,6 +872,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut opt_self = None; let mut allow_defaults = false; + let mut origin = ty::OriginOfTyParam::Other; let no_generics = hir::Generics::empty(); let (ast_generics, opt_inputs) = match node { @@ -891,13 +892,21 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { - ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)), - ItemImpl(_, _, _, ref generics, ..) => (generics, None), + ItemFn(ref decl, .., ref generics, _) => { + origin = ty::OriginOfTyParam::Fn; + (generics, Some(&decl.inputs)) + } + + ItemImpl(_, _, _, ref generics, ..) => { + origin = ty::OriginOfTyParam::Impl; + (generics, None) + } ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | ItemUnion(_, ref generics) => { + origin = ty::OriginOfTyParam::TyDef; allow_defaults = true; (generics, None) } @@ -914,6 +923,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: keywords::SelfType.name(), def_id: tcx.hir.local_def_id(param_id), has_default: false, + origin: ty::OriginOfTyParam::Other, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, synthetic: None, @@ -990,6 +1000,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: p.name, def_id: tcx.hir.local_def_id(p.id), has_default: p.default.is_some(), + origin, object_lifetime_default: object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]), pure_wrt_drop: p.pure_wrt_drop, @@ -1008,6 +1019,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: Symbol::intern(&tcx.hir.node_to_pretty_string(info.id)), def_id: info.def_id, has_default: false, + origin: ty::OriginOfTyParam::Other, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, synthetic: Some(SyntheticTyParamKind::ImplTrait), @@ -1047,6 +1059,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: Symbol::intern(""), def_id, has_default: false, + origin: ty::OriginOfTyParam::Other, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, synthetic: None, From 9a98d234a3ffea0b390a9be97d65fab69c5ef0c9 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 15:45:21 -0200 Subject: [PATCH 17/35] Feature gate default type parameter fallback. --- 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 55c6fa6ce57ba..3ab05af66a8c4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2258,7 +2258,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(self.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); - self.apply_user_type_parameter_fallback(); + if self.tcx.sess.features.borrow().default_type_parameter_fallback { + self.apply_user_type_parameter_fallback(); + } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); From ced260011b41bdf44ec9e7b117cac61daa9f4e8b Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 17:08:15 -0200 Subject: [PATCH 18/35] Remove default data from TypeVariableValue::Bounded. We use the default information in TypeVariableData. Also improved some comments. --- src/librustc/infer/type_variable.rs | 29 ++++++++++++---------------- src/librustc_typeck/check/mod.rs | 30 +++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 8e98fbdd9617e..030f877d1e1b6 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -80,9 +80,7 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), - Bounded { - default: Option> - } + Bounded, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -112,9 +110,8 @@ pub struct Snapshot { sub_snapshot: ut::Snapshot, } -struct Instantiate<'tcx> { +struct Instantiate { vid: ty::TyVid, - default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); @@ -175,8 +172,8 @@ impl<'tcx> TypeVariableTable<'tcx> { }; match old_value { - TypeVariableValue::Bounded { default } => { - self.values.record(Instantiate { vid: vid, default: default }); + TypeVariableValue::Bounded => { + self.values.record(Instantiate { vid: vid }); } TypeVariableValue::Known(old_ty) => { bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", @@ -201,7 +198,7 @@ impl<'tcx> TypeVariableTable<'tcx> { }; let index = self.values.push(TypeVariableData { - value: Bounded { default: Some(default.clone()) }, + value: Bounded, origin, default, }); @@ -253,7 +250,7 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { debug_assert!(self.root_var(vid) == vid); match self.values.get(vid.index as usize).value { - Bounded { .. } => None, + Bounded => None, Known(t) => Some(t) } } @@ -349,12 +346,12 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(Instantiate { vid, .. }) => { + sv::UndoLog::Other(Instantiate { vid }) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. let escaping_type = match self.values.get(vid.index as usize).value { - Bounded { .. } => bug!(), + Bounded => bug!(), Known(ty) => ty, }; escaping_types.push(escaping_type); @@ -385,12 +382,10 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = Instantiate<'tcx>; + type Undo = Instantiate; - fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { - let Instantiate { vid, default } = action; - values[vid.index as usize].value = Bounded { - default, - }; + fn reverse(values: &mut Vec>, action: Instantiate) { + let Instantiate { vid } = action; + values[vid.index as usize].value = Bounded; } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3ab05af66a8c4..33100c8fbbf31 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2178,12 +2178,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// This runs as the last resort of type inference. + /// + /// It applies user supplied defaults as fallbacks for inference variables, + /// for example in `fn foo()` an inference variable originated from `T` + /// will have `String` as its default. + /// + /// Adding a default to a type parameter that has none should be backwards compatible. + /// However if we get conflicting defaults we do not know how to resolve them. + /// Therefore we must future-proof against such a conflict by not allowing + /// type variables with defaults to unify with type variables without defaults. + /// + /// We may come up with rules to prioritize a type parameter over another. + /// When unifying type variables, the highest priority parameter involved + /// has the final say on what the default should be. + /// Currently we prioritize defaults from impls and fns over defaults in types, + /// this for example allows `fn foo(x: Option)` to work + /// even though `Option` has no default for `T`. fn apply_user_type_parameter_fallback(&self) { use self::TypeVariableOrigin::TypeParameterDefinition; use ty::OriginOfTyParam; - // Collect variables that are unsolved and support fallback, - // grouped by subtyping equivalence. + // grouped in bags by subtyping equivalence. let mut bags = FxHashMap(); for vid in self.fulfillment_cx.borrow().vars_in_unsolved_obligations() { let mut type_variables = self.infcx.type_variables.borrow_mut(); @@ -2199,9 +2215,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bags.entry(root).or_insert(Vec::new()).push(vid); } } - + // A bag will successfuly fallback to a default if all of it's variables + // have a default, and that default is the same. + // Low priority variables will be ignored in the presence of higher priority variables. 'bags: for (_, mut bag) in bags.into_iter() { - // Partition the bag by the origin of the default. + // Partition the bag by the origin of the type param. let (fn_or_impl, ty_def) = bag.into_iter().partition(|&v| { match self.infcx.type_variables.borrow().var_origin(v) { TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | @@ -2212,7 +2230,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); // Params from fns or impls take priority, if they exist ignore the rest of the bag. bag = fn_or_impl; - if bag.is_empty() { + if bag.is_empty() { bag = ty_def; } // For future-proofing against conflicting defaults, @@ -2233,7 +2251,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let normalized_default = self.normalize_associated_types_in( user_default.origin_span, &user_default.ty); - // QUESTION(leodasvacas): + // QUESTION(leodasvacas): // This will emit "expected type mismatch" on conflicting defaults, which is bad. // I'd be happy to somehow detect or rollback this demand on conflict defaults // so we would emit "type annotations needed" instead. From f27f976c55ef6ab6148be6d55e030bb96dd22d60 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 22 Nov 2017 18:30:27 -0200 Subject: [PATCH 19/35] Fix rebase conflict --- src/librustc_typeck/collect.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2438f6f66ccea..40647fba74447 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1037,6 +1037,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: Symbol::intern(""), def_id, has_default: false, + origin: ty::OriginOfTyParam::Other, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, synthetic: None, @@ -1048,6 +1049,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, name: Symbol::intern(""), def_id, has_default: false, + origin: ty::OriginOfTyParam::Other, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, synthetic: None, From bdda07ba43ee1e3720354e269f5ddb36bb9a58e1 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 23 Nov 2017 08:54:35 -0200 Subject: [PATCH 20/35] Set OriginOfTyParam for methods. Fixes bug with default fallback, and small refactorings to default fallback. --- src/librustc/traits/fulfill.rs | 4 +-- .../obligation_forest/mod.rs | 11 +++----- src/librustc_typeck/check/mod.rs | 13 ++++++---- src/librustc_typeck/collect.rs | 10 +++++-- ...ault_ty_param_fallback_method_call_test.rs | 24 +++++++++++++++++ .../default_ty_param_fallback_struct.rs | 23 ++++++++++++++++ .../default_ty_param_fallback_trait_impl.rs | 25 ++++++++++++++++++ ...ult_ty_param_fallback_trait_impl_simple.rs | 26 +++++++++++++++++++ .../default_ty_param_fallback_type_alias.rs | 19 ++++++++++++++ 9 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs create mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs create mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs create mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs create mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1d00ee9209a24..4575a3b55c02f 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -180,9 +180,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { self.predicates.pending_obligations() } - pub fn vars_in_unsolved_obligations(&self) -> FxHashSet { + pub fn vars_in_obligations(&self) -> FxHashSet { let mut vars = FxHashSet(); - for p in self.predicates.unsolved_obligations() { + for p in self.predicates.obligations() { for ty in p.obligation.predicate.walk_tys() { if let TypeVariants::TyInfer(InferTy::TyVar(vid)) = ty.sty { vars.insert(vid); diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 3292b88c9780b..ba4ec477eea26 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -244,16 +244,11 @@ impl ObligationForest { .collect() } - /// Returns the set of obligations that are in a pending or waiting state. - pub fn unsolved_obligations(&self) -> Vec + /// Returns all obligations. + pub fn obligations(&self) -> Vec where O: Clone { - self.nodes - .iter() - .filter(|n| n.state.get() == NodeState::Pending || - n.state.get() == NodeState::Waiting) - .map(|n| n.obligation.clone()) - .collect() + self.nodes.iter().map(|n| n.obligation.clone()).collect() } /// Perform a pass through the obligation list. This must diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 33100c8fbbf31..78ff5f7f00062 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2201,7 +2201,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Collect variables that are unsolved and support fallback, // grouped in bags by subtyping equivalence. let mut bags = FxHashMap(); - for vid in self.fulfillment_cx.borrow().vars_in_unsolved_obligations() { + for vid in self.fulfillment_cx.borrow().vars_in_obligations() { let mut type_variables = self.infcx.type_variables.borrow_mut(); let not_known = type_variables.probe(vid).is_none(); let supports_fallback = match type_variables.var_origin(vid) { @@ -2236,8 +2236,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // For future-proofing against conflicting defaults, // if one of the variables has no default, nothing is unified. for &vid in &bag { - match self.infcx.type_variables.borrow().default(vid) { - &Default::User(_) => {}, + let default = self.infcx.type_variables.borrow().default(vid).clone(); + debug!("apply_user_type_parameter_fallback: \ + checking var: {:?} with default: {:?}", vid, default); + match default { + Default::User(_) => {}, _ => continue 'bags, } } @@ -2245,8 +2248,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If future-proof, then all vars have defaults. let default = self.infcx.type_variables.borrow().default(vid).clone(); let ty = self.tcx.mk_var(vid); - debug!("apply_user_type_parameter_fallback: \ - ty: {:?} with default: {:?}", ty, default); + debug!("apply_user_type_parameter_fallback: applying fallback to var: {:?} \ + with ty: {:?} with default: {:?}", vid, ty, default); if let Default::User(user_default) = default { let normalized_default = self.normalize_associated_types_in( user_default.origin_span, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 40647fba74447..11e2ad7c4e7b3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -878,14 +878,20 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (ast_generics, opt_inputs) = match node { NodeTraitItem(item) => { match item.node { - TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + TraitItemKind::Method(ref sig, _) => { + origin = ty::OriginOfTyParam::Fn; + (&item.generics, Some(&sig.decl.inputs)) + } _ => (&item.generics, None) } } NodeImplItem(item) => { match item.node { - ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)), + ImplItemKind::Method(ref sig, _) => { + origin = ty::OriginOfTyParam::Fn; + (&item.generics, Some(&sig.decl.inputs)) + } _ => (&item.generics, None) } } diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs new file mode 100644 index 0000000000000..e8d93092ec53d --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +struct Foo; + +impl Foo { + fn method(&self) -> A { + A::default() + } +} + +fn main() { + let f = Foo.method(); + println!("{}", f); +} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs new file mode 100644 index 0000000000000..d9ac51fc23b02 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +struct Foo(A); + +impl Foo { + fn new() -> Foo { + Foo(A::default()) + } +} + +fn main() { + let foo = Foo::new(); +} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs new file mode 100644 index 0000000000000..c67d3a49aff3d --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// Another example from the RFC +trait Foo { } +trait Bar { } + +impl Foo for Vec {} +impl Bar for usize {} + +fn takes_foo(f: F) {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + takes_foo(x); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs new file mode 100644 index 0000000000000..067ad524922c0 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// An example from the RFC +trait Foo { fn takes_foo(&self); } +trait Bar { } + +impl Foo for Vec { + fn takes_foo(&self) {} +} + +impl Bar for usize {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + x.takes_foo(); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs new file mode 100644 index 0000000000000..1b4747406d0c6 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::collections::HashMap; + +type IntMap = HashMap; + +fn main() { + let x = IntMap::new(); +} From 385782669f014df75418b6c56402b8656f17b808 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 23 Nov 2017 09:43:22 -0200 Subject: [PATCH 21/35] Run pass tests. The happy kind of test. --- .../default_ty_param_fallback_trait_impl.rs | 25 ----------- ...ult_ty_param_fallback_trait_impl_simple.rs | 26 ----------- .../default_ty_param_fallback_type_alias.rs | 19 -------- .../dependent_associated_type.rs} | 6 +-- .../dependent_defaults.rs} | 9 +++- .../enum.rs} | 23 ++++++---- ...allback_struct.rs => fallback_in_impls.rs} | 0 .../method_call.rs} | 7 ++- .../struct.rs} | 2 +- .../trait_impl.rs} | 24 +++++++--- .../trait_impl_with_param_in_trait.rs | 45 +++++++++++++++++++ ...back_method_call_test.rs => type_alias.rs} | 13 +++--- ..._ty_param_fallback_default_over_literal.rs | 15 ------- ..._ty_param_fallback_ensure_normalization.rs | 16 ------- ...ty_param_fallback_struct_and_type_alias.rs | 40 ----------------- .../default_ty_param_fallback_type_alias.rs | 19 -------- 16 files changed, 102 insertions(+), 187 deletions(-) delete mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs delete mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs delete mode 100644 src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs rename src/test/run-pass/{default_ty_param_fallback_default_dependent_associated_type.rs => default-ty-param-fallback/dependent_associated_type.rs} (86%) rename src/test/run-pass/{default_ty_param_fallback_dependent_defaults.rs => default-ty-param-fallback/dependent_defaults.rs} (80%) rename src/test/run-pass/{default_ty_param_fallback_trait_impl_simple.rs => default-ty-param-fallback/enum.rs} (58%) rename src/test/run-pass/default-ty-param-fallback/{default_ty_param_fallback_struct.rs => fallback_in_impls.rs} (100%) rename src/test/run-pass/{default_ty_param_fallback_method_call_test.rs => default-ty-param-fallback/method_call.rs} (66%) rename src/test/run-pass/{default_ty_param_fallback_struct.rs => default-ty-param-fallback/struct.rs} (96%) rename src/test/run-pass/{default_ty_param_fallback_trait_impl.rs => default-ty-param-fallback/trait_impl.rs} (52%) create mode 100644 src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs rename src/test/run-pass/default-ty-param-fallback/{default_ty_param_fallback_method_call_test.rs => type_alias.rs} (67%) delete mode 100755 src/test/run-pass/default_ty_param_fallback_default_over_literal.rs delete mode 100644 src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs delete mode 100644 src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs delete mode 100644 src/test/run-pass/default_ty_param_fallback_type_alias.rs diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs deleted file mode 100644 index c67d3a49aff3d..0000000000000 --- a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -// Another example from the RFC -trait Foo { } -trait Bar { } - -impl Foo for Vec {} -impl Bar for usize {} - -fn takes_foo(f: F) {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - takes_foo(x); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs deleted file mode 100644 index 067ad524922c0..0000000000000 --- a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_trait_impl_simple.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -// An example from the RFC -trait Foo { fn takes_foo(&self); } -trait Bar { } - -impl Foo for Vec { - fn takes_foo(&self) {} -} - -impl Bar for usize {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - x.takes_foo(); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs b/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs deleted file mode 100644 index 1b4747406d0c6..0000000000000 --- a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_type_alias.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -use std::collections::HashMap; - -type IntMap = HashMap; - -fn main() { - let x = IntMap::new(); -} diff --git a/src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs similarity index 86% rename from src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs rename to src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs index 8fc2c2e6bce70..f2585000a924c 100644 --- a/src/test/run-pass/default_ty_param_fallback_default_dependent_associated_type.rs +++ b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs @@ -21,16 +21,16 @@ impl Id for A { type This = A; } -struct Foo::This> { +struct Foo { data: PhantomData<(X, Y)> } -impl Foo { +impl::This> Foo { fn new() -> Foo { Foo { data: PhantomData } } } fn main() { - let foo = Foo::new(); + let _ = Foo::new(); } diff --git a/src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs b/src/test/run-pass/default-ty-param-fallback/dependent_defaults.rs similarity index 80% rename from src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs rename to src/test/run-pass/default-ty-param-fallback/dependent_defaults.rs index ac833d0f54744..3b77caf963b6f 100644 --- a/src/test/run-pass/default_ty_param_fallback_dependent_defaults.rs +++ b/src/test/run-pass/default-ty-param-fallback/dependent_defaults.rs @@ -12,8 +12,15 @@ #![feature(default_type_parameter_fallback)] use std::marker::PhantomData; +#[allow(dead_code)] struct Foo { t: T, data: PhantomData } +impl Foo { + fn new(t: T) -> Foo { + Foo { t, data: PhantomData } + } +} + fn main() { - let foo = Foo { t: 'a', data: PhantomData }; + let _ = Foo::new('a'); } diff --git a/src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs b/src/test/run-pass/default-ty-param-fallback/enum.rs similarity index 58% rename from src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs rename to src/test/run-pass/default-ty-param-fallback/enum.rs index 067ad524922c0..54d7b454047d0 100644 --- a/src/test/run-pass/default_ty_param_fallback_trait_impl_simple.rs +++ b/src/test/run-pass/default-ty-param-fallback/enum.rs @@ -10,17 +10,22 @@ #![feature(default_type_parameter_fallback)] -// An example from the RFC -trait Foo { fn takes_foo(&self); } -trait Bar { } +use std::path::Path; -impl Foo for Vec { - fn takes_foo(&self) {} +enum Opt { + Som(T), + Non, } -impl Bar for usize {} - fn main() { - let x = Vec::new(); // x: Vec<$0> - x.takes_foo(); // adds oblig Vec<$0> : Foo + // Defaults on the type definiton work, as long no other params are interfering. + let _ = Opt::Non; + let _: Opt<_> = Opt::Non; + + func1(None); + func2(Opt::Non); } + +// Defaults on fns take precedence. +fn func1 = String>(p: Option

) { } +fn func2 = String>(p: Opt

) { } -fn func2 = String>(p: Opt

) { } +fn func1 = &'static str>(p: Option

) { + // Testing that we got &str rather than String. + assert_eq!(size_of::

(), size_of::<&str>()) +} + +fn func2 = &'static str>(p: Opt

) { + assert_eq!(size_of::

(), size_of::<&str>()) +} diff --git a/src/test/run-pass/default-ty-param-fallback/heterogeneous_partial_eq_for_option.rs b/src/test/run-pass/default-ty-param-fallback/heterogeneous_partial_eq_for_option.rs new file mode 100644 index 0000000000000..88e9ac0ea7e41 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/heterogeneous_partial_eq_for_option.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +trait PartialQe { + fn qe(&self, _: &Rhs) {} +} + +impl PartialQe> for Option {} + +fn main() { + PartialQe::qe(&Some("str"), &None); + Some('a').qe(&None); +} diff --git a/src/test/run-pass/default-ty-param-fallback/trait_impl.rs b/src/test/run-pass/default-ty-param-fallback/trait_impl.rs index d79863cc5fbb1..085bd3f74a053 100644 --- a/src/test/run-pass/default-ty-param-fallback/trait_impl.rs +++ b/src/test/run-pass/default-ty-param-fallback/trait_impl.rs @@ -29,7 +29,7 @@ fn takes_foo(_: F) {} fn main() { let x = Vac::new(); // x: Vac<$0> // adds oblig Vac<$0> : Foo, - // and applies the default of `impl Vac` and + // and applies the default of `impl Vac` and // `impl Foo for Vac`, which must agree. // // The default of F in takes_foo makes no difference here, diff --git a/src/test/compile-fail/auxiliary/default_ty_param_cross_crate_crate.rs b/src/test/ui/default-ty-param-fallback/bad_messages/auxiliary/default_ty_param_cross_crate_crate.rs similarity index 100% rename from src/test/compile-fail/auxiliary/default_ty_param_cross_crate_crate.rs rename to src/test/ui/default-ty-param-fallback/bad_messages/auxiliary/default_ty_param_cross_crate_crate.rs diff --git a/src/test/compile-fail/default_ty_param_fallback_conflict.rs b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs similarity index 71% rename from src/test/compile-fail/default_ty_param_fallback_conflict.rs rename to src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs index 48c5cd1ff7706..b0d12f1d683f8 100644 --- a/src/test/compile-fail/default_ty_param_fallback_conflict.rs +++ b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs @@ -14,19 +14,13 @@ use std::fmt::Debug; // Example from the RFC fn foo() -> F { F::default() } -//~^ NOTE: a default was defined here... fn bar(b: B) { println!("{:?}", b); } -//~^ NOTE: a second default was defined here... fn main() { // Here, F is instantiated with $0=uint let x = foo(); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: ...that was applied to an unconstrained type variable here // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. bar(x); - //~^ NOTE: ...that also applies to the same type variable here } diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr new file mode 100644 index 0000000000000..12fc985d97335 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr @@ -0,0 +1,8 @@ +error[E0308]: mismatched types + --> $DIR/fallback_conflict.rs:25:9 + | +25 | bar(x); + | ^ expected isize, found usize + +error: aborting due to previous error + diff --git a/src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs similarity index 77% rename from src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs rename to src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs index 4d60724372ada..70eb9e6fba905 100644 --- a/src/test/compile-fail/default_ty_param_fallback_conflict_cross_crate.rs +++ b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs @@ -17,13 +17,9 @@ extern crate default_param_test; use default_param_test::{Foo, bleh}; fn meh(x: Foo) {} -//~^ NOTE: a default was defined here... fn main() { let foo = bleh(); - //~^ NOTE: ...that also applies to the same type variable here meh(foo); - //~^ ERROR: mismatched types: - //~| NOTE: conflicting type parameter defaults `bool` and `char` } diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr new file mode 100644 index 0000000000000..364376fc998c5 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr @@ -0,0 +1,8 @@ +error[E0308]: mismatched types + --> $DIR/fallback_conflict_cross_crate.rs:24:9 + | +24 | meh(foo); + | ^^^ expected bool, found char + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs new file mode 100644 index 0000000000000..8fc2c2e6bce70 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +trait Id { + type This; +} + +impl Id for A { + type This = A; +} + +struct Foo::This> { + data: PhantomData<(X, Y)> +} + +impl Foo { + fn new() -> Foo { + Foo { data: PhantomData } + } +} + +fn main() { + let foo = Foo::new(); +} diff --git a/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.stderr b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.stderr new file mode 100644 index 0000000000000..e67f7aa8722a9 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.stderr @@ -0,0 +1,10 @@ +error[E0283]: type annotations required: cannot resolve `_: std::default::Default` + --> $DIR/default_dependent_associated_type.rs:35:15 + | +35 | let foo = Foo::new(); + | ^^^^^^^^ + | + = note: required by `>::new` + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/dependent_defaults.rs b/src/test/ui/default-ty-param-fallback/dependent_defaults.rs new file mode 100644 index 0000000000000..ac833d0f54744 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/dependent_defaults.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] +use std::marker::PhantomData; + +struct Foo { t: T, data: PhantomData } + +fn main() { + let foo = Foo { t: 'a', data: PhantomData }; +} diff --git a/src/test/ui/default-ty-param-fallback/dependent_defaults.stderr b/src/test/ui/default-ty-param-fallback/dependent_defaults.stderr new file mode 100644 index 0000000000000..1188d498ff40a --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/dependent_defaults.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/dependent_defaults.rs:18:15 + | +18 | let foo = Foo { t: 'a', data: PhantomData }; + | --- ^^^ cannot infer type for `U` + | | + | consider giving `foo` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/feature_gate.rs b/src/test/ui/default-ty-param-fallback/feature_gate.rs new file mode 100644 index 0000000000000..8b3e1674cc6b4 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/feature_gate.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Opt { + Som(T), + Non, +} + +fn main() { + Opt::Non; +} diff --git a/src/test/ui/default-ty-param-fallback/feature_gate.stderr b/src/test/ui/default-ty-param-fallback/feature_gate.stderr new file mode 100644 index 0000000000000..1f7d981993324 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/feature_gate.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/feature_gate.rs:17:5 + | +17 | Opt::Non; + | ^^^^^^^^ cannot infer type for `T` + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs b/src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs new file mode 100644 index 0000000000000..54d7b454047d0 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::path::Path; + +enum Opt { + Som(T), + Non, +} + +fn main() { + // Defaults on the type definiton work, as long no other params are interfering. + let _ = Opt::Non; + let _: Opt<_> = Opt::Non; + + func1(None); + func2(Opt::Non); +} + +// Defaults on fns take precedence. +fn func1 = String>(p: Option

) { } +fn func2 = String>(p: Opt

) { } diff --git a/src/test/ui/default-ty-param-fallback/future_proof.rs b/src/test/ui/default-ty-param-fallback/future_proof.rs new file mode 100644 index 0000000000000..7a28ffd6089b4 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/future_proof.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::path::Path; + +fn func = String>(p: Option

) { + match p { + None => { println!("None"); } + Some(path) => { println!("{:?}", path.as_ref()); } + } +} + +fn main() { + // Dont fallback to future-proof against default on `noner`. + func(noner()); +} + +fn noner() -> Option { None } diff --git a/src/test/ui/default-ty-param-fallback/future_proof.stderr b/src/test/ui/default-ty-param-fallback/future_proof.stderr new file mode 100644 index 0000000000000..68bd854935634 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/future_proof.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/future_proof.rs:24:5 + | +24 | func(noner()); + | ^^^^ cannot infer type for `P` + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/method_call_test.rs b/src/test/ui/default-ty-param-fallback/method_call_test.rs new file mode 100644 index 0000000000000..e8d93092ec53d --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/method_call_test.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +struct Foo; + +impl Foo { + fn method(&self) -> A { + A::default() + } +} + +fn main() { + let f = Foo.method(); + println!("{}", f); +} diff --git a/src/test/ui/default-ty-param-fallback/method_call_test.stderr b/src/test/ui/default-ty-param-fallback/method_call_test.stderr new file mode 100644 index 0000000000000..7362c7f6686e2 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/method_call_test.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/method_call_test.rs:22:9 + | +22 | let f = Foo.method(); + | ^ + | | + | cannot infer type for `_` + | consider giving `f` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs new file mode 100644 index 0000000000000..6e3e60a02e5e2 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +struct DeterministicHasher; +struct RandomHasher; + + +struct MyHashMap { + data: PhantomData<(K, V, H)> +} + +impl MyHashMap { + fn new() -> MyHashMap { + MyHashMap { data: PhantomData } + } +} + +mod mystd { + use super::{MyHashMap, RandomHasher}; + pub type HashMap = MyHashMap; +} + +fn try_me(hash_map: mystd::HashMap) {} + +fn main() { + let hash_map = mystd::HashMap::new(); + try_me(hash_map); +} diff --git a/src/test/ui/default-ty-param-fallback/struct_and_type_alias.stderr b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.stderr new file mode 100644 index 0000000000000..fd012aa11fe89 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/struct_and_type_alias.rs:38:20 + | +38 | let hash_map = mystd::HashMap::new(); + | -------- ^^^^^^^^^^^^^^^^^^^ cannot infer type for `H` + | | + | consider giving `hash_map` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/trait_impl.rs b/src/test/ui/default-ty-param-fallback/trait_impl.rs new file mode 100644 index 0000000000000..c67d3a49aff3d --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_impl.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// Another example from the RFC +trait Foo { } +trait Bar { } + +impl Foo for Vec {} +impl Bar for usize {} + +fn takes_foo(f: F) {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + takes_foo(x); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/ui/default-ty-param-fallback/trait_impl.stderr b/src/test/ui/default-ty-param-fallback/trait_impl.stderr new file mode 100644 index 0000000000000..2c5d0e1955908 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_impl.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/trait_impl.rs:23:13 + | +23 | let x = Vec::new(); // x: Vec<$0> + | - ^^^^^^^^ cannot infer type for `T` + | | + | consider giving `x` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs b/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs new file mode 100644 index 0000000000000..067ad524922c0 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +// An example from the RFC +trait Foo { fn takes_foo(&self); } +trait Bar { } + +impl Foo for Vec { + fn takes_foo(&self) {} +} + +impl Bar for usize {} + +fn main() { + let x = Vec::new(); // x: Vec<$0> + x.takes_foo(); // adds oblig Vec<$0> : Foo +} diff --git a/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr b/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr new file mode 100644 index 0000000000000..1d4c015da981c --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/trait_impl_simple.rs:24:13 + | +24 | let x = Vec::new(); // x: Vec<$0> + | - ^^^^^^^^ cannot infer type for `T` + | | + | consider giving `x` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/type_alias.rs b/src/test/ui/default-ty-param-fallback/type_alias.rs new file mode 100644 index 0000000000000..1b4747406d0c6 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/type_alias.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::collections::HashMap; + +type IntMap = HashMap; + +fn main() { + let x = IntMap::new(); +} diff --git a/src/test/ui/default-ty-param-fallback/type_alias.stderr b/src/test/ui/default-ty-param-fallback/type_alias.stderr new file mode 100644 index 0000000000000..29cedc4e8dce9 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/type_alias.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/type_alias.rs:18:13 + | +18 | let x = IntMap::new(); + | - ^^^^^^^^^^^ cannot infer type for `K` + | | + | consider giving `x` a type + +error: aborting due to previous error + From 0bd87ef75a57f497337ab178f12f4e67e19ae873 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 25 Nov 2017 17:21:44 -0200 Subject: [PATCH 23/35] Adjust fallback algorithm. We only demand equality when we are sure now, fixing bad error messages. We also skip a priority level if we detect a conflict, an improvement over the previous algorithm. But there is a bug related to normalizing dependent defaults, see FIXME. --- src/librustc/infer/type_variable.rs | 10 ++ src/librustc_typeck/check/mod.rs | 92 ++++++++++--------- .../skip_conflict.rs | 37 ++++++++ .../default_ty_param_cross_crate_crate.rs | 0 .../bad_messages/fallback_conflict.stderr | 8 -- .../fallback_conflict_cross_crate.stderr | 8 -- .../{bad_messages => }/fallback_conflict.rs | 0 .../fallback_conflict.stderr | 11 +++ .../fallback_conflict_cross_crate.rs | 0 .../fallback_conflict_cross_crate.stderr | 10 ++ 10 files changed, 119 insertions(+), 57 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/skip_conflict.rs rename src/test/ui/default-ty-param-fallback/{bad_messages => }/auxiliary/default_ty_param_cross_crate_crate.rs (100%) delete mode 100644 src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr delete mode 100644 src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr rename src/test/ui/default-ty-param-fallback/{bad_messages => }/fallback_conflict.rs (100%) create mode 100644 src/test/ui/default-ty-param-fallback/fallback_conflict.stderr rename src/test/ui/default-ty-param-fallback/{bad_messages => }/fallback_conflict_cross_crate.rs (100%) create mode 100644 src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 030f877d1e1b6..cf3f179bed9c0 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -92,6 +92,16 @@ pub enum Default<'tcx> { None, } +impl<'tcx> Default<'tcx> { + pub fn get_user(&self) -> Option> { + match *self { + Default::User(ref user_default) => Some(user_default.clone()), + Default::None => None, + _ => bug!("Default exists but is not user"), + } + } +} + // We will use this to store the required information to recapitulate // what happened when an error occurs. #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 78ff5f7f00062..bb9f3d684fec7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,7 +90,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; use namespace::Namespace; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; -use rustc::infer::type_variable::{TypeVariableOrigin, Default}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::middle::region; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; @@ -2185,13 +2185,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// will have `String` as its default. /// /// Adding a default to a type parameter that has none should be backwards compatible. - /// However if we get conflicting defaults we do not know how to resolve them. - /// Therefore we must future-proof against such a conflict by not allowing - /// type variables with defaults to unify with type variables without defaults. + /// Therefore we take care to future-proof against conflicting defaults. /// - /// We may come up with rules to prioritize a type parameter over another. - /// When unifying type variables, the highest priority parameter involved - /// has the final say on what the default should be. /// Currently we prioritize defaults from impls and fns over defaults in types, /// this for example allows `fn foo(x: Option)` to work /// even though `Option` has no default for `T`. @@ -2215,10 +2210,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bags.entry(root).or_insert(Vec::new()).push(vid); } } - // A bag will successfuly fallback to a default if all of it's variables - // have a default, and that default is the same. - // Low priority variables will be ignored in the presence of higher priority variables. - 'bags: for (_, mut bag) in bags.into_iter() { + + // Attempt to find a fallback for each bag. + for (_, bag) in bags { // Partition the bag by the origin of the type param. let (fn_or_impl, ty_def) = bag.into_iter().partition(|&v| { match self.infcx.type_variables.borrow().var_origin(v) { @@ -2228,37 +2222,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => bug!("type var does not support fallback") } }); - // Params from fns or impls take priority, if they exist ignore the rest of the bag. - bag = fn_or_impl; - if bag.is_empty() { - bag = ty_def; - } - // For future-proofing against conflicting defaults, - // if one of the variables has no default, nothing is unified. - for &vid in &bag { - let default = self.infcx.type_variables.borrow().default(vid).clone(); - debug!("apply_user_type_parameter_fallback: \ - checking var: {:?} with default: {:?}", vid, default); - match default { - Default::User(_) => {}, - _ => continue 'bags, + // Params from fns or impls have higher priority than those from type definitions. + // We consider the priority levels in order and stop at the first success or failure: + // We succeed if all defaults exist and agree. + // We fail if existing defaults agree but there are missing defaults. + // We continue if the priority level is empty or if there are any disagreements. + let priority_levels: Vec> = vec![fn_or_impl, ty_def]; + 'priority_levels: for priority_level in priority_levels { + if priority_level.is_empty() { + continue; } - } - for &vid in &bag { - // If future-proof, then all vars have defaults. - let default = self.infcx.type_variables.borrow().default(vid).clone(); - let ty = self.tcx.mk_var(vid); - debug!("apply_user_type_parameter_fallback: applying fallback to var: {:?} \ - with ty: {:?} with default: {:?}", vid, ty, default); - if let Default::User(user_default) = default { - let normalized_default = self.normalize_associated_types_in( - user_default.origin_span, - &user_default.ty); - // QUESTION(leodasvacas): - // This will emit "expected type mismatch" on conflicting defaults, which is bad. - // I'd be happy to somehow detect or rollback this demand on conflict defaults - // so we would emit "type annotations needed" instead. - self.demand_eqtype(user_default.origin_span, &ty, normalized_default); + let normalized_default = |&vid| { + let default = self.infcx.type_variables.borrow().default(vid).get_user(); + default.map(|d| self.normalize_associated_types_in(d.origin_span, &d.ty)) + }; + let mut existing_defaults = priority_level.iter().filter_map(&normalized_default); + let equivalent_default = match existing_defaults.next() { + Some(default) => default, + None => break, // Failed, no params have defaults at this level. + }; + + // If there are conflicting defaults, skip this level. + // FIXME(leodasvacas): In a case like `impl::This>`, + // as found in the test "dependent_associated_type.rs", + // if `Y` is normalized before the default of `X` is applied, + // then it's normalized to `TyInfer`, so we use a fragile workaround here. + // If it is `Y = Vec<::This>` we are in trouble again. + // Type equality that considers all inference variables equal is a correct fix. + if existing_defaults.any(|default| match (&default.sty, &equivalent_default.sty) { + (&ty::TyInfer(_), &ty::TyInfer(_)) => false, + (ref a, ref b) => **a != **b + }) + { + debug!("apply_user_type_parameter_fallback: skipping priority level"); + continue; + } + // All existing defaults agree, but for future-proofing + // we must fail if there is a param with no default. + if priority_level.iter().any(|vid| normalized_default(vid) == None) { + break; + } + // All defaults exist and agree, apply the default and succeed. + for &vid in &priority_level { + let ty = self.tcx.mk_var(vid); + debug!("apply_user_type_parameter_fallback: applying fallback to var: {:?} \ + with ty: {:?} with default: {:?}", vid, ty, equivalent_default); + self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); + break 'priority_levels; } } } diff --git a/src/test/run-pass/default-ty-param-fallback/skip_conflict.rs b/src/test/run-pass/default-ty-param-fallback/skip_conflict.rs new file mode 100644 index 0000000000000..49e5a28aba4a6 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/skip_conflict.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::path::Path; +use std::mem::size_of; + +enum Opt { + Som(T), + Non, +} + +fn main() { + // func1 and func2 cannot agree so we apply the fallback from the type. + let x = Opt::Non; + func1(&x); + func2(&x); +} + +// Defaults on fns take precedence. +fn func1 = &'static str>(_: &Opt

) { + // Testing that we got String. + assert_eq!(size_of::

(), size_of::()) +} + +fn func2 = &'static &'static str>(_: &Opt

) { + // Testing that we got String. + assert_eq!(size_of::

(), size_of::()) +} diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/auxiliary/default_ty_param_cross_crate_crate.rs b/src/test/ui/default-ty-param-fallback/auxiliary/default_ty_param_cross_crate_crate.rs similarity index 100% rename from src/test/ui/default-ty-param-fallback/bad_messages/auxiliary/default_ty_param_cross_crate_crate.rs rename to src/test/ui/default-ty-param-fallback/auxiliary/default_ty_param_cross_crate_crate.rs diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr deleted file mode 100644 index 12fc985d97335..0000000000000 --- a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/fallback_conflict.rs:25:9 - | -25 | bar(x); - | ^ expected isize, found usize - -error: aborting due to previous error - diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr b/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr deleted file mode 100644 index 364376fc998c5..0000000000000 --- a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/fallback_conflict_cross_crate.rs:24:9 - | -24 | meh(foo); - | ^^^ expected bool, found char - -error: aborting due to previous error - diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs b/src/test/ui/default-ty-param-fallback/fallback_conflict.rs similarity index 100% rename from src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs rename to src/test/ui/default-ty-param-fallback/fallback_conflict.rs diff --git a/src/test/ui/default-ty-param-fallback/fallback_conflict.stderr b/src/test/ui/default-ty-param-fallback/fallback_conflict.stderr new file mode 100644 index 0000000000000..bef89b2d19bf4 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/fallback_conflict.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/fallback_conflict.rs:22:9 + | +22 | let x = foo(); + | ^ + | | + | cannot infer type for `_` + | consider giving `x` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs similarity index 100% rename from src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs rename to src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs diff --git a/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr new file mode 100644 index 0000000000000..effb300eb6c87 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/fallback_conflict_cross_crate.rs:22:15 + | +22 | let foo = bleh(); + | --- ^^^^ cannot infer type for `A` + | | + | consider giving `foo` a type + +error: aborting due to previous error + From babfa76b7c4b723ce4c76ea6c2592e32de9dc2d7 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sun, 26 Nov 2017 12:22:05 -0200 Subject: [PATCH 24/35] Get normalization of dependent defaults right. Since this means there are cross-bag dependencies, we use a fixed point algorithm, looping over the bags until we can no longer solve any of them. --- src/librustc/infer/type_variable.rs | 2 +- src/librustc_typeck/check/mod.rs | 147 +++++++++++------- .../dependent_associated_type.rs | 13 +- 3 files changed, 97 insertions(+), 65 deletions(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index cf3f179bed9c0..4dd0bf98e8b32 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -93,7 +93,7 @@ pub enum Default<'tcx> { } impl<'tcx> Default<'tcx> { - pub fn get_user(&self) -> Option> { + pub fn as_user(&self) -> Option> { match *self { Default::User(ref user_default) => Some(user_default.clone()), Default::None => None, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bb9f3d684fec7..53cfd7917bd5b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,6 +113,7 @@ use std::rc::Rc; use std::collections::hash_map::Entry; use std::cmp; use std::fmt::Display; +use std::iter::FromIterator; use std::mem::replace; use std::ops::{self, Deref}; use syntax::abi::Abi; @@ -2001,6 +2002,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value) } + fn eager_normalize_in(&self, span: Span, value: &T) -> Option + where T : TypeFoldable<'tcx> + { + let infer_ok = self.inh.partially_normalize_associated_types_in(span, + self.body_id, + self.param_env, + value); + if infer_ok.obligations.is_empty() { + Some(infer_ok.value) + } else { + self.inh.register_predicates(infer_ok.obligations); + self.select_obligations_where_possible(); + let resolved = self.resolve_type_vars_if_possible(&infer_ok.value); + if !resolved.needs_infer() { + Some(resolved) + } else { + None + } + } + } + pub fn require_type_meets(&self, ty: Ty<'tcx>, span: Span, @@ -2210,67 +2232,76 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bags.entry(root).or_insert(Vec::new()).push(vid); } } - + // Discard key, bags is a sequence of pairs (bag, done). + let mut bags = Vec::from_iter(bags.into_iter().map(|b| b.1).map(|b| (b, false))); // Attempt to find a fallback for each bag. - for (_, bag) in bags { - // Partition the bag by the origin of the type param. - let (fn_or_impl, ty_def) = bag.into_iter().partition(|&v| { - match self.infcx.type_variables.borrow().var_origin(v) { - TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | - TypeParameterDefinition(_, _, OriginOfTyParam::Impl) => true, - TypeParameterDefinition(_, _, OriginOfTyParam::TyDef) => false, - _ => bug!("type var does not support fallback") - } - }); - // Params from fns or impls have higher priority than those from type definitions. - // We consider the priority levels in order and stop at the first success or failure: - // We succeed if all defaults exist and agree. - // We fail if existing defaults agree but there are missing defaults. - // We continue if the priority level is empty or if there are any disagreements. - let priority_levels: Vec> = vec![fn_or_impl, ty_def]; - 'priority_levels: for priority_level in priority_levels { - if priority_level.is_empty() { - continue; - } - let normalized_default = |&vid| { - let default = self.infcx.type_variables.borrow().default(vid).get_user(); - default.map(|d| self.normalize_associated_types_in(d.origin_span, &d.ty)) - }; - let mut existing_defaults = priority_level.iter().filter_map(&normalized_default); - let equivalent_default = match existing_defaults.next() { - Some(default) => default, - None => break, // Failed, no params have defaults at this level. - }; - - // If there are conflicting defaults, skip this level. - // FIXME(leodasvacas): In a case like `impl::This>`, - // as found in the test "dependent_associated_type.rs", - // if `Y` is normalized before the default of `X` is applied, - // then it's normalized to `TyInfer`, so we use a fragile workaround here. - // If it is `Y = Vec<::This>` we are in trouble again. - // Type equality that considers all inference variables equal is a correct fix. - if existing_defaults.any(|default| match (&default.sty, &equivalent_default.sty) { - (&ty::TyInfer(_), &ty::TyInfer(_)) => false, - (ref a, ref b) => **a != **b - }) - { - debug!("apply_user_type_parameter_fallback: skipping priority level"); - continue; - } - // All existing defaults agree, but for future-proofing - // we must fail if there is a param with no default. - if priority_level.iter().any(|vid| normalized_default(vid) == None) { - break; - } - // All defaults exist and agree, apply the default and succeed. - for &vid in &priority_level { - let ty = self.tcx.mk_var(vid); - debug!("apply_user_type_parameter_fallback: applying fallback to var: {:?} \ - with ty: {:?} with default: {:?}", vid, ty, equivalent_default); - self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); - break 'priority_levels; + loop { + // For dependent defaults, solving a bag + // might allow us to normalize an associated type in another bag. + // For example in `impl::Type>`. + // Therefore we loop over the bags until we are at a fixed point. + let mut fixed_point = true; + // Loop over bags that are not done. + 'bags: for &mut(ref bag, ref mut done) in bags.iter_mut().filter(|bag| !bag.1) { + // Partition the bag by the origin of the type param. + let (fn_or_impl, ty_def) = bag.iter().partition(|&&v| { + match self.infcx.type_variables.borrow().var_origin(v) { + TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | + TypeParameterDefinition(_, _, OriginOfTyParam::Impl) => true, + TypeParameterDefinition(_, _, OriginOfTyParam::TyDef) => false, + _ => bug!("type var does not support fallback") + } + }); + // Params from fns or impls have higher priority than those from type definitions. + // Consider the priority levels in order: + // Try again later if a default can't be normalized. + // Succeed if all defaults exist and agree. + // Fail if existing defaults agree but there are missing defaults. + // Skip the priority level if it's empty or there are disagreements. + let priority_levels: Vec> = vec![fn_or_impl, ty_def]; + 'priority_levels: for priority_level in priority_levels { + if priority_level.is_empty() { + continue; + } + let get_default = |&v| self.infcx.type_variables.borrow().default(v).as_user(); + let mut existing_defaults = Vec::new(); + for default in priority_level.iter().filter_map(&get_default) { + match self.eager_normalize_in(default.origin_span, &default.ty) { + Some(def) => existing_defaults.push(def), + None => continue 'bags, // Try again later. + } + } + let mut existing_defaults = existing_defaults.iter(); + let equivalent_default = match existing_defaults.next() { + Some(default) => default, + None => break, // Failed, no params have defaults at this level. + }; + // On conflicting defaults, skip this level. + if existing_defaults.any(|&default| default.sty != equivalent_default.sty) { + debug!("apply_user_type_parameter_fallback: skipping priority level"); + continue; + } + // All existing defaults agree, but for future-proofing + // we must fail if there is a param with no default. + if priority_level.iter().any(|vid| get_default(vid) == None) { + break; + } + // All defaults exist and agree, apply the default and succeed. + for &vid in &priority_level { + let ty = self.tcx.mk_var(vid); + self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); + debug!("apply_user_type_parameter_fallback: applied fallback to var: {:?} \ + with ty: {:?} with default: {:?}", vid, ty, equivalent_default); + // Progress was made. + fixed_point = false; + *done = true; + break 'priority_levels; + } } } + if fixed_point { + break; + } } } diff --git a/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs index f2585000a924c..80ef398a831b4 100644 --- a/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs +++ b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type.rs @@ -14,19 +14,20 @@ use std::marker::PhantomData; trait Id { - type This; + type Me; } impl Id for A { - type This = A; + type Me = A; } -struct Foo { - data: PhantomData<(X, Y)> +struct Foo { + data: PhantomData<(X, Y, Z, W)>, } -impl::This> Foo { - fn new() -> Foo { +impl::Me, Z = ::Me, W = Vec<::Me>> + Foo { + fn new() -> Foo { Foo { data: PhantomData } } } From 14a9420b8cb2fa71e262b690ff91e089ba853341 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sun, 26 Nov 2017 14:55:55 -0200 Subject: [PATCH 25/35] Fallback: Don't skip conflicting defaults. While this was future-proof wrt API evolution, it is not future proof wrt to compiler evolution, such as making priority levels more fine-grained or just fixing bugs. It's a not very useful behavior and a complexity this feature doesn't need. Refactored the fallback algorithm to be simpler. Just fails on conflicting defaults. --- src/librustc_typeck/check/mod.rs | 72 +++++++++---------- .../type_alias_see_through.rs | 23 ++++++ .../dont_skip_conflict.rs} | 16 ++--- .../dont_skip_conflict.stderr | 10 +++ 4 files changed, 71 insertions(+), 50 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/type_alias_see_through.rs rename src/test/{run-pass/default-ty-param-fallback/skip_conflict.rs => ui/default-ty-param-fallback/dont_skip_conflict.rs} (62%) create mode 100644 src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 53cfd7917bd5b..1c6188129c350 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2209,9 +2209,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Adding a default to a type parameter that has none should be backwards compatible. /// Therefore we take care to future-proof against conflicting defaults. /// - /// Currently we prioritize defaults from impls and fns over defaults in types, + /// Currently we prioritize params from impls and fns over params in types, /// this for example allows `fn foo(x: Option)` to work /// even though `Option` has no default for `T`. + /// Lower priority defaults are considered when there are no higher priority params involved. fn apply_user_type_parameter_fallback(&self) { use self::TypeVariableOrigin::TypeParameterDefinition; use ty::OriginOfTyParam; @@ -2253,51 +2254,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }); // Params from fns or impls have higher priority than those from type definitions. - // Consider the priority levels in order: - // Try again later if a default can't be normalized. - // Succeed if all defaults exist and agree. - // Fail if existing defaults agree but there are missing defaults. - // Skip the priority level if it's empty or there are disagreements. - let priority_levels: Vec> = vec![fn_or_impl, ty_def]; - 'priority_levels: for priority_level in priority_levels { - if priority_level.is_empty() { - continue; - } - let get_default = |&v| self.infcx.type_variables.borrow().default(v).as_user(); - let mut existing_defaults = Vec::new(); - for default in priority_level.iter().filter_map(&get_default) { + // The first non-empty priority level is considered. + let mut bag: Vec = fn_or_impl; + if bag.is_empty() { + bag = ty_def; + } + // - Try again later if a default can't be normalized. + // - Fail if there are conflicting or missing defaults. + // - Succeess if all defaults exist and agree. + let get_default = |&v| self.infcx.type_variables.borrow().default(v).as_user(); + let mut normalized_defaults = Vec::new(); + for default in bag.iter().map(&get_default) { + if let Some(default) = default { match self.eager_normalize_in(default.origin_span, &default.ty) { - Some(def) => existing_defaults.push(def), + Some(default) => normalized_defaults.push(default), None => continue 'bags, // Try again later. } - } - let mut existing_defaults = existing_defaults.iter(); - let equivalent_default = match existing_defaults.next() { - Some(default) => default, - None => break, // Failed, no params have defaults at this level. - }; - // On conflicting defaults, skip this level. - if existing_defaults.any(|&default| default.sty != equivalent_default.sty) { - debug!("apply_user_type_parameter_fallback: skipping priority level"); - continue; - } - // All existing defaults agree, but for future-proofing - // we must fail if there is a param with no default. - if priority_level.iter().any(|vid| get_default(vid) == None) { - break; - } - // All defaults exist and agree, apply the default and succeed. - for &vid in &priority_level { - let ty = self.tcx.mk_var(vid); - self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); - debug!("apply_user_type_parameter_fallback: applied fallback to var: {:?} \ - with ty: {:?} with default: {:?}", vid, ty, equivalent_default); - // Progress was made. - fixed_point = false; + } else { + // Fail, missing default. *done = true; - break 'priority_levels; + continue 'bags; } } + let equivalent_default = normalized_defaults[0]; + // Fail on conflicting defaults. + if normalized_defaults.iter().any(|&d| d.sty != equivalent_default.sty) { + break; + } + // All defaults exist and agree, success, apply the default. + fixed_point = false; + *done = true; + for &vid in &bag { + let ty = self.tcx.mk_var(vid); + self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); + debug!("apply_user_type_parameter_fallback: applied fallback to var: {:?} \ + with ty: {:?} with default: {:?}", vid, ty, equivalent_default); + } } if fixed_point { break; diff --git a/src/test/run-pass/default-ty-param-fallback/type_alias_see_through.rs b/src/test/run-pass/default-ty-param-fallback/type_alias_see_through.rs new file mode 100644 index 0000000000000..d25e3a2e8a217 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/type_alias_see_through.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +type Strang = &'static str; + +fn main() { + let a = None; + func1(a); + func2(a); +} + +// Defaults on fns take precedence. +fn func1

(_: Option

) {} +fn func2

(_: Option

) {} diff --git a/src/test/run-pass/default-ty-param-fallback/skip_conflict.rs b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs similarity index 62% rename from src/test/run-pass/default-ty-param-fallback/skip_conflict.rs rename to src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs index 49e5a28aba4a6..ddb2432ac1bb9 100644 --- a/src/test/run-pass/default-ty-param-fallback/skip_conflict.rs +++ b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs @@ -19,19 +19,15 @@ enum Opt { } fn main() { - // func1 and func2 cannot agree so we apply the fallback from the type. + // func1 and func2 cannot agree so we fail. + // NB: While it would be future-proof wrt API evolution to use the `String` default in `Opt`, + // that is not future proof wrt to compiler evolution, + // such as making priority levels more fine-grained or just fixing bugs. let x = Opt::Non; func1(&x); func2(&x); } -// Defaults on fns take precedence. -fn func1 = &'static str>(_: &Opt

) { - // Testing that we got String. - assert_eq!(size_of::

(), size_of::()) -} +fn func1 = &'static str>(_: &Opt

) { } -fn func2 = &'static &'static str>(_: &Opt

) { - // Testing that we got String. - assert_eq!(size_of::

(), size_of::()) -} +fn func2 = &'static &'static str>(_: &Opt

) { } diff --git a/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr new file mode 100644 index 0000000000000..ad850dae650ec --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/dont_skip_conflict.rs:26:13 + | +26 | let x = Opt::Non; + | - ^^^^^^^^ cannot infer type for `T` + | | + | consider giving `x` a type + +error: aborting due to previous error + From 423de71b0c8be2211404d12affa1a44849d513d0 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 27 Nov 2017 16:42:37 -0200 Subject: [PATCH 26/35] Fallback: Stop relying on sty equality, use rollbacks. I tried preventing having to rollback inference and being clever with sty equality, but dependent defaults means we need full inference here. All application of defaults goes in the same transaction, again because of dependent defaults. We can't mess with the fulfillment context in a snapshot, so we clone our own fulfillment context. The downside is that if we fail one bag we fail all, which can be very confusing as the user may be presented with several errors when only one of them is the "real one". This is not so bad because we may easily have a heuristic that solves the bags that can be solved in isolation and then puts the complicated cases in a single transaction, making the pathological situation quite rare. --- src/librustc/traits/fulfill.rs | 2 +- .../obligation_forest/mod.rs | 3 +- src/librustc_typeck/check/mod.rs | 96 +++++++------------ .../dependent_associated_type_equal.rs | 44 +++++++++ .../fn_priority_over_ty_def.rs | 1 + .../related_dependent_defaults.rs | 45 +++++++++ .../default_dependent_associated_type.rs | 2 +- .../dependent_defaults.rs | 2 +- .../dont_skip_conflict.rs | 1 + .../dont_skip_conflict.stderr | 4 +- .../fallback_conflict.rs | 4 +- .../fallback_conflict_cross_crate.rs | 3 +- .../fallback_conflict_cross_crate.stderr | 4 +- .../default-ty-param-fallback/feature_gate.rs | 1 + .../feature_gate.stderr | 4 +- .../default-ty-param-fallback/future_proof.rs | 1 + .../future_proof.stderr | 4 +- .../method_call_test.rs | 1 + .../method_call_test.stderr | 4 +- .../related_depent_defaults.rs | 37 +++++++ .../related_depent_defaults.stderr | 10 ++ .../struct_and_type_alias.rs | 2 +- .../default-ty-param-fallback/trait_impl.rs | 1 + .../trait_impl.stderr | 4 +- .../trait_impl_simple.rs | 1 + .../trait_impl_simple.stderr | 4 +- .../default-ty-param-fallback/type_alias.rs | 1 + .../type_alias.stderr | 4 +- 28 files changed, 205 insertions(+), 85 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/dependent_associated_type_equal.rs rename src/test/{ui => run-pass}/default-ty-param-fallback/fn_priority_over_ty_def.rs (95%) create mode 100644 src/test/run-pass/default-ty-param-fallback/related_dependent_defaults.rs create mode 100644 src/test/ui/default-ty-param-fallback/related_depent_defaults.rs create mode 100644 src/test/ui/default-ty-param-fallback/related_depent_defaults.stderr diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 4575a3b55c02f..f5b560294a643 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -42,7 +42,7 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { /// along. Once all type inference constraints have been generated, the /// method `select_all_or_error` can be used to report any remaining /// ambiguous cases as errors. - +#[derive(Clone)] pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index ba4ec477eea26..6376755e21a6a 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -57,6 +57,7 @@ pub trait ObligationProcessor { where I: Clone + Iterator; } +#[derive(Clone)] pub struct ObligationForest { /// The list of obligations. In between calls to /// `process_obligations`, this list only contains nodes in the @@ -81,7 +82,7 @@ pub struct ObligationForest { scratch: Option>, } -#[derive(Debug)] +#[derive(Clone, Debug)] struct Node { obligation: O, state: Cell, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1c6188129c350..4157ee484bbeb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,7 +113,6 @@ use std::rc::Rc; use std::collections::hash_map::Entry; use std::cmp; use std::fmt::Display; -use std::iter::FromIterator; use std::mem::replace; use std::ops::{self, Deref}; use syntax::abi::Abi; @@ -2002,27 +2001,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value) } - fn eager_normalize_in(&self, span: Span, value: &T) -> Option - where T : TypeFoldable<'tcx> - { - let infer_ok = self.inh.partially_normalize_associated_types_in(span, - self.body_id, - self.param_env, - value); - if infer_ok.obligations.is_empty() { - Some(infer_ok.value) - } else { - self.inh.register_predicates(infer_ok.obligations); - self.select_obligations_where_possible(); - let resolved = self.resolve_type_vars_if_possible(&infer_ok.value); - if !resolved.needs_infer() { - Some(resolved) - } else { - None - } - } - } - pub fn require_type_meets(&self, ty: Ty<'tcx>, span: Span, @@ -2233,20 +2211,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { bags.entry(root).or_insert(Vec::new()).push(vid); } } - // Discard key, bags is a sequence of pairs (bag, done). - let mut bags = Vec::from_iter(bags.into_iter().map(|b| b.1).map(|b| (b, false))); - // Attempt to find a fallback for each bag. - loop { - // For dependent defaults, solving a bag - // might allow us to normalize an associated type in another bag. - // For example in `impl::Type>`. - // Therefore we loop over the bags until we are at a fixed point. - let mut fixed_point = true; - // Loop over bags that are not done. - 'bags: for &mut(ref bag, ref mut done) in bags.iter_mut().filter(|bag| !bag.1) { + // We put everything in a single transaction + // because dependent defaults create cross-bag dependencies. + // This is bad in that we may report errors + // for things that actually were successfully inferred. + let _ = self.commit_if_ok(|_| { self.save_and_restore_in_snapshot_flag(|infcx| { + // Clone the whole thing so we can use it for this snapshot. + let mut local_fullfilment = self.fulfillment_cx.borrow().clone(); + // Attempt to find a fallback for each bag. + // - Fail if there are missing defaults. + // - Apply default if all default exist. + 'bags: for bag in bags.into_iter().map(|b| b.1) { // Partition the bag by the origin of the type param. let (fn_or_impl, ty_def) = bag.iter().partition(|&&v| { - match self.infcx.type_variables.borrow().var_origin(v) { + match infcx.type_variables.borrow().var_origin(v) { TypeParameterDefinition(_, _, OriginOfTyParam::Fn) | TypeParameterDefinition(_, _, OriginOfTyParam::Impl) => true, TypeParameterDefinition(_, _, OriginOfTyParam::TyDef) => false, @@ -2259,42 +2237,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if bag.is_empty() { bag = ty_def; } - // - Try again later if a default can't be normalized. - // - Fail if there are conflicting or missing defaults. - // - Succeess if all defaults exist and agree. - let get_default = |&v| self.infcx.type_variables.borrow().default(v).as_user(); + let get_default = |&v| infcx.type_variables.borrow().default(v).as_user(); let mut normalized_defaults = Vec::new(); - for default in bag.iter().map(&get_default) { - if let Some(default) = default { - match self.eager_normalize_in(default.origin_span, &default.ty) { - Some(default) => normalized_defaults.push(default), - None => continue 'bags, // Try again later. + for (&vid, default) in bag.iter().zip(bag.iter().map(&get_default)) { + if let Some(d) = default { + let infr_ok = self.normalize_associated_types_in_as_infer_ok(d.origin_span, + &d.ty); + normalized_defaults.push((vid, infr_ok.value)); + for obligation in infr_ok.obligations { + local_fullfilment.register_predicate_obligation(infcx, obligation); } } else { - // Fail, missing default. - *done = true; - continue 'bags; + continue 'bags; // Fail, missing default. } } - let equivalent_default = normalized_defaults[0]; - // Fail on conflicting defaults. - if normalized_defaults.iter().any(|&d| d.sty != equivalent_default.sty) { - break; - } - // All defaults exist and agree, success, apply the default. - fixed_point = false; - *done = true; - for &vid in &bag { + // All defaults exist, apply them. + for (vid, default) in normalized_defaults { let ty = self.tcx.mk_var(vid); - self.demand_eqtype(syntax_pos::DUMMY_SP, &ty, equivalent_default); + let cause = self.misc(syntax_pos::DUMMY_SP); + if let Ok(infer_ok) = self.at(&cause, self.param_env).sub(default, ty) { + for obligation in infer_ok.obligations { + local_fullfilment.register_predicate_obligation(infcx, obligation); + } + } debug!("apply_user_type_parameter_fallback: applied fallback to var: {:?} \ - with ty: {:?} with default: {:?}", vid, ty, equivalent_default); + with ty: {:?} with default: {:?}", vid, ty, default); } } - if fixed_point { - break; + // Rollback on any conflict. + if local_fullfilment.select_where_possible(self).is_err() { + Err(()) + } else { + Ok(()) } - } + })}); } // Implements type inference fallback algorithm diff --git a/src/test/run-pass/default-ty-param-fallback/dependent_associated_type_equal.rs b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type_equal.rs new file mode 100644 index 0000000000000..0b8e031e259b0 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/dependent_associated_type_equal.rs @@ -0,0 +1,44 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::marker::PhantomData; + +#[derive(Copy, Clone)] +enum Opt { + Som(T), + Non, +} + +trait Id { + type Me; +} + +impl Id for A { + type Me = A; +} + +struct Foo { + data: PhantomData<(X, Y, Z)>, +} + +impl::Me, Z = ::Me> + Foo { + fn new(_: Opt, _: Opt, _: Opt) -> Foo { + Foo { data: PhantomData } + } +} + +fn main() { + let a = Opt::Non; + let _ = Foo::new(a, a, a); +} diff --git a/src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs b/src/test/run-pass/default-ty-param-fallback/fn_priority_over_ty_def.rs similarity index 95% rename from src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs rename to src/test/run-pass/default-ty-param-fallback/fn_priority_over_ty_def.rs index 54d7b454047d0..1096c777c41ec 100644 --- a/src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs +++ b/src/test/run-pass/default-ty-param-fallback/fn_priority_over_ty_def.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/run-pass/default-ty-param-fallback/related_dependent_defaults.rs b/src/test/run-pass/default-ty-param-fallback/related_dependent_defaults.rs new file mode 100644 index 0000000000000..8429b174376b1 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/related_dependent_defaults.rs @@ -0,0 +1,45 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +#[derive(Copy, Clone)] +enum Opt { + Som(T), + Non, +} + +fn main() { + let a = Opt::Non; + let b = Opt::Non; + func1(a, b); + func2(b, a); + + let c = Opt::Non; + let d = Opt::Non; + func1(c, d); + func2(c, d); +} + +fn func1(_: Opt, _: Opt) { +} + +fn func2(_: Opt, _: Opt) { +} diff --git a/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs index 8fc2c2e6bce70..54541ac436175 100644 --- a/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs +++ b/src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/dependent_defaults.rs b/src/test/ui/default-ty-param-fallback/dependent_defaults.rs index ac833d0f54744..40d9767239649 100644 --- a/src/test/ui/default-ty-param-fallback/dependent_defaults.rs +++ b/src/test/ui/default-ty-param-fallback/dependent_defaults.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] use std::marker::PhantomData; diff --git a/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs index ddb2432ac1bb9..4bc3be2bda375 100644 --- a/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs +++ b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr index ad850dae650ec..fd4a1ed786eb9 100644 --- a/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr +++ b/src/test/ui/default-ty-param-fallback/dont_skip_conflict.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/dont_skip_conflict.rs:26:13 + --> $DIR/dont_skip_conflict.rs:27:13 | -26 | let x = Opt::Non; +27 | let x = Opt::Non; | - ^^^^^^^^ cannot infer type for `T` | | | consider giving `x` a type diff --git a/src/test/ui/default-ty-param-fallback/fallback_conflict.rs b/src/test/ui/default-ty-param-fallback/fallback_conflict.rs index b0d12f1d683f8..3a7b2f8026357 100644 --- a/src/test/ui/default-ty-param-fallback/fallback_conflict.rs +++ b/src/test/ui/default-ty-param-fallback/fallback_conflict.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] @@ -18,9 +19,6 @@ fn foo() -> F { F::default() } fn bar(b: B) { println!("{:?}", b); } fn main() { - // Here, F is instantiated with $0=uint let x = foo(); - - // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. bar(x); } diff --git a/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs index 70eb9e6fba905..794357162f6b4 100644 --- a/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs +++ b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -//aux-build:default_ty_param_cross_crate_crate.rs +// aux-build:default_ty_param_cross_crate_crate.rs +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr index effb300eb6c87..21bd5da3d2867 100644 --- a/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr +++ b/src/test/ui/default-ty-param-fallback/fallback_conflict_cross_crate.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/fallback_conflict_cross_crate.rs:22:15 + --> $DIR/fallback_conflict_cross_crate.rs:23:15 | -22 | let foo = bleh(); +23 | let foo = bleh(); | --- ^^^^ cannot infer type for `A` | | | consider giving `foo` a type diff --git a/src/test/ui/default-ty-param-fallback/feature_gate.rs b/src/test/ui/default-ty-param-fallback/feature_gate.rs index 8b3e1674cc6b4..36dea669fd877 100644 --- a/src/test/ui/default-ty-param-fallback/feature_gate.rs +++ b/src/test/ui/default-ty-param-fallback/feature_gate.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human enum Opt { Som(T), diff --git a/src/test/ui/default-ty-param-fallback/feature_gate.stderr b/src/test/ui/default-ty-param-fallback/feature_gate.stderr index 1f7d981993324..af5fbe6d3891e 100644 --- a/src/test/ui/default-ty-param-fallback/feature_gate.stderr +++ b/src/test/ui/default-ty-param-fallback/feature_gate.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/feature_gate.rs:17:5 + --> $DIR/feature_gate.rs:18:5 | -17 | Opt::Non; +18 | Opt::Non; | ^^^^^^^^ cannot infer type for `T` error: aborting due to previous error diff --git a/src/test/ui/default-ty-param-fallback/future_proof.rs b/src/test/ui/default-ty-param-fallback/future_proof.rs index 7a28ffd6089b4..ca36877308694 100644 --- a/src/test/ui/default-ty-param-fallback/future_proof.rs +++ b/src/test/ui/default-ty-param-fallback/future_proof.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/future_proof.stderr b/src/test/ui/default-ty-param-fallback/future_proof.stderr index 68bd854935634..6160c569c6a10 100644 --- a/src/test/ui/default-ty-param-fallback/future_proof.stderr +++ b/src/test/ui/default-ty-param-fallback/future_proof.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/future_proof.rs:24:5 + --> $DIR/future_proof.rs:25:5 | -24 | func(noner()); +25 | func(noner()); | ^^^^ cannot infer type for `P` error: aborting due to previous error diff --git a/src/test/ui/default-ty-param-fallback/method_call_test.rs b/src/test/ui/default-ty-param-fallback/method_call_test.rs index e8d93092ec53d..388997ee24b6f 100644 --- a/src/test/ui/default-ty-param-fallback/method_call_test.rs +++ b/src/test/ui/default-ty-param-fallback/method_call_test.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/method_call_test.stderr b/src/test/ui/default-ty-param-fallback/method_call_test.stderr index 7362c7f6686e2..cbfe7c724d429 100644 --- a/src/test/ui/default-ty-param-fallback/method_call_test.stderr +++ b/src/test/ui/default-ty-param-fallback/method_call_test.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/method_call_test.rs:22:9 + --> $DIR/method_call_test.rs:23:9 | -22 | let f = Foo.method(); +23 | let f = Foo.method(); | ^ | | | cannot infer type for `_` diff --git a/src/test/ui/default-ty-param-fallback/related_depent_defaults.rs b/src/test/ui/default-ty-param-fallback/related_depent_defaults.rs new file mode 100644 index 0000000000000..1aad506d6ec02 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/related_depent_defaults.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +#![feature(default_type_parameter_fallback)] + +#[derive(Copy, Clone)] +enum Opt { + Som(T), + Non, +} + +fn main() { + let a = Opt::Non; + let b = Opt::Non; + func1(a, b); + func2(a, b); + + let c = Opt::Non; + let d = Opt::Non; + func1(c, d); + func2(d, c); +} + +fn func1(_: Opt, _: Opt) { +} + +fn func2(_: Opt, _: Opt) { +} + diff --git a/src/test/ui/default-ty-param-fallback/related_depent_defaults.stderr b/src/test/ui/default-ty-param-fallback/related_depent_defaults.stderr new file mode 100644 index 0000000000000..4915a1d04abf9 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/related_depent_defaults.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/related_depent_defaults.rs:21:13 + | +21 | let a = Opt::Non; + | - ^^^^^^^^ cannot infer type for `T` + | | + | consider giving `a` a type + +error: aborting due to previous error + diff --git a/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs index 6e3e60a02e5e2..65b065c4a4775 100644 --- a/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs +++ b/src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/trait_impl.rs b/src/test/ui/default-ty-param-fallback/trait_impl.rs index c67d3a49aff3d..8f4c5046b672a 100644 --- a/src/test/ui/default-ty-param-fallback/trait_impl.rs +++ b/src/test/ui/default-ty-param-fallback/trait_impl.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/trait_impl.stderr b/src/test/ui/default-ty-param-fallback/trait_impl.stderr index 2c5d0e1955908..23acc0ea9f485 100644 --- a/src/test/ui/default-ty-param-fallback/trait_impl.stderr +++ b/src/test/ui/default-ty-param-fallback/trait_impl.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/trait_impl.rs:23:13 + --> $DIR/trait_impl.rs:24:13 | -23 | let x = Vec::new(); // x: Vec<$0> +24 | let x = Vec::new(); // x: Vec<$0> | - ^^^^^^^^ cannot infer type for `T` | | | consider giving `x` a type diff --git a/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs b/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs index 067ad524922c0..e4e86182f4a8c 100644 --- a/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs +++ b/src/test/ui/default-ty-param-fallback/trait_impl_simple.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr b/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr index 1d4c015da981c..63b6ee29923c8 100644 --- a/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr +++ b/src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/trait_impl_simple.rs:24:13 + --> $DIR/trait_impl_simple.rs:25:13 | -24 | let x = Vec::new(); // x: Vec<$0> +25 | let x = Vec::new(); // x: Vec<$0> | - ^^^^^^^^ cannot infer type for `T` | | | consider giving `x` a type diff --git a/src/test/ui/default-ty-param-fallback/type_alias.rs b/src/test/ui/default-ty-param-fallback/type_alias.rs index 1b4747406d0c6..43f811be5e815 100644 --- a/src/test/ui/default-ty-param-fallback/type_alias.rs +++ b/src/test/ui/default-ty-param-fallback/type_alias.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] diff --git a/src/test/ui/default-ty-param-fallback/type_alias.stderr b/src/test/ui/default-ty-param-fallback/type_alias.stderr index 29cedc4e8dce9..d7927ffc062d8 100644 --- a/src/test/ui/default-ty-param-fallback/type_alias.stderr +++ b/src/test/ui/default-ty-param-fallback/type_alias.stderr @@ -1,7 +1,7 @@ error[E0282]: type annotations needed - --> $DIR/type_alias.rs:18:13 + --> $DIR/type_alias.rs:19:13 | -18 | let x = IntMap::new(); +19 | let x = IntMap::new(); | - ^^^^^^^^^^^ cannot infer type for `K` | | | consider giving `x` a type From 91da0cc519c03371d7a5e773d96d921f4488c500 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 27 Nov 2017 21:57:56 -0200 Subject: [PATCH 27/35] Refactor tests. Make test more focused, and clarify what the bug is. Add new ui test. --- .../trait_impl_param_in_trait.rs | 40 +++++++++++++++++++ .../trait_impl_param_in_trait.rs} | 30 +++++--------- .../trait_impl_param_in_trait.stderr | 11 +++++ 3 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs rename src/test/{run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs => ui/default-ty-param-fallback/trait_impl_param_in_trait.rs} (66%) create mode 100644 src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.stderr diff --git a/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs b/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs new file mode 100644 index 0000000000000..d274996086d34 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +trait B { + fn b(&self) -> T; +} + +impl B for X + where T: Default +{ + fn b(&self) -> T { + T::default() + } +} + +#[derive(Copy, Clone, Default)] +struct X(u8); + +fn main() { + let x = X(0); + let y = x.b(); + foo(y); + // Uncommenting the following line makes the fallback fail. + // Probably we are creating a new inference var, + // that is carrying over the origin but not the value of the default. + // x.0; +} + +fn foo(a: T) -> T { + a +} diff --git a/src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs b/src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.rs similarity index 66% rename from src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs rename to src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.rs index 910c54a59f246..5bf97859fb3c5 100644 --- a/src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs +++ b/src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.rs @@ -7,39 +7,31 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human #![feature(default_type_parameter_fallback)] -trait A { - fn a(t: &T) -> Self; -} - -trait B { +trait B { fn b(&self) -> T; } impl B for X - where T: A + where T: Default { fn b(&self) -> T { - T::a(self) + T::default() } } +#[derive(Copy, Clone, Default)] struct X(u8); -impl A for X { - fn a(x: &X) -> X { - X(x.0) - } -} - -fn g(x: &X) { - // Bug: replacing with `let x = X::b(x)` will cause `x` to be unknown in `x.0`. - let x = ::b(x); - x.0; +fn main() { + let x = X(0); + let y = x.b(); + foo(y); } -fn main() { - g(&X(0)); +fn foo(a: T) -> T { + a } diff --git a/src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.stderr b/src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.stderr new file mode 100644 index 0000000000000..0445b1d30e6cc --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_impl_param_in_trait.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/trait_impl_param_in_trait.rs:31:9 + | +31 | let y = x.b(); + | ^ + | | + | cannot infer type for `_` + | consider giving `y` a type + +error: aborting due to previous error + From da4dcad71b98a4f66e40067ec9db95c6bf8920d6 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 28 Nov 2017 08:57:38 -0200 Subject: [PATCH 28/35] Fallback: Tests to clarify defaults for `Self` in trait impls. --- .../trait_method_call_default_self.rs | 38 +++++++++++++++++++ .../trait_method_call_default_self.rs | 36 ++++++++++++++++++ .../trait_method_call_default_self.stderr | 10 +++++ 3 files changed, 84 insertions(+) create mode 100644 src/test/run-pass/default-ty-param-fallback/trait_method_call_default_self.rs create mode 100644 src/test/ui/default-ty-param-fallback/trait_method_call_default_self.rs create mode 100644 src/test/ui/default-ty-param-fallback/trait_method_call_default_self.stderr diff --git a/src/test/run-pass/default-ty-param-fallback/trait_method_call_default_self.rs b/src/test/run-pass/default-ty-param-fallback/trait_method_call_default_self.rs new file mode 100644 index 0000000000000..19633ee5412cb --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/trait_method_call_default_self.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +use std::fmt::Debug; + +trait B { + fn b(&self) -> Self; +} + +// Strangely, having a default for `Self` +// will fail for fundamental types such as `T` or `Box`. +// Replace `Option` for `Box` in this test to reproduce. +impl B for Option + where T: Default +{ + fn b(&self) -> Option { + Some(T::default()) + } +} + +fn main() { + let x = None; + foo(x.b()); +} + +fn foo(a: Option) + where T: Debug + PartialEq<&'static str> { + assert_eq!(a.unwrap(), ""); +} diff --git a/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.rs b/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.rs new file mode 100644 index 0000000000000..c5c59bc2bd02b --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.rs @@ -0,0 +1,36 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +#![feature(default_type_parameter_fallback)] + +use std::fmt::Debug; + +trait B { + fn b(&self) -> Self; +} + +impl B for Option + where T: Default +{ + fn b(&self) -> Option { + Some(T::default()) + } +} + +fn main() { + let x = None; + foo(x.b()); +} + +fn foo(a: Option) + where T: Debug + PartialEq<&'static str> { + assert_eq!(a.unwrap(), ""); +} diff --git a/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.stderr b/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.stderr new file mode 100644 index 0000000000000..2a43b061d7d33 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/trait_method_call_default_self.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/trait_method_call_default_self.rs:29:13 + | +29 | let x = None; + | - ^^^^ cannot infer type for `T` + | | + | consider giving `x` a type + +error: aborting due to previous error + From 90a42a8340bb37b2caeeaafb344a79f83456a4f0 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 28 Nov 2017 10:52:01 -0200 Subject: [PATCH 29/35] Test interaction with specialization. --- .../specialization_concrete.rs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/run-pass/default-ty-param-fallback/specialization_concrete.rs diff --git a/src/test/run-pass/default-ty-param-fallback/specialization_concrete.rs b/src/test/run-pass/default-ty-param-fallback/specialization_concrete.rs new file mode 100644 index 0000000000000..30a4eca18a776 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/specialization_concrete.rs @@ -0,0 +1,45 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] +#![feature(specialization)] + +use std::fmt::Debug; + +trait B { + fn b(&self) -> Self; +} + +default impl B for Option + where T: Default +{ + fn b(&self) -> Option { + Some(T::default()) + } +} + +impl B for Option +{ + fn b(&self) -> Option { + Some("special".into()) + } +} + +fn main() { + let x = None; + // Even with defaults, the concrete impl is prefered, + // the defaults are simply ignored. + foo(x.b()); +} + +fn foo(a: Option) + where T: Debug { + assert_eq!(format!("{:?}", a.unwrap()), "\"special\""); +} From d84f3edff5836cc5bcb2a991052248d82807815a Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 29 Nov 2017 10:33:56 -0200 Subject: [PATCH 30/35] Test that trait definition owns the default, not the impl. I don't know if it's what we want but it's how it works now. If we want to keep it then we should forbid writing the default in the impl. --- .../trait_def_rules_over_impl.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/run-pass/default-ty-param-fallback/trait_def_rules_over_impl.rs diff --git a/src/test/run-pass/default-ty-param-fallback/trait_def_rules_over_impl.rs b/src/test/run-pass/default-ty-param-fallback/trait_def_rules_over_impl.rs new file mode 100644 index 0000000000000..4bcf7a1176848 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/trait_def_rules_over_impl.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +trait Bar { + // Current we consider only the default in the trait, + // never the one in the impl. + // Is this good? Is it bad? Is it just the way it works? + // If this is ok then we should forbid writing the default in the impl. + fn method(&self) -> A; +} + +struct Foo; + +impl Bar for Foo { + fn method(&self) -> A { + A::default() + } +} + +fn main() { + Foo.method(); +} From 4753319f9068877fdcc7fd66193ccd0dd5859f1c Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 29 Nov 2017 17:27:04 -0200 Subject: [PATCH 31/35] Test associated type as default, test that elided params are not inferred --- .../associated_type_as_default.rs | 64 +++++++++++++++++++ .../elided_is_not_inferred.rs | 30 +++++++++ .../elided_is_not_inferred.stderr | 26 ++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs create mode 100644 src/test/ui/default-ty-param-fallback/elided_is_not_inferred.rs create mode 100644 src/test/ui/default-ty-param-fallback/elided_is_not_inferred.stderr diff --git a/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs new file mode 100644 index 0000000000000..e3930d16a5ef1 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs @@ -0,0 +1,64 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// + +#![feature(default_type_parameter_fallback)] + +use std::vec::IntoIter; +use std::iter::Sum; +use std::slice::Iter; +use std::ops::Add; + +trait Itarator: Iterator { + type Iten; + // Bug: Even though it's unambiguos, using Self::Iten dosen't work here. + // probably can be fixed in fn associated_path_def_to_ty. + fn foo::Iten>(&self) -> T { + T::default() + } + + fn suma::Iten as Add>::Output>(self) -> S + where Self: Sized, + S: Sum<::Item>, + { + Sum::sum(self) + } +} + +impl Itarator for IntoIter { + type Iten = as Iterator>::Item; +} + +impl<'a> Itarator for Iter<'a, u32> { + type Iten = as Iterator>::Item; +} + +fn main() { + let x = vec![0u32]; + { + let v = x.iter(); + // Bug: if we put a cast such as `as u64`, inference fails. + //The usual guess is that we propagate the origin but not the default of the inference var. + v.suma(); + } + x.clone().into_iter().suma(); + x.into_iter().suma(); +} diff --git a/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.rs b/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.rs new file mode 100644 index 0000000000000..7efcf64e9f807 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +#![feature(default_type_parameter_fallback)] + +struct Bar(T); + +impl Bar { + fn new() -> Bar { + Bar(Z::default()) + } +} + +fn main() { + let _:u32 = foo::(); + let _:Bar = Bar::new::(); +} + +fn foo() -> T { + T::default() +} + diff --git a/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.stderr b/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.stderr new file mode 100644 index 0000000000000..1bb7b710ddc7f --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/elided_is_not_inferred.stderr @@ -0,0 +1,26 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/elided_is_not_inferred.rs:16:10 + | +16 | impl Bar { + | ^ not found in this scope + +error[E0308]: mismatched types + --> $DIR/elided_is_not_inferred.rs:23:17 + | +23 | let _:u32 = foo::(); + | ^^^^^^^^^^^^^^ expected u32, found struct `std::string::String` + | + = note: expected type `u32` + found type `std::string::String` + +error[E0308]: mismatched types + --> $DIR/elided_is_not_inferred.rs:24:22 + | +24 | let _:Bar = Bar::new::(); + | ^^^^^^^^^^^^^^^^^^^ expected u32, found struct `std::string::String` + | + = note: expected type `Bar` + found type `Bar` + +error: aborting due to 3 previous errors + From bad548a5fa7260ca5200922a013cc06793f1c353 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 29 Nov 2017 21:47:15 -0200 Subject: [PATCH 32/35] Fix "associated type not found" when using associated type in default. Makes associated types in defaults less verbose. --- src/librustc_typeck/astconv.rs | 34 +++++++++++++++++-- .../associated_type_as_default.rs | 11 +++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 8b849a9e52f3a..ab3b7a829b899 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -706,6 +706,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span) } + fn count_bounds_for_assoc_item(&self, + ty_param_def_id: DefId, + assoc_name: ast::Name, + span: Span) + -> usize + { + let tcx = self.tcx(); + let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id) + .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect(); + traits::transitive_bounds(tcx, &bounds) + .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name)).count() + } // Checks that bounds contains exactly one element and reports appropriate // errors otherwise. @@ -777,6 +789,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { item_segment: &hir::PathSegment) -> (Ty<'tcx>, Def) { + use rustc::ty::ToPolyTraitRef; + let tcx = self.tcx(); let assoc_name = item_segment.name; @@ -808,9 +822,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Err(ErrorReported) => return (tcx.types.err, Def::Err), } } - (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) | - (&ty::TyParam(_), Def::TyParam(param_did)) => { - match self.find_bound_for_assoc_item(param_did, assoc_name, span) { + (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) + if self.count_bounds_for_assoc_item(trait_did, assoc_name, span) == 0 => { + // No bounds for `Self` in trait definition. + let substs = Substs::identity_for_item(tcx, trait_did); + let trait_ref = ty::TraitRef::new(trait_did, substs).to_poly_trait_ref(); + let candidates = + traits::supertraits(tcx, trait_ref) + .filter(|r| self.trait_defines_associated_type_named(r.def_id(), + assoc_name)); + match self.one_bound_for_assoc_type(candidates, "Self", assoc_name, span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, Def::Err), + } + } + (&ty::TyParam(_), Def::SelfTy(Some(did), None)) | + (&ty::TyParam(_), Def::TyParam(did)) => { + match self.find_bound_for_assoc_item(did, assoc_name, span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, Def::Err), } diff --git a/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs index e3930d16a5ef1..4e6414ea83940 100644 --- a/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs +++ b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs @@ -29,15 +29,14 @@ use std::ops::Add; trait Itarator: Iterator { type Iten; - // Bug: Even though it's unambiguos, using Self::Iten dosen't work here. - // probably can be fixed in fn associated_path_def_to_ty. - fn foo::Iten>(&self) -> T { + + fn foo(&self) -> T { T::default() } - fn suma::Iten as Add>::Output>(self) -> S + fn suma::Output>(self) -> S where Self: Sized, - S: Sum<::Item>, + S: Sum, { Sum::sum(self) } @@ -56,7 +55,7 @@ fn main() { { let v = x.iter(); // Bug: if we put a cast such as `as u64`, inference fails. - //The usual guess is that we propagate the origin but not the default of the inference var. + // The guess is that we propagate the origin but not the default of the inference var. v.suma(); } x.clone().into_iter().suma(); From 5c2822492d0c1749e2a476258441e31a963a0f7d Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 30 Nov 2017 07:39:54 -0200 Subject: [PATCH 33/35] Propagate defaults in fudge If you propagate the origin, you propagate the default. Fixes fallback for field access. Also small refactoring in combine. --- src/librustc/infer/combine.rs | 8 +------- src/librustc/infer/fudge.rs | 6 +++--- src/librustc/infer/type_variable.rs | 10 ++++++---- .../trait_impl_param_in_trait.rs | 5 +---- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 9f618b41ede1b..d0d446530f199 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -46,7 +46,6 @@ use ty::error::TypeError; use ty::relate::{self, Relate, RelateResult, TypeRelation}; use ty::subst::Substs; use traits::{Obligation, PredicateObligations}; -use infer::type_variable::Default; use syntax::ast; use syntax_pos::Span; @@ -425,12 +424,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } let origin = variables.origin(vid); - let orig_default = variables.default(vid).clone(); - let default = if let Default::User(user_default) = orig_default { - Some(user_default) - } else { - None - }; + let default = variables.default(vid).as_user().clone(); let new_var_id = variables.new_var(false, origin, default); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 756a6947ee3f8..b81e6db60069a 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -111,7 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - type_variables: &'a TypeVariableMap, + type_variables: &'a TypeVariableMap<'tcx>, region_vars: &'a Vec, origin: &'a RegionVariableOrigin, } @@ -135,11 +135,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { ty } - Some(&origin) => { + Some(&(origin, ref default)) => { // This variable was created during the // fudging. Recreate it with a fresh variable // here. - self.infcx.next_ty_var(origin) + self.infcx.next_ty_var_with_default(default.clone(), origin) } } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 4dd0bf98e8b32..257f509eec845 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -70,7 +70,8 @@ pub enum TypeVariableOrigin { Generalized(ty::TyVid), } -pub type TypeVariableMap = FxHashMap; +pub type TypeVariableMap<'tcx> = FxHashMap>)>; struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, @@ -196,7 +197,7 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: bool, origin: TypeVariableOrigin, default: Option>,) -> ty::TyVid { - debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); + debug!("new_var(diverging={:?}, origin={:?} default={:?})", diverging, origin, default); self.eq_relations.new_key(()); self.sub_relations.new_key(()); @@ -314,7 +315,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// ty-variables created during the snapshot, and the values /// `{V2}` are the root variables that they were unified with, /// along with their origin. - pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { + pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap<'tcx> { let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); actions_since_snapshot @@ -325,7 +326,8 @@ impl<'tcx> TypeVariableTable<'tcx> { }) .map(|vid| { let origin = self.values.get(vid.index as usize).origin.clone(); - (vid, origin) + let default = self.default(vid).clone().as_user(); + (vid, (origin, default)) }) .collect() } diff --git a/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs b/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs index d274996086d34..8c97370caa303 100644 --- a/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs +++ b/src/test/run-pass/default-ty-param-fallback/trait_impl_param_in_trait.rs @@ -29,10 +29,7 @@ fn main() { let x = X(0); let y = x.b(); foo(y); - // Uncommenting the following line makes the fallback fail. - // Probably we are creating a new inference var, - // that is carrying over the origin but not the value of the default. - // x.0; + x.0; } fn foo(a: T) -> T { From 973f782f0899335aa40230a5e9abaaa0bf1a2b81 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 30 Nov 2017 08:43:10 -0200 Subject: [PATCH 34/35] Use fallbacks to avoid "the type of this value must be known in this context" Try fallback right in `structurally_resolve_type_or_else` right before we hit "the type of this value must be known in this context". This gets casts working, and probably other things not tested for. Also remove some dead code. --- src/librustc/infer/mod.rs | 19 ------------------- src/librustc_typeck/check/mod.rs | 8 ++++++++ .../associated_type_as_default.rs | 4 +--- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a8f6f378c2eb8..7e6f61e6d5dfd 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -695,25 +695,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - /// Returns a type variable's default fallback if any exists. A default - /// must be attached to the variable when created, if it is created - /// without a default, this will return NoDefault. - /// - /// This code does not apply to integral or floating point variables, - /// only to use declared defaults. - /// - /// See `new_ty_var_with_default` to create a type variable with a default. - /// See `type_variable::Default` for details about what a default entails. - pub fn default(&self, ty: Ty<'tcx>) -> type_variable::Default<'tcx> { - match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables - .borrow() - .default(vid) - .clone(), - _ => type_variable::Default::None, - } - } - // Returns a vector containing all type variables that have an applicable default, // along with their defaults. // diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4157ee484bbeb..07f49bfaa427d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5088,6 +5088,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If not, error. if alternative.is_ty_var() || alternative.references_error() { if !self.is_tainted_by_errors() { + // Try user fallbacks as a last attempt. + if self.tcx.sess.features.borrow().default_type_parameter_fallback { + self.apply_user_type_parameter_fallback(); + let ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_var() { + return ty; + } + } type_error_struct!(self.tcx.sess, sp, ty, E0619, "the type of this value must be known in this context") .emit(); diff --git a/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs index 4e6414ea83940..5a1d33a0fd48c 100644 --- a/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs +++ b/src/test/run-pass/default-ty-param-fallback/associated_type_as_default.rs @@ -54,9 +54,7 @@ fn main() { let x = vec![0u32]; { let v = x.iter(); - // Bug: if we put a cast such as `as u64`, inference fails. - // The guess is that we propagate the origin but not the default of the inference var. - v.suma(); + v.suma() as u64; } x.clone().into_iter().suma(); x.into_iter().suma(); From 06e74564fe283562db2c481321ee3931840c20ec Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 30 Nov 2017 14:36:15 -0200 Subject: [PATCH 35/35] Fix fallback for `_` placeholders. It seems we have pretty much the same logic in three different places, so it was fixed in three different places. Took the opportunity to leave FIXMEs regarding elision of defaulted params. --- src/librustc_typeck/astconv.rs | 24 +++++++++++++------ src/librustc_typeck/check/method/confirm.rs | 10 +++++++- src/librustc_typeck/check/mod.rs | 10 +++++++- .../default-ty-param-fallback/method_call.rs | 5 +--- .../placeholder_type_hint.rs | 22 +++++++++++++++++ .../default-ty-param-fallback/struct.rs | 1 + .../placeholder_type_hint.rs | 23 ++++++++++++++++++ .../placeholder_type_hint.stderr | 10 ++++++++ 8 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 src/test/run-pass/default-ty-param-fallback/placeholder_type_hint.rs create mode 100644 src/test/ui/default-ty-param-fallback/placeholder_type_hint.rs create mode 100644 src/test/ui/default-ty-param-fallback/placeholder_type_hint.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ab3b7a829b899..98e0bc60675e5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -244,20 +244,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return ty; } + let inferred_param = || if !default_needs_object_self(def) { + self.ty_infer_for_def(def, substs, span) + } else { + self.ty_infer(span) + }; + let i = i - self_ty.is_some() as usize - decl_generics.regions.len(); if i < num_types_provided { // A provided type parameter. - self.ast_ty_to_ty(¶meters.types[i]) + let provided = ¶meters.types[i]; + if provided.node != hir::Ty_::TyInfer { + self.ast_ty_to_ty(provided) + } else { + let inferred = inferred_param(); + self.record_ty(provided.hir_id, inferred, provided.span); + inferred + } } else if infer_types { // 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 + inferred_param() } else if def.has_default { // No type parameter provided, but a default exists. + // FIXME(leodasvacas): + // For fns and impls, feature gate under `default_type_parameter_fallback`. // If we are converting an object type, then the // `Self` parameter is unknown. However, some of the diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 17ed0aaa30b02..81d63511afcad 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -304,6 +304,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. + // FIXME(leodasvacas): + // Support substituting elided for defaults under gate `default_type_parameter_fallback`. assert_eq!(method_generics.parent_count(), parent_substs.len()); let provided = &segment.parameters; Substs::for_item(self.tcx, pick.item.def_id, |def, _| { @@ -325,7 +327,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { p.types.get(i - parent_substs.len() - method_generics.regions.len()) }) { - self.to_ty(ast_ty) + if ast_ty.node != hir::Ty_::TyInfer { + self.to_ty(ast_ty) + } else { + let inferred = self.type_var_for_def(self.span, def, cur_substs); + self.record_ty(ast_ty.hir_id, inferred, ast_ty.span); + inferred + } } else { self.type_var_for_def(self.span, def, cur_substs) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 07f49bfaa427d..3941c82e63f5a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4878,9 +4878,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(ast_ty) = types.get(i) { // A provided type parameter. - self.to_ty(ast_ty) + if ast_ty.node != hir::Ty_::TyInfer { + self.to_ty(ast_ty) + } else { + let inferred = self.type_var_for_def(span, def, substs); + self.record_ty(ast_ty.hir_id, inferred, ast_ty.span); + inferred + } } else if !infer_types && def.has_default { // No type parameter provided, but a default exists. + // FIXME(leodasvacas): + // For fns and impls, feature gate under `default_type_parameter_fallback`. let default = self.tcx.type_of(def.def_id); self.normalize_ty( span, diff --git a/src/test/run-pass/default-ty-param-fallback/method_call.rs b/src/test/run-pass/default-ty-param-fallback/method_call.rs index ee638c6f3ccd2..ecfd52475b2ca 100644 --- a/src/test/run-pass/default-ty-param-fallback/method_call.rs +++ b/src/test/run-pass/default-ty-param-fallback/method_call.rs @@ -19,9 +19,6 @@ impl Foo { } fn main() { - // Bug: Replacing with Foo.method::<_>() fails. - // Suspicion: astconv and tycheck are considering this a "A provided type parameter.", - // resulting in type_var_for_def not being called and a TypeInference var being created - // rather than a TypeParameterDefinition var. let _ = Foo.method(); + Foo.method::<_>(); } diff --git a/src/test/run-pass/default-ty-param-fallback/placeholder_type_hint.rs b/src/test/run-pass/default-ty-param-fallback/placeholder_type_hint.rs new file mode 100644 index 0000000000000..5c8637f2f3e1d --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/placeholder_type_hint.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +enum Opt { + Som(T), + Non, +} + +struct Foo(Opt); + +fn main() { + let _: Foo<_> = Foo(Opt::Non); +} diff --git a/src/test/run-pass/default-ty-param-fallback/struct.rs b/src/test/run-pass/default-ty-param-fallback/struct.rs index 9cdfc31831b20..a54e5eb759adb 100644 --- a/src/test/run-pass/default-ty-param-fallback/struct.rs +++ b/src/test/run-pass/default-ty-param-fallback/struct.rs @@ -20,4 +20,5 @@ impl Foo { fn main() { let _ = Foo::new(); + Foo::<_>::new(); } diff --git a/src/test/ui/default-ty-param-fallback/placeholder_type_hint.rs b/src/test/ui/default-ty-param-fallback/placeholder_type_hint.rs new file mode 100644 index 0000000000000..62e461291c6f1 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/placeholder_type_hint.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// compile-flags: --error-format=human + +#![feature(default_type_parameter_fallback)] + +enum Opt { + Som(T), + Non, +} + +struct Foo(Opt); + +fn main() { + let _: Foo<_> = Foo(Opt::Non); +} diff --git a/src/test/ui/default-ty-param-fallback/placeholder_type_hint.stderr b/src/test/ui/default-ty-param-fallback/placeholder_type_hint.stderr new file mode 100644 index 0000000000000..c58f2fb42ff07 --- /dev/null +++ b/src/test/ui/default-ty-param-fallback/placeholder_type_hint.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/placeholder_type_hint.rs:22:21 + | +22 | let _: Foo<_> = Foo(Opt::Non); + | - ^^^ cannot infer type for `A` + | | + | consider giving the pattern a type + +error: aborting due to previous error +

) { } diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs b/src/test/run-pass/default-ty-param-fallback/fallback_in_impls.rs similarity index 100% rename from src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_struct.rs rename to src/test/run-pass/default-ty-param-fallback/fallback_in_impls.rs diff --git a/src/test/run-pass/default_ty_param_fallback_method_call_test.rs b/src/test/run-pass/default-ty-param-fallback/method_call.rs similarity index 66% rename from src/test/run-pass/default_ty_param_fallback_method_call_test.rs rename to src/test/run-pass/default-ty-param-fallback/method_call.rs index e8d93092ec53d..ee638c6f3ccd2 100644 --- a/src/test/run-pass/default_ty_param_fallback_method_call_test.rs +++ b/src/test/run-pass/default-ty-param-fallback/method_call.rs @@ -19,6 +19,9 @@ impl Foo { } fn main() { - let f = Foo.method(); - println!("{}", f); + // Bug: Replacing with Foo.method::<_>() fails. + // Suspicion: astconv and tycheck are considering this a "A provided type parameter.", + // resulting in type_var_for_def not being called and a TypeInference var being created + // rather than a TypeParameterDefinition var. + let _ = Foo.method(); } diff --git a/src/test/run-pass/default_ty_param_fallback_struct.rs b/src/test/run-pass/default-ty-param-fallback/struct.rs similarity index 96% rename from src/test/run-pass/default_ty_param_fallback_struct.rs rename to src/test/run-pass/default-ty-param-fallback/struct.rs index d9ac51fc23b02..9cdfc31831b20 100644 --- a/src/test/run-pass/default_ty_param_fallback_struct.rs +++ b/src/test/run-pass/default-ty-param-fallback/struct.rs @@ -19,5 +19,5 @@ impl Foo { } fn main() { - let foo = Foo::new(); + let _ = Foo::new(); } diff --git a/src/test/run-pass/default_ty_param_fallback_trait_impl.rs b/src/test/run-pass/default-ty-param-fallback/trait_impl.rs similarity index 52% rename from src/test/run-pass/default_ty_param_fallback_trait_impl.rs rename to src/test/run-pass/default-ty-param-fallback/trait_impl.rs index c67d3a49aff3d..d79863cc5fbb1 100644 --- a/src/test/run-pass/default_ty_param_fallback_trait_impl.rs +++ b/src/test/run-pass/default-ty-param-fallback/trait_impl.rs @@ -10,16 +10,30 @@ #![feature(default_type_parameter_fallback)] -// Another example from the RFC +struct Vac(Vec); + +impl Vac { + fn new() -> Self { + Vac(Vec::new()) + } +} + trait Foo { } trait Bar { } -impl Foo for Vec {} +impl Foo for Vac {} impl Bar for usize {} -fn takes_foo(f: F) {} +fn takes_foo(_: F) {} fn main() { - let x = Vec::new(); // x: Vec<$0> - takes_foo(x); // adds oblig Vec<$0> : Foo + let x = Vac::new(); // x: Vac<$0> + // adds oblig Vac<$0> : Foo, + // and applies the default of `impl Vac` and + // `impl Foo for Vac`, which must agree. + // + // The default of F in takes_foo makes no difference here, + // because the corresponding inference var will be generalized + // to Vac<_>. + takes_foo(x); } diff --git a/src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs b/src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs new file mode 100644 index 0000000000000..910c54a59f246 --- /dev/null +++ b/src/test/run-pass/default-ty-param-fallback/trait_impl_with_param_in_trait.rs @@ -0,0 +1,45 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(default_type_parameter_fallback)] + +trait A { + fn a(t: &T) -> Self; +} + +trait B { + fn b(&self) -> T; +} + +impl B for X + where T: A +{ + fn b(&self) -> T { + T::a(self) + } +} + +struct X(u8); + +impl A for X { + fn a(x: &X) -> X { + X(x.0) + } +} + +fn g(x: &X) { + // Bug: replacing with `let x = X::b(x)` will cause `x` to be unknown in `x.0`. + let x = ::b(x); + x.0; +} + +fn main() { + g(&X(0)); +} diff --git a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs b/src/test/run-pass/default-ty-param-fallback/type_alias.rs similarity index 67% rename from src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs rename to src/test/run-pass/default-ty-param-fallback/type_alias.rs index e8d93092ec53d..78c0062c24451 100644 --- a/src/test/run-pass/default-ty-param-fallback/default_ty_param_fallback_method_call_test.rs +++ b/src/test/run-pass/default-ty-param-fallback/type_alias.rs @@ -10,15 +10,16 @@ #![feature(default_type_parameter_fallback)] -struct Foo; +struct HeshMep(Vec, Vec, S); -impl Foo { - fn method(&self) -> A { - A::default() +impl HeshMep { + fn new() -> HeshMep { + HeshMep(Vec::new(), Vec::new(), S::default()) } } +type IntMap = HeshMep; + fn main() { - let f = Foo.method(); - println!("{}", f); + let _ = IntMap::new(); } diff --git a/src/test/run-pass/default_ty_param_fallback_default_over_literal.rs b/src/test/run-pass/default_ty_param_fallback_default_over_literal.rs deleted file mode 100755 index bc5478240a272..0000000000000 --- a/src/test/run-pass/default_ty_param_fallback_default_over_literal.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -fn foo(t: T) -> usize { std::mem::size_of_val(&t) } - -fn main() { assert_eq!(foo(22), std::mem::size_of::()) } diff --git a/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs b/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs deleted file mode 100644 index bc9e309563ef6..0000000000000 --- a/src/test/run-pass/default_ty_param_fallback_ensure_normalization.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] -#![feature(iter_arith)] - -fn main() { - print!("{}", (1..4).sum()); -} diff --git a/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs deleted file mode 100644 index 6e3e60a02e5e2..0000000000000 --- a/src/test/run-pass/default_ty_param_fallback_struct_and_type_alias.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// - -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -struct DeterministicHasher; -struct RandomHasher; - - -struct MyHashMap { - data: PhantomData<(K, V, H)> -} - -impl MyHashMap { - fn new() -> MyHashMap { - MyHashMap { data: PhantomData } - } -} - -mod mystd { - use super::{MyHashMap, RandomHasher}; - pub type HashMap = MyHashMap; -} - -fn try_me(hash_map: mystd::HashMap) {} - -fn main() { - let hash_map = mystd::HashMap::new(); - try_me(hash_map); -} diff --git a/src/test/run-pass/default_ty_param_fallback_type_alias.rs b/src/test/run-pass/default_ty_param_fallback_type_alias.rs deleted file mode 100644 index 1b4747406d0c6..0000000000000 --- a/src/test/run-pass/default_ty_param_fallback_type_alias.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(default_type_parameter_fallback)] - -use std::collections::HashMap; - -type IntMap = HashMap; - -fn main() { - let x = IntMap::new(); -} From 5362bbe00a4b1b03f99dd65c57c70ff0d8b7b8b0 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 23 Nov 2017 10:38:39 -0200 Subject: [PATCH 22/35] Tests for default fallback: ui tests, run fail test, more run pass tests. The tests under bad_messages in ui are the ones that have bad messages that need fixing. --- src/test/run-fail/default_over_literal.rs | 17 ++++++++ .../default-ty-param-fallback/enum.rs | 11 ++++- .../heterogeneous_partial_eq_for_option.rs | 22 ++++++++++ .../default-ty-param-fallback/trait_impl.rs | 2 +- .../default_ty_param_cross_crate_crate.rs | 0 .../bad_messages/fallback_conflict.rs} | 6 --- .../bad_messages/fallback_conflict.stderr | 8 ++++ .../fallback_conflict_cross_crate.rs} | 4 -- .../fallback_conflict_cross_crate.stderr | 8 ++++ .../default_dependent_associated_type.rs | 36 +++++++++++++++++ .../default_dependent_associated_type.stderr | 10 +++++ .../dependent_defaults.rs | 19 +++++++++ .../dependent_defaults.stderr | 10 +++++ .../default-ty-param-fallback/feature_gate.rs | 18 +++++++++ .../feature_gate.stderr | 8 ++++ .../fn_priority_over_ty_def.rs | 31 ++++++++++++++ .../default-ty-param-fallback/future_proof.rs | 27 +++++++++++++ .../future_proof.stderr | 8 ++++ .../method_call_test.rs | 24 +++++++++++ .../method_call_test.stderr | 11 +++++ .../struct_and_type_alias.rs | 40 +++++++++++++++++++ .../struct_and_type_alias.stderr | 10 +++++ .../default-ty-param-fallback/trait_impl.rs | 25 ++++++++++++ .../trait_impl.stderr | 10 +++++ .../trait_impl_simple.rs | 26 ++++++++++++ .../trait_impl_simple.stderr | 10 +++++ .../default-ty-param-fallback/type_alias.rs | 19 +++++++++ .../type_alias.stderr | 10 +++++ 28 files changed, 417 insertions(+), 13 deletions(-) create mode 100644 src/test/run-fail/default_over_literal.rs create mode 100644 src/test/run-pass/default-ty-param-fallback/heterogeneous_partial_eq_for_option.rs rename src/test/{compile-fail => ui/default-ty-param-fallback/bad_messages}/auxiliary/default_ty_param_cross_crate_crate.rs (100%) rename src/test/{compile-fail/default_ty_param_fallback_conflict.rs => ui/default-ty-param-fallback/bad_messages/fallback_conflict.rs} (71%) create mode 100644 src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict.stderr rename src/test/{compile-fail/default_ty_param_fallback_conflict_cross_crate.rs => ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.rs} (77%) create mode 100644 src/test/ui/default-ty-param-fallback/bad_messages/fallback_conflict_cross_crate.stderr create mode 100644 src/test/ui/default-ty-param-fallback/default_dependent_associated_type.rs create mode 100644 src/test/ui/default-ty-param-fallback/default_dependent_associated_type.stderr create mode 100644 src/test/ui/default-ty-param-fallback/dependent_defaults.rs create mode 100644 src/test/ui/default-ty-param-fallback/dependent_defaults.stderr create mode 100644 src/test/ui/default-ty-param-fallback/feature_gate.rs create mode 100644 src/test/ui/default-ty-param-fallback/feature_gate.stderr create mode 100644 src/test/ui/default-ty-param-fallback/fn_priority_over_ty_def.rs create mode 100644 src/test/ui/default-ty-param-fallback/future_proof.rs create mode 100644 src/test/ui/default-ty-param-fallback/future_proof.stderr create mode 100644 src/test/ui/default-ty-param-fallback/method_call_test.rs create mode 100644 src/test/ui/default-ty-param-fallback/method_call_test.stderr create mode 100644 src/test/ui/default-ty-param-fallback/struct_and_type_alias.rs create mode 100644 src/test/ui/default-ty-param-fallback/struct_and_type_alias.stderr create mode 100644 src/test/ui/default-ty-param-fallback/trait_impl.rs create mode 100644 src/test/ui/default-ty-param-fallback/trait_impl.stderr create mode 100644 src/test/ui/default-ty-param-fallback/trait_impl_simple.rs create mode 100644 src/test/ui/default-ty-param-fallback/trait_impl_simple.stderr create mode 100644 src/test/ui/default-ty-param-fallback/type_alias.rs create mode 100644 src/test/ui/default-ty-param-fallback/type_alias.stderr diff --git a/src/test/run-fail/default_over_literal.rs b/src/test/run-fail/default_over_literal.rs new file mode 100644 index 0000000000000..b3d5c2eb7f906 --- /dev/null +++ b/src/test/run-fail/default_over_literal.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:assertion failed: `(left == right)` + +#![feature(default_type_parameter_fallback)] + +fn foo(t: T) -> usize { std::mem::size_of_val(&t) } + +fn main() { assert_eq!(foo(22), std::mem::size_of::()) } diff --git a/src/test/run-pass/default-ty-param-fallback/enum.rs b/src/test/run-pass/default-ty-param-fallback/enum.rs index 54d7b454047d0..98cf71bde339b 100644 --- a/src/test/run-pass/default-ty-param-fallback/enum.rs +++ b/src/test/run-pass/default-ty-param-fallback/enum.rs @@ -11,6 +11,7 @@ #![feature(default_type_parameter_fallback)] use std::path::Path; +use std::mem::size_of; enum Opt { Som(T), @@ -27,5 +28,11 @@ fn main() { } // Defaults on fns take precedence. -fn func1 = String>(p: Option