From bbcb13da88f7a4b25506ec85f2f170e6f78d5a58 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 7 Jul 2015 15:50:02 -0700 Subject: [PATCH 01/18] Implement Default TyParam fallback This patch allows type parameter defaults to influence type inference. This is a possible breaking change since it effects the way type inference works and will have different behavior when mixing defaults and literal fallback. --- src/librustc/middle/infer/mod.rs | 78 ++++++++++- src/librustc/middle/infer/type_variable.rs | 9 ++ src/librustc/middle/ty.rs | 11 ++ src/librustc_data_structures/unify/mod.rs | 8 +- src/librustc_typeck/check/method/confirm.rs | 10 +- src/librustc_typeck/check/method/mod.rs | 5 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 128 ++++++++++++++---- .../compile-fail/default_ty_param_conflict.rs | 23 ++++ .../default_ty_param_type_alias.rs | 17 +++ .../default_ty_param_method_call_test.rs | 22 +++ src/test/run-pass/default_ty_param_struct.rs | 21 +++ .../run-pass/default_ty_param_trait_impl.rs | 23 ++++ .../default_ty_param_trait_impl_simple.rs | 26 ++++ 14 files changed, 340 insertions(+), 45 deletions(-) create mode 100644 src/test/compile-fail/default_ty_param_conflict.rs create mode 100644 src/test/compile-fail/default_ty_param_type_alias.rs create mode 100644 src/test/run-pass/default_ty_param_method_call_test.rs create mode 100644 src/test/run-pass/default_ty_param_struct.rs create mode 100644 src/test/run-pass/default_ty_param_trait_impl.rs create mode 100644 src/test/run-pass/default_ty_param_trait_impl_simple.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index c6df1c395cce..5339464503b3 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -95,6 +95,9 @@ pub struct InferCtxt<'a, 'tcx: 'a> { normalize: bool, err_count_on_creation: usize, + + // Default Type Parameter fallbacks + pub defaults: RefCell, Ty<'tcx>>>, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -350,7 +353,8 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)), normalize: false, - err_count_on_creation: tcx.sess.err_count() + err_count_on_creation: tcx.sess.err_count(), + defaults: RefCell::new(FnvHashMap()), } } @@ -653,6 +657,30 @@ pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { } } + pub fn unsolved_variables(&self) -> Vec> { + let mut variables = Vec::new(); + + let unbound_ty_vars = self.type_variables + .borrow() + .unsolved_variables() + .into_iter().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)); + + let unbound_float_vars = self.float_unification_table + .borrow_mut() + .unsolved_variables() + .into_iter().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, a_is_expected: bool, trace: TypeTrace<'tcx>) -> CombineFields<'a, 'tcx> { CombineFields {infcx: self, @@ -996,6 +1024,23 @@ pub fn region_vars_for_defs(&self, .collect() } + pub fn type_vars_for_defs(&self, + defs: &[ty::TypeParameterDef<'tcx>]) + -> Vec> { + let mut vars = Vec::with_capacity(defs.len()); + + for def in defs.iter() { + let ty_var = self.next_ty_var(); + match def.default { + None => {}, + Some(default) => { self.defaults.borrow_mut().insert(ty_var, default); } + } + vars.push(ty_var) + } + + vars + } + /// Given a set of generics defined on a type or impl, returns a substitution mapping each /// type/region parameter to a fresh inference variable. pub fn fresh_substs_for_generics(&self, @@ -1003,9 +1048,12 @@ pub fn fresh_substs_for_generics(&self, generics: &ty::Generics<'tcx>) -> subst::Substs<'tcx> { - let type_params = - generics.types.map( - |_| self.next_ty_var()); + let mut type_params = subst::VecPerParamSpace::empty(); + + for space in subst::ParamSpace::all().iter() { + type_params.replace(*space, self.type_vars_for_defs(generics.types.get_slice(*space))) + } + let region_params = generics.regions.map( |d| self.next_region_var(EarlyBoundRegion(span, d.name))); @@ -1027,8 +1075,8 @@ pub fn fresh_substs_for_trait(&self, assert!(generics.regions.len(subst::SelfSpace) == 0); assert!(generics.regions.len(subst::FnSpace) == 0); - let type_parameter_count = generics.types.len(subst::TypeSpace); - let type_parameters = self.next_ty_vars(type_parameter_count); + let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); + let type_parameters = self.type_vars_for_defs(type_parameter_defs); let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); @@ -1268,6 +1316,24 @@ pub fn report_mismatched_types(&self, self.report_and_explain_type_error(trace, err); } + pub fn report_conflicting_default_types(&self, + span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>) { + let trace = TypeTrace { + origin: Misc(span), + values: Types(ty::expected_found { + expected: expected, + found: actual + }) + }; + + self.report_and_explain_type_error(trace, &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found { + expected: expected, + found: actual + })); + } + pub fn replace_late_bound_regions_with_fresh_var( &self, span: Span, diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 6f1de3ee6359..ebecb0898b4d 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -195,6 +195,15 @@ pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { escaping_types } + + pub fn unsolved_variables(&self) -> Vec { + self.values.iter().enumerate().filter_map(|(i, value)| + match &value.value { + &TypeVariableValue::Known(_) => None, + &TypeVariableValue::Bounded(_) => Some(ty::TyVid { index: i as u32 }) + } + ).collect() + } } impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 84ca7cd437a9..a08c5e1f73fa 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2068,6 +2068,7 @@ pub enum TypeError<'tcx> { ConvergenceMismatch(ExpectedFound), ProjectionNameMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), + terr_ty_param_default_mismatch(expected_found>) } /// Bounds suitable for an existentially quantified type parameter @@ -5080,6 +5081,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "expected {} associated type bindings, found {}", values.expected, values.found) + }, + terr_ty_param_default_mismatch(ref values) => { + write!(f, "conflicting type parameter defaults {} {}", + values.expected, + values.found) } } } @@ -5437,6 +5443,11 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { &format!("consider boxing your closure and/or \ using it as a trait object")); } + }, + terr_ty_param_default_mismatch(expected) => { + self.sess.span_note(sp, + &format!("found conflicting defaults {:?} {:?}", + expected.expected, expected.found)) } _ => {} } diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index a899bbacc030..7582b7ff61d8 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -339,5 +339,11 @@ pub fn has_value(&mut self, id: K) -> bool { pub fn probe(&mut self, a_id: K) -> Option { self.get(a_id).value.clone() } -} + pub fn unsolved_variables(&mut self) -> Vec { + self.values + .iter() + .filter_map(|vv| if vv.value.is_some() { None } else { Some(vv.key()) }) + .collect() + } +} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a8c56b2660ce..e3b9b990cb9e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -309,15 +309,17 @@ fn instantiate_method_substs(&mut self, // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let num_method_types = pick.item.as_opt_method().unwrap() - .generics.types.len(subst::FnSpace); + let method = pick.item.as_opt_method().unwrap(); + let method_types = method.generics.types.get_slice(subst::FnSpace); + let num_method_types = method_types.len(); + let method_types = { if num_supplied_types == 0 { - self.fcx.infcx().next_ty_vars(num_method_types) + self.fcx.infcx().type_vars_for_defs(method_types) } else if num_method_types == 0 { span_err!(self.tcx().sess, self.span, E0035, "does not take type parameters"); - self.fcx.infcx().next_ty_vars(num_method_types) + self.fcx.infcx().type_vars_for_defs(method_types) } else if num_supplied_types != num_method_types { span_err!(self.tcx().sess, self.span, E0036, "incorrect number of type parameters given for this method"); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index a74c004389b4..2ca5a88fb06d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -167,7 +167,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let trait_def = fcx.tcx().lookup_trait_def(trait_def_id); - let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace); + let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); + let expected_number_of_input_types = type_parameter_defs.len(); let input_types = match opt_input_types { Some(input_types) => { assert_eq!(expected_number_of_input_types, input_types.len()); @@ -175,7 +176,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } None => { - fcx.inh.infcx.next_ty_vars(expected_number_of_input_types) + fcx.inh.infcx.type_vars_for_defs(type_parameter_defs) } }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index a960123efc6b..88bd000cfdd6 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1207,8 +1207,8 @@ fn xform_method_self_ty(&self, !method.generics.regions.is_empty_in(subst::FnSpace) { let method_types = - self.infcx().next_ty_vars( - method.generics.types.len(subst::FnSpace)); + self.infcx().type_vars_for_defs( + method.generics.types.get_slice(subst::FnSpace)); // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 082dafc72bc6..e226b0b21a1e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -108,6 +108,7 @@ use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; +use std::collections::HashSet; use std::mem::replace; use std::slice; use syntax::{self, abi, attr}; @@ -1255,28 +1256,6 @@ pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> { } } - /// Apply "fallbacks" to some types - /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. - pub fn default_type_parameters(&self) { - use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - for (_, &mut ref ty) in &mut self.inh.tables.borrow_mut().node_types { - let resolved = self.infcx().resolve_type_vars_if_possible(ty); - if self.infcx().type_var_diverges(resolved) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); - } else { - 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 => { } - } - } - } - } - #[inline] pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", @@ -1711,11 +1690,98 @@ fn check_casts(&self) { } fn select_all_obligations_and_apply_defaults(&self) { - debug!("select_all_obligations_and_apply_defaults"); + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - self.select_obligations_where_possible(); - self.default_type_parameters(); - self.select_obligations_where_possible(); + debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults); + + for _ in (0..self.tcx().sess.recursion_limit.get()) { + self.select_obligations_where_possible(); + + let unsolved_variables = self.inh.infcx.unsolved_variables(); + let mut unbound_tyvars = HashSet::new(); + + // Gather all unconstrainted integer and float variables + for ty in &unsolved_variables { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if self.infcx().type_var_diverges(resolved) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt => { + unbound_tyvars.insert(resolved); + }, + UnconstrainedFloat => { + unbound_tyvars.insert(resolved); + } + Neither => {} + } + } + } + + // Collect the set of variables that need fallback applied + for ty in &unsolved_variables { + if self.inh.infcx.defaults.borrow().contains_key(ty) { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + + debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + ty, self.inh.infcx.defaults.borrow().get(ty)); + + match resolved.sty { + ty::TyInfer(ty::TyVar(_)) => { + unbound_tyvars.insert(ty); + } + + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => { + unbound_tyvars.insert(ty); + if unbound_tyvars.contains(resolved) { + unbound_tyvars.remove(resolved); + } + } + + _ => {} + } + } + } + + if unbound_tyvars.is_empty() { + break; + } + + // Go through the unbound variables and unify them with the proper fallbacks + for ty in &unbound_tyvars { + // let resolved = self.infcx().resolve_type_vars_if_possible(ty); + 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 => { + let default_map = self.inh.infcx.defaults.borrow(); + if let Some(default) = default_map.get(ty) { + match infer::mk_eqty(self.infcx(), false, + infer::Misc(codemap::DUMMY_SP), + ty, default) { + Ok(()) => { /* ok */ } + Err(_) => { + self.infcx().report_conflicting_default_types( + codemap::DUMMY_SP, + ty, + default) + } + } + } + } + } + } + } + + self.select_obligations_where_possible(); + } } fn select_all_obligations_or_error(&self) { @@ -2421,13 +2487,15 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.tcx(); let ity = tcx.lookup_item_type(did); - let (n_tps, rps, raw_ty) = - (ity.generics.types.len(subst::TypeSpace), + let (tps, rps, raw_ty) = + (ity.generics.types.get_slice(subst::TypeSpace), ity.generics.regions.get_slice(subst::TypeSpace), ity.ty); + debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); + let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); - let tps = fcx.inh.infcx.next_ty_vars(n_tps); + let tps = fcx.inh.infcx.type_vars_for_defs(tps); let substs = subst::Substs::new_type(tps, rps); let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); @@ -4647,7 +4715,7 @@ fn adjust_type_parameters<'a, 'tcx>( // Nothing specified at all: supply inference variables for // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { - substs.types.replace(space, fcx.infcx().next_ty_vars(desired.len())); + substs.types.replace(space, fcx.infcx().type_vars_for_defs(&desired[..])); return; } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs new file mode 100644 index 000000000000..900945da1136 --- /dev/null +++ b/src/test/compile-fail/default_ty_param_conflict.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. + +use std::fmt::Debug; + +// Example from the RFC +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/compile-fail/default_ty_param_type_alias.rs b/src/test/compile-fail/default_ty_param_type_alias.rs new file mode 100644 index 000000000000..c3e44e55beeb --- /dev/null +++ b/src/test/compile-fail/default_ty_param_type_alias.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. + +use std::collections::HashMap; + +type IntMap = HashMap; + +fn main() { + let x = IntMap::new(); +} diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs new file mode 100644 index 000000000000..35f0fcab0017 --- /dev/null +++ b/src/test/run-pass/default_ty_param_method_call_test.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. + +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_struct.rs b/src/test/run-pass/default_ty_param_struct.rs new file mode 100644 index 000000000000..b94b759fd113 --- /dev/null +++ b/src/test/run-pass/default_ty_param_struct.rs @@ -0,0 +1,21 @@ +// 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. + +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_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs new file mode 100644 index 000000000000..fbceb60b9a8e --- /dev/null +++ b/src/test/run-pass/default_ty_param_trait_impl.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. + +// Another example from the RFC +trait Foo { } +trait Bar { } + +impl Foo for Vec {} // Impl 1 +impl Bar for usize { } // Impl 2 + +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_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs new file mode 100644 index 000000000000..00d7ccf43bec --- /dev/null +++ b/src/test/run-pass/default_ty_param_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. + +// An example from the RFC +trait Foo { fn takes_foo(&self); } +trait Bar { } + +impl Foo for Vec { + fn takes_foo(&self) {} +} // Impl 1 + +impl Bar for usize { } // Impl 2 + +// fn takes_foo(f: F) { } + +fn main() { + let x = Vec::new(); // x: Vec<$0> + x.takes_foo(); // adds oblig Vec<$0> : Foo +} From 91de8e6c281fafd257e52def26551b2b722aaddb Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 7 Jul 2015 16:06:35 -0700 Subject: [PATCH 02/18] Fix tidy --- src/librustc/middle/infer/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 5339464503b3..59ca795e5f75 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1328,9 +1328,10 @@ pub fn report_conflicting_default_types(&self, }) }; - self.report_and_explain_type_error(trace, &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found { - expected: expected, - found: actual + self.report_and_explain_type_error(trace, + &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found { + expected: expected, + found: actual })); } From bbdca2c8aded0497c289536ee5ead694ca2d8fc0 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 8 Jul 2015 13:42:46 -0700 Subject: [PATCH 03/18] Correctly collect defaults from type alises in astconv --- src/librustc_typeck/astconv.rs | 12 ++++++------ src/librustc_typeck/check/mod.rs | 9 +++++++-- src/librustc_typeck/collect.rs | 2 +- .../default_ty_param_type_alias.rs | 0 4 files changed, 14 insertions(+), 9 deletions(-) rename src/test/{compile-fail => run-pass}/default_ty_param_type_alias.rs (100%) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c448af2288a6..5ed1da2fedeb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -111,7 +111,7 @@ fn get_free_substs(&self) -> Option<&Substs<'tcx>> { } /// What type should we use when a type is omitted? - fn ty_infer(&self, span: Span) -> Ty<'tcx>; + fn ty_infer(&self, default: Option>, span: Span) -> Ty<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -403,7 +403,7 @@ fn create_substs_for_ast_path<'tcx>( // they were optional (e.g. paths inside expressions). let mut type_substs = if param_mode == PathParamMode::Optional && types_provided.is_empty() { - (0..formal_ty_param_count).map(|_| this.ty_infer(span)).collect() + ty_param_defs.iter().map(|p| this.ty_infer(p.default, span)).collect() } else { types_provided }; @@ -1661,7 +1661,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, // values in a ExprClosure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. - this.ty_infer(ast_ty.span) + this.ty_infer(None, ast_ty.span) } }; @@ -1677,7 +1677,7 @@ pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, { match a.ty.node { ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), - ast::TyInfer => this.ty_infer(a.ty.span), + ast::TyInfer => this.ty_infer(None, a.ty.span), _ => ast_ty_to_ty(this, rscope, &*a.ty), } } @@ -1796,7 +1796,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, let output_ty = match decl.output { ast::Return(ref output) if output.node == ast::TyInfer => - ty::FnConverging(this.ty_infer(output.span)), + ty::FnConverging(this.ty_infer(None, output.span)), ast::Return(ref output) => ty::FnConverging(convert_ty_with_lifetime_elision(this, implied_output_region, @@ -1936,7 +1936,7 @@ pub fn ty_of_closure<'tcx>( _ if is_infer && expected_ret_ty.is_some() => expected_ret_ty.unwrap(), _ if is_infer => - ty::FnConverging(this.ty_infer(decl.output.span())), + ty::FnConverging(this.ty_infer(None, decl.output.span())), ast::Return(ref output) => ty::FnConverging(ast_ty_to_ty(this, &rb, &**output)), ast::DefaultReturn(..) => unreachable!(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e226b0b21a1e..ae2b3448e01d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1138,8 +1138,13 @@ fn trait_defines_associated_type_named(&self, trait_def.associated_type_names.contains(&assoc_name) } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { - self.infcx().next_ty_var() + fn ty_infer(&self, default: Option>, _span: Span) -> Ty<'tcx> { + let ty_var = self.infcx().next_ty_var(); + match default { + Some(default) => { self.infcx().defaults.borrow_mut().insert(ty_var, default); } + None => {} + } + ty_var } fn projected_ty_from_poly_trait_ref(&self, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5a6519cb4b7a..695991a97f06 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,7 @@ fn trait_defines_associated_type_named(&self, } } - fn ty_infer(&self, span: Span) -> Ty<'tcx> { + fn ty_infer(&self, _default: Option>, span: Span) -> Ty<'tcx> { span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); self.tcx().types.err diff --git a/src/test/compile-fail/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs similarity index 100% rename from src/test/compile-fail/default_ty_param_type_alias.rs rename to src/test/run-pass/default_ty_param_type_alias.rs From 49eb2c6763e68ee462b5808ab558b4fa9f84fcc0 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 9 Jul 2015 12:15:48 -0700 Subject: [PATCH 04/18] Remove defaults table and attach defaults directly to tyvars --- src/librustc/middle/infer/mod.rs | 54 ++++++++++++++----- src/librustc/middle/infer/type_variable.rs | 45 +++++++++++----- src/librustc_typeck/check/mod.rs | 25 ++++----- ...meter_default_dependent_associated_type.rs | 23 ++++++++ ...fault_type_parameter_dependent_defaults.rs | 7 +++ ...lt_type_parameter_struct_and_type_alias.rs | 30 +++++++++++ 6 files changed, 143 insertions(+), 41 deletions(-) create mode 100644 src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs create mode 100644 src/test/run-pass/default_type_parameter_dependent_defaults.rs create mode 100644 src/test/run-pass/default_type_parameter_struct_and_type_alias.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 59ca795e5f75..db6e0ad1d4a8 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -95,9 +95,6 @@ pub struct InferCtxt<'a, 'tcx: 'a> { normalize: bool, err_count_on_creation: usize, - - // Default Type Parameter fallbacks - pub defaults: RefCell, Ty<'tcx>>>, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -353,8 +350,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)), normalize: false, - err_count_on_creation: tcx.sess.err_count(), - defaults: RefCell::new(FnvHashMap()), + err_count_on_creation: tcx.sess.err_count() } } @@ -657,27 +653,44 @@ pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { } } + /// 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. + /// + /// 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> { + match ty.sty { + ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), + _ => None + } + } + pub fn unsolved_variables(&self) -> Vec> { let mut variables = Vec::new(); let unbound_ty_vars = self.type_variables .borrow() .unsolved_variables() - .into_iter().map(|t| self.tcx.mk_var(t)); + .into_iter() + .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)); + .into_iter() + .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)); + .into_iter() + .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; } @@ -984,13 +997,22 @@ pub fn region_outlives_predicate(&self, pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { self.type_variables .borrow_mut() - .new_var(diverging) + .new_var(diverging, None) } pub fn next_ty_var(&self) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(false)) } + pub fn next_ty_var_with_default(&self, + default: Option>) -> Ty<'tcx> { + let ty_var_id = self.type_variables + .borrow_mut() + .new_var(false, default); + + self.tcx.mk_var(ty_var_id) + } + pub fn next_diverging_ty_var(&self) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(true)) } @@ -1027,14 +1049,18 @@ pub fn region_vars_for_defs(&self, pub fn type_vars_for_defs(&self, defs: &[ty::TypeParameterDef<'tcx>]) -> Vec> { + let mut substs = Substs::empty(); let mut vars = Vec::with_capacity(defs.len()); for def in defs.iter() { - let ty_var = self.next_ty_var(); - match def.default { - None => {}, - Some(default) => { self.defaults.borrow_mut().insert(ty_var, default); } - } + let default = def.default.map(|default| { + type_variable::Default { + ty: default + } + }); + //.subst(self.tcx, &substs) + let ty_var = self.next_ty_var_with_default(default); + substs.types.push(subst::ParamSpace::SelfSpace, ty_var); vars.push(ty_var) } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index ebecb0898b4d..6ba289d3665a 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -30,7 +30,17 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), - Bounded(Vec), + Bounded { + relations: Vec, + default: Option> + } +} + +// We will use this to store the required information to recapitulate what happened when +// an error occurs. +#[derive(Clone)] +pub struct Default<'tcx> { + pub ty: Ty<'tcx> } pub struct Snapshot { @@ -72,6 +82,13 @@ fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { relations(self.values.get_mut(a.index as usize)) } + 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 var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { self.values.get(vid.index as usize).diverging } @@ -102,7 +119,7 @@ pub fn instantiate_and_push( }; let relations = match old_value { - Bounded(b) => b, + Bounded { relations, .. } => relations, Known(_) => panic!("Asked to instantiate variable that is \ already instantiated") }; @@ -114,9 +131,11 @@ pub fn instantiate_and_push( self.values.record(SpecifyVar(vid, relations)); } - pub fn new_var(&mut self, diverging: bool) -> ty::TyVid { + pub fn new_var(&mut self, + diverging: bool, + default: Option>) -> ty::TyVid { let index = self.values.push(TypeVariableData { - value: Bounded(vec![]), + value: Bounded { relations: vec![], default: default }, diverging: diverging }); ty::TyVid { index: index as u32 } @@ -124,7 +143,7 @@ pub fn new_var(&mut self, diverging: bool) -> ty::TyVid { pub fn probe(&self, vid: ty::TyVid) -> Option> { match self.values.get(vid.index as usize).value { - Bounded(..) => None, + Bounded { .. } => None, Known(t) => Some(t) } } @@ -197,12 +216,14 @@ pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { } pub fn unsolved_variables(&self) -> Vec { - self.values.iter().enumerate().filter_map(|(i, value)| - match &value.value { + self.values + .iter() + .enumerate() + .filter_map(|(i, value)| match &value.value { &TypeVariableValue::Known(_) => None, - &TypeVariableValue::Bounded(_) => Some(ty::TyVid { index: i as u32 }) - } - ).collect() + &TypeVariableValue::Bounded { .. } => Some(ty::TyVid { index: i as u32 }) + }) + .collect() } } @@ -213,7 +234,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { fn reverse(values: &mut Vec>, action: UndoEntry) { match action { SpecifyVar(vid, relations) => { - values[vid.index as usize].value = Bounded(relations); + values[vid.index as usize].value = Bounded { relations: relations, default: None }; } Relate(a, b) => { @@ -227,6 +248,6 @@ fn reverse(values: &mut Vec>, action: UndoEntry) { fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { match v.value { Known(_) => panic!("var_sub_var: variable is known"), - Bounded(ref mut relations) => relations + Bounded { ref mut relations, .. } => relations } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae2b3448e01d..f6a4dbca291b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,6 +87,7 @@ use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; use middle::infer; +use middle::infer::type_variable; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; @@ -1139,12 +1140,8 @@ fn trait_defines_associated_type_named(&self, } fn ty_infer(&self, default: Option>, _span: Span) -> Ty<'tcx> { - let ty_var = self.infcx().next_ty_var(); - match default { - Some(default) => { self.infcx().defaults.borrow_mut().insert(ty_var, default); } - None => {} - } - ty_var + let default = default.map(|t| type_variable::Default { ty: t }); + self.infcx().next_ty_var_with_default(default) } fn projected_ty_from_poly_trait_ref(&self, @@ -1697,7 +1694,7 @@ fn check_casts(&self) { fn select_all_obligations_and_apply_defaults(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults); + // debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults); for _ in (0..self.tcx().sess.recursion_limit.get()) { self.select_obligations_where_possible(); @@ -1725,11 +1722,11 @@ fn select_all_obligations_and_apply_defaults(&self) { // Collect the set of variables that need fallback applied for ty in &unsolved_variables { - if self.inh.infcx.defaults.borrow().contains_key(ty) { + if let Some(_) = self.inh.infcx.default(ty) { let resolved = self.infcx().resolve_type_vars_if_possible(ty); - debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", - ty, self.inh.infcx.defaults.borrow().get(ty)); + // debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + // ty, self.inh.infcx.defaults.borrow().get(ty)); match resolved.sty { ty::TyInfer(ty::TyVar(_)) => { @@ -1754,7 +1751,6 @@ fn select_all_obligations_and_apply_defaults(&self) { // Go through the unbound variables and unify them with the proper fallbacks for ty in &unbound_tyvars { - // let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(ty) { demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { @@ -1766,17 +1762,16 @@ fn select_all_obligations_and_apply_defaults(&self) { demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { - let default_map = self.inh.infcx.defaults.borrow(); - if let Some(default) = default_map.get(ty) { + if let Some(default) = self.inh.infcx.default(ty) { match infer::mk_eqty(self.infcx(), false, infer::Misc(codemap::DUMMY_SP), - ty, default) { + ty, default.ty) { Ok(()) => { /* ok */ } Err(_) => { self.infcx().report_conflicting_default_types( codemap::DUMMY_SP, ty, - default) + default.ty) } } } diff --git a/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs b/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs new file mode 100644 index 000000000000..402399f14b93 --- /dev/null +++ b/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs @@ -0,0 +1,23 @@ +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_type_parameter_dependent_defaults.rs b/src/test/run-pass/default_type_parameter_dependent_defaults.rs new file mode 100644 index 000000000000..4f492bed9d4f --- /dev/null +++ b/src/test/run-pass/default_type_parameter_dependent_defaults.rs @@ -0,0 +1,7 @@ +use std::marker::PhantomData; + +struct Foo { data: PhantomData<(T, U)> } + +fn main() { + let foo = Foo { data: PhantomData }; +} diff --git a/src/test/run-pass/default_type_parameter_struct_and_type_alias.rs b/src/test/run-pass/default_type_parameter_struct_and_type_alias.rs new file mode 100644 index 000000000000..d42e65d90fee --- /dev/null +++ b/src/test/run-pass/default_type_parameter_struct_and_type_alias.rs @@ -0,0 +1,30 @@ +use std::marker::PhantomData; + +trait TypeEq {} +impl TypeEq for A {} + +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); +} From d782e35c30a9642afe4ea28614efc08025694b1b Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 9 Jul 2015 16:04:37 -0700 Subject: [PATCH 05/18] Fix bug with defaults not being restored --- src/librustc/middle/infer/type_variable.rs | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 6ba289d3665a..fa7cd143e3b2 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -47,9 +47,9 @@ pub struct Snapshot { snapshot: sv::Snapshot } -enum UndoEntry { +enum UndoEntry<'tcx> { // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec), + SpecifyVar(ty::TyVid, Vec, Option>), Relate(ty::TyVid, ty::TyVid), } @@ -118,8 +118,8 @@ pub fn instantiate_and_push( mem::replace(value_ptr, Known(ty)) }; - let relations = match old_value { - Bounded { relations, .. } => relations, + let (relations, default) = match old_value { + Bounded { relations, default } => (relations, default), Known(_) => panic!("Asked to instantiate variable that is \ already instantiated") }; @@ -128,7 +128,7 @@ pub fn instantiate_and_push( stack.push((ty, dir, vid)); } - self.values.record(SpecifyVar(vid, relations)); + self.values.record(SpecifyVar(vid, relations, default)); } pub fn new_var(&mut self, @@ -198,7 +198,7 @@ pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(SpecifyVar(vid, _)) => { + sv::UndoLog::Other(SpecifyVar(vid, _, _)) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. @@ -229,12 +229,15 @@ pub fn unsolved_variables(&self) -> Vec { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry; + type Undo = UndoEntry<'tcx>; - fn reverse(values: &mut Vec>, action: UndoEntry) { + fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { match action { - SpecifyVar(vid, relations) => { - values[vid.index as usize].value = Bounded { relations: relations, default: None }; + SpecifyVar(vid, relations, default) => { + values[vid.index as usize].value = Bounded { + relations: relations, + default: default + }; } Relate(a, b) => { From 01dcb3bdf0fd779208c915d704ae634beb5c4448 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sun, 12 Jul 2015 20:33:17 -0700 Subject: [PATCH 06/18] Refactor the default type parameter algorithm The algorithm was not correctly detecting conflicts after moving defaults into TypeVariableValue. The updated algorithm correctly detects and reports conflicts with information about where the conflict occured and which items the defaults were introduced by. The span's for said items are not being correctly attached and still need to be patched. --- src/librustc/middle/infer/error_reporting.rs | 4 +- src/librustc/middle/infer/mod.rs | 41 +++-- src/librustc/middle/infer/type_variable.rs | 11 +- src/librustc/middle/ty.rs | 28 +++- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 151 ++++++++++++++++--- src/librustc_typeck/collect.rs | 2 +- src/rust-installer | 2 +- 11 files changed, 198 insertions(+), 53 deletions(-) diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 8d66ffac5d17..fbf19a10d93b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -893,8 +893,8 @@ fn report_processed_errors(&self, self.report_inference_failure(vo.clone()); } self.give_suggestion(same_regions); - for &(ref trace, terr) in trace_origins { - self.report_and_explain_type_error(trace.clone(), &terr); + for &(ref trace, ref terr) in trace_origins { + self.report_and_explain_type_error(trace.clone(), terr); } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index db6e0ad1d4a8..d38417143ce0 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -40,6 +40,7 @@ use syntax::codemap::{Span, DUMMY_SP}; use util::nodemap::{FnvHashMap, NodeMap}; +use ast_map; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::error_reporting::ErrorReporting; @@ -72,7 +73,7 @@ pub struct InferCtxt<'a, 'tcx: 'a> { // We instantiate UnificationTable with bounds because the // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. - type_variables: RefCell>, + pub type_variables: RefCell>, // Map from integral variable to the kind of integer it represents int_unification_table: RefCell>, @@ -690,7 +691,7 @@ pub fn unsolved_variables(&self) -> Vec> { variables.extend(unbound_ty_vars); variables.extend(unbound_int_vars); variables.extend(unbound_float_vars); - + return variables; } @@ -1047,15 +1048,36 @@ pub fn region_vars_for_defs(&self, } pub fn type_vars_for_defs(&self, + span: Span, + // substs: Substs, defs: &[ty::TypeParameterDef<'tcx>]) -> Vec> { + + fn definition_span<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId) -> Span { + let parent = tcx.map.get_parent(def_id.node); + debug!("definition_span def_id={:?} parent={:?} node={:?} parent_node={:?}", + def_id, parent, tcx.map.find(def_id.node), tcx.map.find(parent)); + match tcx.map.find(parent) { + None => DUMMY_SP, + Some(ref node) => match *node { + ast_map::NodeItem(ref item) => item.span, + ast_map::NodeForeignItem(ref item) => item.span, + ast_map::NodeTraitItem(ref item) => item.span, + ast_map::NodeImplItem(ref item) => item.span, + _ => DUMMY_SP + } + } + } + let mut substs = Substs::empty(); let mut vars = Vec::with_capacity(defs.len()); for def in defs.iter() { let default = def.default.map(|default| { type_variable::Default { - ty: default + ty: default, + origin_span: span, + definition_span: definition_span(self.tcx, def.def_id) } }); //.subst(self.tcx, &substs) @@ -1077,7 +1099,8 @@ pub fn fresh_substs_for_generics(&self, let mut type_params = subst::VecPerParamSpace::empty(); for space in subst::ParamSpace::all().iter() { - type_params.replace(*space, self.type_vars_for_defs(generics.types.get_slice(*space))) + type_params.replace(*space, + self.type_vars_for_defs(span, generics.types.get_slice(*space))) } let region_params = @@ -1102,7 +1125,7 @@ pub fn fresh_substs_for_trait(&self, assert!(generics.regions.len(subst::FnSpace) == 0); let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); - let type_parameters = self.type_vars_for_defs(type_parameter_defs); + let type_parameters = self.type_vars_for_defs(span, type_parameter_defs); let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); @@ -1344,13 +1367,13 @@ pub fn report_mismatched_types(&self, pub fn report_conflicting_default_types(&self, span: Span, - expected: Ty<'tcx>, - actual: Ty<'tcx>) { + expected: type_variable::Default<'tcx>, + actual: type_variable::Default<'tcx>) { let trace = TypeTrace { origin: Misc(span), values: Types(ty::expected_found { - expected: expected, - found: actual + expected: expected.ty, + found: actual.ty }) }; diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index fa7cd143e3b2..8707306a149c 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -11,8 +11,9 @@ pub use self::RelationDir::*; use self::TypeVariableValue::*; use self::UndoEntry::*; - use middle::ty::{self, Ty}; +use syntax::codemap::Span; + use std::cmp::min; use std::marker::PhantomData; use std::mem; @@ -38,9 +39,13 @@ enum TypeVariableValue<'tcx> { // We will use this to store the required information to recapitulate what happened when // an error occurs. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Default<'tcx> { - pub ty: Ty<'tcx> + pub ty: Ty<'tcx>, + /// The span where the default was incurred + pub origin_span: Span, + /// The definition that the default originates from + pub definition_span: Span } pub struct Snapshot { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a08c5e1f73fa..19add679bbfd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -54,6 +54,7 @@ use middle::region; use middle::resolve_lifetime; use middle::infer; +use middle::infer::type_variable; use middle::pat_util; use middle::region::RegionMaps; use middle::stability; @@ -2068,7 +2069,7 @@ pub enum TypeError<'tcx> { ConvergenceMismatch(ExpectedFound), ProjectionNameMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), - terr_ty_param_default_mismatch(expected_found>) + TyParamDefaultMismatch(ExpectedFound>) } /// Bounds suitable for an existentially quantified type parameter @@ -5083,9 +5084,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { values.found) }, terr_ty_param_default_mismatch(ref values) => { - write!(f, "conflicting type parameter defaults {} {}", - values.expected, - values.found) + write!(f, "conflicting type parameter defaults {} and {}", + values.expected.ty, + values.found.ty) } } } @@ -5405,7 +5406,7 @@ pub fn field_idx_strict(&self, name: ast::Name, fields: &[Field<'tcx>]) pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { use self::TypeError::*; - match *err { + match err.clone() { RegionsDoesNotOutlive(subregion, superregion) => { self.note_and_explain_region("", subregion, "..."); self.note_and_explain_region("...does not necessarily outlive ", @@ -5444,10 +5445,21 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { using it as a trait object")); } }, - terr_ty_param_default_mismatch(expected) => { + terr_ty_param_default_mismatch(values) => { + let expected = values.expected; + let found = values.found; self.sess.span_note(sp, - &format!("found conflicting defaults {:?} {:?}", - expected.expected, expected.found)) + &format!("conflicting type parameter defaults {} and {}", + expected.ty, + found.ty)); + self.sess.span_note(expected.definition_span, + &format!("...a default was defined")); + self.sess.span_note(expected.origin_span, + &format!("...that was applied to an unconstrained type variable here")); + self.sess.span_note(found.definition_span, + &format!("...a second default was defined")); + self.sess.span_note(found.origin_span, + &format!("...that also applies to the same type variable here")); } _ => {} } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5ed1da2fedeb..3925f4e751c2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -111,7 +111,7 @@ fn get_free_substs(&self) -> Option<&Substs<'tcx>> { } /// What type should we use when a type is omitted? - fn ty_infer(&self, default: Option>, span: Span) -> Ty<'tcx>; + fn ty_infer(&self, default: Option>, span: Span) -> Ty<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -403,7 +403,7 @@ fn create_substs_for_ast_path<'tcx>( // they were optional (e.g. paths inside expressions). let mut type_substs = if param_mode == PathParamMode::Optional && types_provided.is_empty() { - ty_param_defs.iter().map(|p| this.ty_infer(p.default, span)).collect() + ty_param_defs.iter().map(|p| this.ty_infer(Some(p.clone()), span)).collect() } else { types_provided }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e3b9b990cb9e..488428833ac1 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -315,11 +315,11 @@ fn instantiate_method_substs(&mut self, let method_types = { if num_supplied_types == 0 { - self.fcx.infcx().type_vars_for_defs(method_types) + self.fcx.infcx().type_vars_for_defs(self.span, method_types) } else if num_method_types == 0 { span_err!(self.tcx().sess, self.span, E0035, "does not take type parameters"); - self.fcx.infcx().type_vars_for_defs(method_types) + self.fcx.infcx().type_vars_for_defs(self.span, method_types) } else if num_supplied_types != num_method_types { span_err!(self.tcx().sess, self.span, E0036, "incorrect number of type parameters given for this method"); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2ca5a88fb06d..767797e843ca 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -176,7 +176,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } None => { - fcx.inh.infcx.type_vars_for_defs(type_parameter_defs) + fcx.inh.infcx.type_vars_for_defs(span, type_parameter_defs) } }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 88bd000cfdd6..b190e7a7a483 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1207,7 +1207,7 @@ fn xform_method_self_ty(&self, !method.generics.regions.is_empty_in(subst::FnSpace) { let method_types = - self.infcx().type_vars_for_defs( + self.infcx().type_vars_for_defs(self.span, method.generics.types.get_slice(subst::FnSpace)); // In general, during probe we erase regions. See diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f6a4dbca291b..3a93c7ed9161 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1139,8 +1139,9 @@ fn trait_defines_associated_type_named(&self, trait_def.associated_type_names.contains(&assoc_name) } - fn ty_infer(&self, default: Option>, _span: Span) -> Ty<'tcx> { - let default = default.map(|t| type_variable::Default { ty: t }); + fn ty_infer(&self, ty_param_def: Option>, span: Span) -> Ty<'tcx> { + let default = ty_param_def.and_then(|t| + t.default.map(|ty| type_variable::Default { ty: ty, origin_span: span, definition_span: span })); self.infcx().next_ty_var_with_default(default) } @@ -1694,39 +1695,61 @@ fn check_casts(&self) { fn select_all_obligations_and_apply_defaults(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - // debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults); + // 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(); + // There is a possibility 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(); - // Gather all unconstrainted integer and float variables + debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); + + // We loop over the unsolved variables, resolving them and if they are + // and unconstrainted numberic type we add them to the set of unbound + // variables. We do this so we only apply literal fallback to type + // variables without defaults. for ty in &unsolved_variables { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { + UnconstrainedInt | UnconstrainedFloat => { unbound_tyvars.insert(resolved); }, - UnconstrainedFloat => { - unbound_tyvars.insert(resolved); - } Neither => {} } } } - // Collect the set of variables that need fallback applied + // We now remove any numeric types that also have defaults, and instead insert + // the type variable with a defined fallback. for ty in &unsolved_variables { - if let Some(_) = self.inh.infcx.default(ty) { + if let Some(_default) = default_map.get(ty) { let resolved = self.infcx().resolve_type_vars_if_possible(ty); - // debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", - // ty, self.inh.infcx.defaults.borrow().get(ty)); + debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + ty, _default); match resolved.sty { ty::TyInfer(ty::TyVar(_)) => { @@ -1745,11 +1768,21 @@ fn select_all_obligations_and_apply_defaults(&self) { } } + // 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; } - // Go through the unbound variables and unify them with the proper fallbacks + // Finally we go 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 it must be a conflicting default because the + // variable would only be in `unbound_tyvars` and have a concrete value if + // it had been solved by previously applying a default. + + // We take a snapshot for use in error reporting. + let snapshot = self.infcx().type_variables.borrow_mut().snapshot(); + for ty in &unbound_tyvars { if self.infcx().type_var_diverges(ty) { demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); @@ -1762,16 +1795,14 @@ fn select_all_obligations_and_apply_defaults(&self) { demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { - if let Some(default) = self.inh.infcx.default(ty) { + if let Some(default) = default_map.get(ty) { + let default = default.clone(); match infer::mk_eqty(self.infcx(), false, - infer::Misc(codemap::DUMMY_SP), + infer::Misc(default.origin_span), ty, default.ty) { - Ok(()) => { /* ok */ } + Ok(()) => {} Err(_) => { - self.infcx().report_conflicting_default_types( - codemap::DUMMY_SP, - ty, - default.ty) + conflicts.push((*ty, default)); } } } @@ -1780,8 +1811,82 @@ fn select_all_obligations_and_apply_defaults(&self) { } } - self.select_obligations_where_possible(); + // There were some errors to report + if conflicts.len() > 0 { + self.infcx().type_variables.borrow_mut().rollback_to(snapshot); + + 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, + definition_span: codemap::DUMMY_SP + }); + + self.infcx().report_conflicting_default_types( + conflicting_default.origin_span, + conflicting_default, + default) + } + } else { + self.infcx().type_variables.borrow_mut().commit(snapshot) + } } + + 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::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + + // Ensure that the conflicting default is applied 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. + 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) { @@ -2495,7 +2600,7 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); - let tps = fcx.inh.infcx.type_vars_for_defs(tps); + let tps = fcx.inh.infcx.type_vars_for_defs(span, tps); let substs = subst::Substs::new_type(tps, rps); let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); @@ -4715,7 +4820,7 @@ fn adjust_type_parameters<'a, 'tcx>( // Nothing specified at all: supply inference variables for // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { - substs.types.replace(space, fcx.infcx().type_vars_for_defs(&desired[..])); + substs.types.replace(space, fcx.infcx().type_vars_for_defs(span, &desired[..])); return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 695991a97f06..8b38c58ce7a1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,7 @@ fn trait_defines_associated_type_named(&self, } } - fn ty_infer(&self, _default: Option>, span: Span) -> Ty<'tcx> { + fn ty_infer(&self, _default: Option>, span: Span) -> Ty<'tcx> { span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); self.tcx().types.err diff --git a/src/rust-installer b/src/rust-installer index c37d3747da75..8e4f8ea58150 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit c37d3747da75c280237dc2d6b925078e69555499 +Subproject commit 8e4f8ea581502a2edc8177a040300e05ff7f91e3 From e85787102fa6a7b27e1df845c07084f6a7d77fe3 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sun, 12 Jul 2015 21:02:16 -0700 Subject: [PATCH 07/18] Clean up test cases --- src/librustc_typeck/check/mod.rs | 6 +++- ...param_default_dependent_associated_type.rs | 33 +++++++++++++++++++ .../default_ty_param_dependent_defaults.rs | 18 ++++++++++ ...default_ty_param_struct_and_type_alias.rs} | 14 ++++++-- ...meter_default_dependent_associated_type.rs | 23 ------------- ...fault_type_parameter_dependent_defaults.rs | 7 ---- 6 files changed, 67 insertions(+), 34 deletions(-) create mode 100644 src/test/run-pass/default_ty_param_default_dependent_associated_type.rs create mode 100644 src/test/run-pass/default_ty_param_dependent_defaults.rs rename src/test/run-pass/{default_type_parameter_struct_and_type_alias.rs => default_ty_param_struct_and_type_alias.rs} (53%) delete mode 100644 src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs delete mode 100644 src/test/run-pass/default_type_parameter_dependent_defaults.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a93c7ed9161..d93848f408ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1141,7 +1141,11 @@ fn trait_defines_associated_type_named(&self, fn ty_infer(&self, ty_param_def: Option>, span: Span) -> Ty<'tcx> { let default = ty_param_def.and_then(|t| - t.default.map(|ty| type_variable::Default { ty: ty, origin_span: span, definition_span: span })); + t.default.map(|ty| type_variable::Default { + ty: ty, + origin_span: span, + definition_span: span + })); self.infcx().next_ty_var_with_default(default) } diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs new file mode 100644 index 000000000000..fe8c1063c96d --- /dev/null +++ b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs @@ -0,0 +1,33 @@ +// 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. +// +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_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs new file mode 100644 index 000000000000..9322c9ad165a --- /dev/null +++ b/src/test/run-pass/default_ty_param_dependent_defaults.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. +// + +use std::marker::PhantomData; + +struct Foo { data: PhantomData<(T, U)> } + +fn main() { + let foo = Foo { data: PhantomData }; +} diff --git a/src/test/run-pass/default_type_parameter_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs similarity index 53% rename from src/test/run-pass/default_type_parameter_struct_and_type_alias.rs rename to src/test/run-pass/default_ty_param_struct_and_type_alias.rs index d42e65d90fee..0a8543c03b13 100644 --- a/src/test/run-pass/default_type_parameter_struct_and_type_alias.rs +++ b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs @@ -1,7 +1,15 @@ -use std::marker::PhantomData; +// 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. +// -trait TypeEq {} -impl TypeEq for A {} +use std::marker::PhantomData; struct DeterministicHasher; struct RandomHasher; diff --git a/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs b/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs deleted file mode 100644 index 402399f14b93..000000000000 --- a/src/test/run-pass/default_type_parameter_default_dependent_associated_type.rs +++ /dev/null @@ -1,23 +0,0 @@ -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_type_parameter_dependent_defaults.rs b/src/test/run-pass/default_type_parameter_dependent_defaults.rs deleted file mode 100644 index 4f492bed9d4f..000000000000 --- a/src/test/run-pass/default_type_parameter_dependent_defaults.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::marker::PhantomData; - -struct Foo { data: PhantomData<(T, U)> } - -fn main() { - let foo = Foo { data: PhantomData }; -} From ee4392041073795f479365f34d40777eff69c378 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sun, 12 Jul 2015 21:43:13 -0700 Subject: [PATCH 08/18] Rebase fixes --- src/librustc/middle/infer/mod.rs | 12 ++++++------ src/librustc/middle/ty.rs | 8 ++++---- src/librustc_typeck/check/mod.rs | 10 ++++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index d38417143ce0..eaa5b6d58f89 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -73,7 +73,7 @@ pub struct InferCtxt<'a, 'tcx: 'a> { // We instantiate UnificationTable with bounds because the // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. - pub type_variables: RefCell>, + type_variables: RefCell>, // Map from integral variable to the kind of integer it represents int_unification_table: RefCell>, @@ -1366,19 +1366,19 @@ pub fn report_mismatched_types(&self, } pub fn report_conflicting_default_types(&self, - span: Span, - expected: type_variable::Default<'tcx>, - actual: type_variable::Default<'tcx>) { + span: Span, + expected: type_variable::Default<'tcx>, + actual: type_variable::Default<'tcx>) { let trace = TypeTrace { origin: Misc(span), - values: Types(ty::expected_found { + values: Types(ty::ExpectedFound { expected: expected.ty, found: actual.ty }) }; self.report_and_explain_type_error(trace, - &ty::type_err::terr_ty_param_default_mismatch(ty::expected_found { + &TypeError::TyParamDefaultMismatch(ty::ExpectedFound { expected: expected, found: actual })); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 19add679bbfd..4945e0766e75 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2039,7 +2039,7 @@ pub struct ExpectedFound { } // Data structures used in type unification -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub enum TypeError<'tcx> { Mismatch, UnsafetyMismatch(ExpectedFound), @@ -2069,7 +2069,7 @@ pub enum TypeError<'tcx> { ConvergenceMismatch(ExpectedFound), ProjectionNameMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>) + TyParamDefaultMismatch(ExpectedFound>) } /// Bounds suitable for an existentially quantified type parameter @@ -5083,7 +5083,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { values.expected, values.found) }, - terr_ty_param_default_mismatch(ref values) => { + TyParamDefaultMismatch(ref values) => { write!(f, "conflicting type parameter defaults {} and {}", values.expected.ty, values.found.ty) @@ -5445,7 +5445,7 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { using it as a trait object")); } }, - terr_ty_param_default_mismatch(values) => { + TyParamDefaultMismatch(values) => { let expected = values.expected; let found = values.found; self.sess.span_note(sp, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d93848f408ca..c9b10cec44a9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1785,7 +1785,7 @@ fn select_all_obligations_and_apply_defaults(&self) { // it had been solved by previously applying a default. // We take a snapshot for use in error reporting. - let snapshot = self.infcx().type_variables.borrow_mut().snapshot(); + let snapshot = self.infcx().start_snapshot(); for ty in &unbound_tyvars { if self.infcx().type_var_diverges(ty) { @@ -1815,10 +1815,12 @@ fn select_all_obligations_and_apply_defaults(&self) { } } - // There were some errors to report + // There are some errors to report if conflicts.len() > 0 { - self.infcx().type_variables.borrow_mut().rollback_to(snapshot); + self.infcx().rollback_to(snapshot); + // Loop through each conflicting default compute the conflict + // and then report the error. for (conflict, default) in conflicts { let conflicting_default = self.find_conflicting_default( @@ -1836,7 +1838,7 @@ fn select_all_obligations_and_apply_defaults(&self) { default) } } else { - self.infcx().type_variables.borrow_mut().commit(snapshot) + self.infcx().commit_from(snapshot) } } From b75f215e8244ae742ac2e5b3cfd27ab4a761ed9e Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 13 Jul 2015 01:49:13 -0700 Subject: [PATCH 09/18] Remove second transaction --- src/librustc_typeck/check/mod.rs | 124 +++++++++++++++++-------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c9b10cec44a9..42b28dcbc1b5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1784,43 +1784,49 @@ fn select_all_obligations_and_apply_defaults(&self) { // variable would only be in `unbound_tyvars` and have a concrete value if // it had been solved by previously applying a default. - // We take a snapshot for use in error reporting. - let snapshot = self.infcx().start_snapshot(); - - 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(_) => { - conflicts.push((*ty, default)); + // We wrap this in a transaction for error reporting, if we detect a conflict + // we will rollback the inference context to its prior state so we can probe + // for conflicts and correctly report them. + let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { + 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(_) => { + conflicts.push((*ty, default)); + } } } } } } } - } - // There are some errors to report + // If there are conflicts we rollback, otherwise commit + if conflicts.len() > 0 { + Err(()) + } else { + Ok(()) + } + }); + if conflicts.len() > 0 { - self.infcx().rollback_to(snapshot); - - // Loop through each conflicting default compute the conflict - // and then report the error. + // 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( @@ -1832,13 +1838,11 @@ fn select_all_obligations_and_apply_defaults(&self) { definition_span: codemap::DUMMY_SP }); - self.infcx().report_conflicting_default_types( - conflicting_default.origin_span, - conflicting_default, - default) + self.infcx().report_conflicting_default_types( + conflicting_default.origin_span, + conflicting_default, + default) } - } else { - self.infcx().commit_from(snapshot) } } @@ -1856,7 +1860,7 @@ fn find_conflicting_default(&self, -> Option> { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - // Ensure that the conflicting default is applied first + // 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()); @@ -1864,33 +1868,39 @@ fn find_conflicting_default(&self, 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. - 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); + + // We also run this inside snapshot that never commits so we can do error + // reporting for more then one conflict. + //let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { + 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); + } } } } } } } - } + // let result: Result<(), ()> = Err(()); result + //}); return result; } From fbfbdd7d1426d34b94223909eec2c9c009d9c731 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 13 Jul 2015 18:12:18 -0700 Subject: [PATCH 10/18] Correctly subst defaults with the in-scope substs --- src/librustc/middle/infer/mod.rs | 48 ++++++++++------- src/librustc/middle/subst.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 57 +++++++++++++-------- src/librustc_typeck/check/method/mod.rs | 28 ++++++---- src/librustc_typeck/check/method/probe.rs | 15 +++--- src/librustc_typeck/check/mod.rs | 11 ++-- 6 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index eaa5b6d58f89..253f6379d155 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1047,12 +1047,15 @@ pub fn region_vars_for_defs(&self, .collect() } + // We have to take `&mut Substs` in order to provide the correct substitutions for defaults + // along the way, for this reason we don't return them. pub fn type_vars_for_defs(&self, span: Span, - // substs: Substs, - defs: &[ty::TypeParameterDef<'tcx>]) - -> Vec> { + space: subst::ParamSpace, + substs: &mut Substs<'tcx>, + defs: &[ty::TypeParameterDef<'tcx>]) { + // This doesn't work ... fn definition_span<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId) -> Span { let parent = tcx.map.get_parent(def_id.node); debug!("definition_span def_id={:?} parent={:?} node={:?} parent_node={:?}", @@ -1069,24 +1072,21 @@ fn definition_span<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId) -> Span { } } - let mut substs = Substs::empty(); let mut vars = Vec::with_capacity(defs.len()); for def in defs.iter() { - let default = def.default.map(|default| { + let default = def.default.subst_spanned(self.tcx, substs, Some(span)).map(|default| { type_variable::Default { ty: default, origin_span: span, definition_span: definition_span(self.tcx, def.def_id) } }); - //.subst(self.tcx, &substs) + let ty_var = self.next_ty_var_with_default(default); - substs.types.push(subst::ParamSpace::SelfSpace, ty_var); + substs.types.push(space, ty_var); vars.push(ty_var) } - - vars } /// Given a set of generics defined on a type or impl, returns a substitution mapping each @@ -1096,17 +1096,23 @@ pub fn fresh_substs_for_generics(&self, generics: &ty::Generics<'tcx>) -> subst::Substs<'tcx> { - let mut type_params = subst::VecPerParamSpace::empty(); - - for space in subst::ParamSpace::all().iter() { - type_params.replace(*space, - self.type_vars_for_defs(span, generics.types.get_slice(*space))) - } + let type_params = subst::VecPerParamSpace::empty(); let region_params = generics.regions.map( |d| self.next_region_var(EarlyBoundRegion(span, d.name))); - subst::Substs::new(type_params, region_params) + + let mut substs = subst::Substs::new(type_params, region_params); + + for space in subst::ParamSpace::all().iter() { + self.type_vars_for_defs( + span, + *space, + &mut substs, + generics.types.get_slice(*space)); + } + + return substs; } /// Given a set of generics defined on a trait, returns a substitution mapping each output @@ -1124,13 +1130,17 @@ pub fn fresh_substs_for_trait(&self, assert!(generics.regions.len(subst::SelfSpace) == 0); assert!(generics.regions.len(subst::FnSpace) == 0); - let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); - let type_parameters = self.type_vars_for_defs(span, type_parameter_defs); + let type_params = Vec::new(); let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); - subst::Substs::new_trait(type_parameters, regions, self_ty) + let mut substs = subst::Substs::new_trait(type_params, regions, self_ty); + + let type_parameter_defs = generics.types.get_slice(subst::TypeSpace); + self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs); + + return substs; } pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 4e98ef275310..7d8a20c42e36 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -154,7 +154,7 @@ pub fn method_to_trait(self) -> Substs<'tcx> { } impl RegionSubsts { - fn map(self, op: F) -> RegionSubsts where + pub fn map(self, op: F) -> RegionSubsts where F: FnOnce(VecPerParamSpace) -> VecPerParamSpace, { match self { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 488428833ac1..12e14dbcb92f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -84,9 +84,12 @@ fn confirm(&mut self, // Create substitutions for the method's type parameters. let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); - let (method_types, method_regions) = - self.instantiate_method_substs(&pick, supplied_method_types); - let all_substs = rcvr_substs.with_method(method_types, method_regions); + let all_substs = + self.instantiate_method_substs( + &pick, + supplied_method_types, + rcvr_substs); + debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. @@ -302,8 +305,9 @@ fn extract_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R wh fn instantiate_method_substs(&mut self, pick: &probe::Pick<'tcx>, - supplied_method_types: Vec>) - -> (Vec>, Vec) + supplied_method_types: Vec>, + substs: subst::Substs<'tcx>) + -> subst::Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -313,21 +317,6 @@ fn instantiate_method_substs(&mut self, let method_types = method.generics.types.get_slice(subst::FnSpace); let num_method_types = method_types.len(); - let method_types = { - if num_supplied_types == 0 { - self.fcx.infcx().type_vars_for_defs(self.span, method_types) - } else if num_method_types == 0 { - span_err!(self.tcx().sess, self.span, E0035, - "does not take type parameters"); - self.fcx.infcx().type_vars_for_defs(self.span, method_types) - } else if num_supplied_types != num_method_types { - span_err!(self.tcx().sess, self.span, E0036, - "incorrect number of type parameters given for this method"); - vec![self.tcx().types.err; num_method_types] - } else { - supplied_method_types - } - }; // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. @@ -339,7 +328,33 @@ fn instantiate_method_substs(&mut self, pick.item.as_opt_method().unwrap() .generics.regions.get_slice(subst::FnSpace)); - (method_types, method_regions) + let subst::Substs { types, regions } = substs; + let regions = regions.map(|r| r.with_vec(subst::FnSpace, method_regions)); + let mut final_substs = subst::Substs { types: types, regions: regions }; + + if num_supplied_types == 0 { + self.fcx.infcx().type_vars_for_defs( + self.span, + subst::FnSpace, + &mut final_substs, + method_types); + } else if num_method_types == 0 { + span_err!(self.tcx().sess, self.span, E0035, + "does not take type parameters"); + self.fcx.infcx().type_vars_for_defs( + self.span, + subst::FnSpace, + &mut final_substs, + method_types); + } else if num_supplied_types != num_method_types { + span_err!(self.tcx().sess, self.span, E0036, + "incorrect number of type parameters given for this method"); + final_substs.types.replace(subst::FnSpace, vec![self.tcx().types.err; num_method_types]); + } else { + final_substs.types.replace(subst::FnSpace, supplied_method_types); + } + + return final_substs; } fn unify_receivers(&mut self, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 767797e843ca..1bcb7a5ce031 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -169,22 +169,28 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); let expected_number_of_input_types = type_parameter_defs.len(); - let input_types = match opt_input_types { - Some(input_types) => { - assert_eq!(expected_number_of_input_types, input_types.len()); - input_types - } - - None => { - fcx.inh.infcx.type_vars_for_defs(span, type_parameter_defs) - } - }; assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0); assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` - let substs = subst::Substs::new_trait(input_types, Vec::new(), self_ty); + let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty); + + match opt_input_types { + Some(input_types) => { + assert_eq!(expected_number_of_input_types, input_types.len()); + substs.types.replace(subst::ParamSpace::TypeSpace, input_types); + } + + None => { + fcx.inh.infcx.type_vars_for_defs( + span, + subst::ParamSpace::TypeSpace, + &mut substs, + type_parameter_defs); + } + } + let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)); // Construct an obligation diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b190e7a7a483..44d769a799f1 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1200,16 +1200,12 @@ fn xform_method_self_ty(&self, return impl_ty; } - let placeholder; + let mut placeholder; let mut substs = substs; if !method.generics.types.is_empty_in(subst::FnSpace) || !method.generics.regions.is_empty_in(subst::FnSpace) { - let method_types = - self.infcx().type_vars_for_defs(self.span, - method.generics.types.get_slice(subst::FnSpace)); - // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. let method_regions = @@ -1218,7 +1214,14 @@ fn xform_method_self_ty(&self, .map(|_| ty::ReStatic) .collect(); - placeholder = (*substs).clone().with_method(method_types, method_regions); + placeholder = (*substs).clone().with_method(Vec::new(), method_regions); + + self.infcx().type_vars_for_defs( + self.span, + subst::FnSpace, + &mut placeholder, + method.generics.types.get_slice(subst::FnSpace)); + substs = &placeholder; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 42b28dcbc1b5..fd99d1ddba9c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2616,8 +2616,10 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); - let tps = fcx.inh.infcx.type_vars_for_defs(span, tps); - let substs = subst::Substs::new_type(tps, rps); + let mut substs = subst::Substs::new( + VecPerParamSpace::empty(), + VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + fcx.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } @@ -4611,6 +4613,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } } + if let Some(self_ty) = opt_self_ty { if type_defs.len(subst::SelfSpace) == 1 { substs.types.push(subst::SelfSpace, self_ty); @@ -4623,7 +4626,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - for &space in &ParamSpace::all() { + for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { adjust_type_parameters(fcx, span, space, type_defs, require_type_space, &mut substs); assert_eq!(substs.types.len(space), type_defs.len(space)); @@ -4836,7 +4839,7 @@ fn adjust_type_parameters<'a, 'tcx>( // Nothing specified at all: supply inference variables for // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { - substs.types.replace(space, fcx.infcx().type_vars_for_defs(span, &desired[..])); + fcx.infcx().type_vars_for_defs(span, space, substs, &desired[..]); return; } From ed3fbba797b0a68b797469f49f878307cc64c993 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 16 Jul 2015 11:26:02 -0700 Subject: [PATCH 11/18] Fix error message spans --- src/librustc/ast_map/mod.rs | 21 ++++- src/librustc/metadata/tydecode.rs | 2 + src/librustc/metadata/tyencode.rs | 4 +- src/librustc/middle/infer/mod.rs | 28 ++----- src/librustc/middle/ty.rs | 9 +- src/librustc/middle/ty_fold.rs | 1 + src/librustc_trans/trans/monomorphize.rs | 1 + src/librustc_typeck/astconv.rs | 22 +++-- src/librustc_typeck/check/mod.rs | 84 +++++++++++-------- src/librustc_typeck/collect.rs | 9 +- src/rust-installer | 2 +- .../default_ty_param_dependent_defaults.rs | 4 +- 12 files changed, 110 insertions(+), 77 deletions(-) diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index bdb481bc9385..10552791d8b8 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -119,6 +119,7 @@ pub enum Node<'ast> { NodeStructCtor(&'ast StructDef), NodeLifetime(&'ast Lifetime), + NodeTyParam(&'ast TyParam) } /// Represents an entry and its parent NodeID. @@ -142,6 +143,7 @@ enum MapEntry<'ast> { EntryBlock(NodeId, &'ast Block), EntryStructCtor(NodeId, &'ast StructDef), EntryLifetime(NodeId, &'ast Lifetime), + EntryTyParam(NodeId, &'ast TyParam), /// Roots for node trees. RootCrate, @@ -175,7 +177,8 @@ fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { NodePat(n) => EntryPat(p, n), NodeBlock(n) => EntryBlock(p, n), NodeStructCtor(n) => EntryStructCtor(p, n), - NodeLifetime(n) => EntryLifetime(p, n) + NodeLifetime(n) => EntryLifetime(p, n), + NodeTyParam(n) => EntryTyParam(p, n), } } @@ -194,6 +197,7 @@ fn parent_node(self) -> Option { EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, + EntryTyParam(id, _) => id, _ => return None }) } @@ -213,6 +217,7 @@ fn to_node(self) -> Option> { EntryBlock(_, n) => NodeBlock(n), EntryStructCtor(_, n) => NodeStructCtor(n), EntryLifetime(_, n) => NodeLifetime(n), + EntryTyParam(_, n) => NodeTyParam(n), _ => return None }) } @@ -573,6 +578,7 @@ pub fn opt_span(&self, id: NodeId) -> Option { Some(NodePat(pat)) => pat.span, Some(NodeBlock(block)) => block.span, Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, + Some(NodeTyParam(ty_param)) => ty_param.span, _ => return None, }; Some(sp) @@ -815,6 +821,14 @@ fn visit_item(&mut self, i: &'ast Item) { self.parent_node = parent_node; } + fn visit_generics(&mut self, generics: &'ast Generics) { + for ty_param in generics.ty_params.iter() { + self.insert(ty_param.id, NodeTyParam(ty_param)); + } + + visit::walk_generics(self, generics); + } + fn visit_trait_item(&mut self, ti: &'ast TraitItem) { let parent_node = self.parent_node; self.parent_node = ti.id; @@ -1015,7 +1029,7 @@ fn print_node(&mut self, node: &Node) -> io::Result<()> { NodePat(a) => self.print_pat(&*a), NodeBlock(a) => self.print_block(&*a), NodeLifetime(a) => self.print_lifetime(&*a), - + NodeTyParam(_) => panic!("cannot print TyParam"), // these cases do not carry enough information in the // ast_map to reconstruct their full structure for pretty // printing. @@ -1123,6 +1137,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { format!("lifetime {}{}", pprust::lifetime_to_string(&**l), id_str) } + Some(NodeTyParam(ref ty_param)) => { + format!("typaram {:?}{}", ty_param, id_str) + } None => { format!("unknown node{}", id_str) } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 72e1525b506d..54c55d76a827 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -833,6 +833,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) assert_eq!(next(st), '|'); let index = parse_u32(st); assert_eq!(next(st), '|'); + let default_def_id = parse_def_(st, NominalType, conv); let default = parse_opt(st, |st| parse_ty_(st, conv)); let object_lifetime_default = parse_object_lifetime_default(st, conv); @@ -841,6 +842,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) def_id: def_id, space: space, index: index, + default_def_id: default_def_id, default: default, object_lifetime_default: object_lifetime_default, } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index c77e96f16488..597401daccfd 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -409,9 +409,9 @@ pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder, pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { - mywrite!(w, "{}:{}|{}|{}|", + mywrite!(w, "{}:{}|{}|{}|{}|", token::get_name(v.name), (cx.ds)(v.def_id), - v.space.to_uint(), v.index); + v.space.to_uint(), v.index, (cx.ds)(v.default_def_id)); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_object_lifetime_default(w, cx, v.object_lifetime_default); } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 253f6379d155..d10dd7073532 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -40,7 +40,6 @@ use syntax::codemap::{Span, DUMMY_SP}; use util::nodemap::{FnvHashMap, NodeMap}; -use ast_map; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::error_reporting::ErrorReporting; @@ -658,6 +657,9 @@ pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { /// must be attached to the variable when created, if it is created /// without a default, this will return None. /// + /// 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> { @@ -1055,31 +1057,15 @@ pub fn type_vars_for_defs(&self, substs: &mut Substs<'tcx>, defs: &[ty::TypeParameterDef<'tcx>]) { - // This doesn't work ... - fn definition_span<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId) -> Span { - let parent = tcx.map.get_parent(def_id.node); - debug!("definition_span def_id={:?} parent={:?} node={:?} parent_node={:?}", - def_id, parent, tcx.map.find(def_id.node), tcx.map.find(parent)); - match tcx.map.find(parent) { - None => DUMMY_SP, - Some(ref node) => match *node { - ast_map::NodeItem(ref item) => item.span, - ast_map::NodeForeignItem(ref item) => item.span, - ast_map::NodeTraitItem(ref item) => item.span, - ast_map::NodeImplItem(ref item) => item.span, - _ => DUMMY_SP - } - } - } - let mut vars = Vec::with_capacity(defs.len()); for def in defs.iter() { - let default = def.default.subst_spanned(self.tcx, substs, Some(span)).map(|default| { + let default = def.default.map(|default| { + let definition_span = self.tcx.map.opt_span(def.def_id.node); type_variable::Default { - ty: default, + ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, - definition_span: definition_span(self.tcx, def.def_id) + definition_span: definition_span.unwrap_or(DUMMY_SP) } }); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4945e0766e75..a4f714b3bf9c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -115,8 +115,6 @@ pub struct Field<'tcx> { pub mt: TypeAndMut<'tcx> } - - // Enum information #[derive(Clone)] pub struct VariantInfo<'tcx> { @@ -2282,6 +2280,7 @@ pub struct TypeParameterDef<'tcx> { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: u32, + pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, pub object_lifetime_default: ObjectLifetimeDefault, } @@ -5084,7 +5083,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { values.found) }, TyParamDefaultMismatch(ref values) => { - write!(f, "conflicting type parameter defaults {} and {}", + write!(f, "conflicting type parameter defaults `{}` and `{}`", values.expected.ty, values.found.ty) } @@ -5453,11 +5452,11 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { expected.ty, found.ty)); self.sess.span_note(expected.definition_span, - &format!("...a default was defined")); + &format!("a default was defined here...")); self.sess.span_note(expected.origin_span, &format!("...that was applied to an unconstrained type variable here")); self.sess.span_note(found.definition_span, - &format!("...a second default was defined")); + &format!("a second default was defined here...")); self.sess.span_note(found.origin_span, &format!("...that also applies to the same type variable here")); } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index b6bb82ad7b15..0c694926ba4b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -340,6 +340,7 @@ fn fold_with>(&self, folder: &mut F) -> ty::TypeParameterDef space: self.space, index: self.index, default: self.default.fold_with(folder), + default_def_id: self.default_def_id, object_lifetime_default: self.object_lifetime_default.fold_with(folder), } } diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 217181da1421..31e4b9c48e20 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -266,6 +266,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Ugh -- but this ensures any new variants won't be forgotten ast_map::NodeForeignItem(..) | ast_map::NodeLifetime(..) | + ast_map::NodeTyParam(..) | ast_map::NodeExpr(..) | ast_map::NodeStmt(..) | ast_map::NodeArg(..) | diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3925f4e751c2..120cfcbca374 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use middle::implicator::object_region_bounds; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; -use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; use middle::traits; use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags}; use middle::ty_fold; @@ -111,7 +111,11 @@ fn get_free_substs(&self) -> Option<&Substs<'tcx>> { } /// What type should we use when a type is omitted? - fn ty_infer(&self, default: Option>, span: Span) -> Ty<'tcx>; + fn ty_infer(&self, + param_and_substs: Option>, + substs: Option<&mut Substs<'tcx>>, + space: Option, + span: Span) -> Ty<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -403,7 +407,11 @@ fn create_substs_for_ast_path<'tcx>( // they were optional (e.g. paths inside expressions). let mut type_substs = if param_mode == PathParamMode::Optional && types_provided.is_empty() { - ty_param_defs.iter().map(|p| this.ty_infer(Some(p.clone()), span)).collect() + let mut substs = region_substs.clone(); + ty_param_defs + .iter() + .map(|p| this.ty_infer(Some(p.clone()), Some(&mut substs), Some(TypeSpace), span)) + .collect() } else { types_provided }; @@ -1661,7 +1669,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, // values in a ExprClosure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. - this.ty_infer(None, ast_ty.span) + this.ty_infer(None, None, None, ast_ty.span) } }; @@ -1677,7 +1685,7 @@ pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, { match a.ty.node { ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), - ast::TyInfer => this.ty_infer(None, a.ty.span), + ast::TyInfer => this.ty_infer(None, None, None, a.ty.span), _ => ast_ty_to_ty(this, rscope, &*a.ty), } } @@ -1796,7 +1804,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, let output_ty = match decl.output { ast::Return(ref output) if output.node == ast::TyInfer => - ty::FnConverging(this.ty_infer(None, output.span)), + ty::FnConverging(this.ty_infer(None, None, None, output.span)), ast::Return(ref output) => ty::FnConverging(convert_ty_with_lifetime_elision(this, implied_output_region, @@ -1936,7 +1944,7 @@ pub fn ty_of_closure<'tcx>( _ if is_infer && expected_ret_ty.is_some() => expected_ret_ty.unwrap(), _ if is_infer => - ty::FnConverging(this.ty_infer(None, decl.output.span())), + ty::FnConverging(this.ty_infer(None, None, None, decl.output.span())), ast::Return(ref output) => ty::FnConverging(ast_ty_to_ty(this, &rb, &**output)), ast::DefaultReturn(..) => unreachable!(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd99d1ddba9c..76886fc1275b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1139,14 +1139,31 @@ fn trait_defines_associated_type_named(&self, trait_def.associated_type_names.contains(&assoc_name) } - fn ty_infer(&self, ty_param_def: Option>, span: Span) -> Ty<'tcx> { - let default = ty_param_def.and_then(|t| - t.default.map(|ty| type_variable::Default { - ty: ty, + 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| { + let definition_span = self.tcx() + .map + .opt_span(def.def_id.node); + + def.default.map(|ty| type_variable::Default { + ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), origin_span: span, - definition_span: span - })); - self.infcx().next_ty_var_with_default(default) + definition_span: definition_span.unwrap_or(codemap::DUMMY_SP) + }) + }); + + 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 projected_ty_from_poly_trait_ref(&self, @@ -1829,10 +1846,8 @@ fn select_all_obligations_and_apply_defaults(&self) { // 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 { + 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, definition_span: codemap::DUMMY_SP @@ -1871,36 +1886,33 @@ fn find_conflicting_default(&self, // We also run this inside snapshot that never commits so we can do error // reporting for more then one conflict. - //let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { - 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 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); } } } } } } - // let result: Result<(), ()> = Err(()); result - //}); + } return result; } @@ -4613,7 +4625,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } } - if let Some(self_ty) = opt_self_ty { if type_defs.len(subst::SelfSpace) == 1 { substs.types.push(subst::SelfSpace, self_ty); @@ -4839,6 +4850,7 @@ fn adjust_type_parameters<'a, 'tcx>( // Nothing specified at all: supply inference variables for // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { + substs.types.replace(space, Vec::new()); fcx.infcx().type_vars_for_defs(span, space, substs, &desired[..]); return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8b38c58ce7a1..6bff90825f32 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,11 @@ fn trait_defines_associated_type_named(&self, } } - fn ty_infer(&self, _default: Option>, span: Span) -> Ty<'tcx> { + fn ty_infer(&self, + _ty_param_def: Option>, + _substs: Option<&mut Substs<'tcx>>, + _space: Option, + span: Span) -> Ty<'tcx> { span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); self.tcx().types.err @@ -1648,6 +1652,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, index: 0, name: special_idents::type_self.name, def_id: local_def(param_id), + default_def_id: local_def(param_id), default: None, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, }; @@ -1921,6 +1926,8 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, index: index, name: param.ident.name, def_id: local_def(param.id), + // what do I return? should this be an option as well + default_def_id: local_def(param.default.as_ref().map(|d| d.id).unwrap_or(param.id)), default: default, object_lifetime_default: object_lifetime_default, }; diff --git a/src/rust-installer b/src/rust-installer index 8e4f8ea58150..c37d3747da75 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit 8e4f8ea581502a2edc8177a040300e05ff7f91e3 +Subproject commit c37d3747da75c280237dc2d6b925078e69555499 diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs index 9322c9ad165a..eba86415af4c 100644 --- a/src/test/run-pass/default_ty_param_dependent_defaults.rs +++ b/src/test/run-pass/default_ty_param_dependent_defaults.rs @@ -11,8 +11,8 @@ use std::marker::PhantomData; -struct Foo { data: PhantomData<(T, U)> } +struct Foo { t: T, data: PhantomData } fn main() { - let foo = Foo { data: PhantomData }; + let foo = Foo { t: 'a', data: PhantomData }; } From 99a12933fb83b1df7975257c323eb414abeb0b16 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 20 Jul 2015 12:39:34 -0700 Subject: [PATCH 12/18] Rework cross crate error messages --- src/librustc/lib.rs | 1 + src/librustc/middle/infer/mod.rs | 3 +- src/librustc/middle/infer/type_variable.rs | 3 +- src/librustc/middle/ty.rs | 49 ++++++++++++++++++---- src/librustc_typeck/check/mod.rs | 8 +--- src/librustc_typeck/collect.rs | 8 +++- 6 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 7d50e6f6917c..fb11aaed6195 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -56,6 +56,7 @@ #![feature(slice_splits)] #![feature(slice_patterns)] #![feature(slice_position_elem)] +#![feature(slice_concat_ext)] #![feature(staged_api)] #![feature(str_char)] #![feature(str_match_indices)] diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index d10dd7073532..f63154af7242 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1061,11 +1061,10 @@ pub fn type_vars_for_defs(&self, for def in defs.iter() { let default = def.default.map(|default| { - let definition_span = self.tcx.map.opt_span(def.def_id.node); type_variable::Default { ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, - definition_span: definition_span.unwrap_or(DUMMY_SP) + def_id: def.default_def_id } }); diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 8707306a149c..3684651f85be 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -12,6 +12,7 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use middle::ty::{self, Ty}; +use syntax::ast::DefId; use syntax::codemap::Span; use std::cmp::min; @@ -45,7 +46,7 @@ pub struct Default<'tcx> { /// The span where the default was incurred pub origin_span: Span, /// The definition that the default originates from - pub definition_span: Span + pub def_id: DefId } pub struct Snapshot { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a4f714b3bf9c..3bda1730e63b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -79,6 +79,7 @@ use std::rc::Rc; use std::vec::IntoIter; use collections::enum_set::{self, EnumSet, CLike}; +use collections::slice::SliceConcatExt; use std::collections::{HashMap, HashSet}; use syntax::abi; use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE}; @@ -5448,17 +5449,47 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { let expected = values.expected; let found = values.found; self.sess.span_note(sp, - &format!("conflicting type parameter defaults {} and {}", - expected.ty, - found.ty)); - self.sess.span_note(expected.definition_span, - &format!("a default was defined here...")); + &format!("conflicting type parameter defaults `{}` and `{}`", + expected.ty, + found.ty)); + + match (expected.def_id.krate == ast::LOCAL_CRATE, self.map.opt_span(expected.def_id.node)) { + (true, Some(span)) => { + self.sess.span_note(span, + &format!("a default was defined here...")); + } + (_, _) => { + let elems = csearch::get_item_path(self, expected.def_id) + .into_iter() + .map(|p| p.to_string()) + .collect::>(); + self.sess.note( + &format!("a default is defined on `{}`", + elems.join("::"))); + } + } + self.sess.span_note(expected.origin_span, - &format!("...that was applied to an unconstrained type variable here")); - self.sess.span_note(found.definition_span, - &format!("a second default was defined here...")); + &format!("...that was applied to an unconstrained type variable here")); + + match (found.def_id.krate == ast::LOCAL_CRATE, self.map.opt_span(found.def_id.node)) { + (true, Some(span)) => { + self.sess.span_note(span, + &format!("a second default was defined here...")); + } + (_, _) => { + let elems = csearch::get_item_path(self, found.def_id) + .into_iter() + .map(|p| p.to_string()) + .collect::>(); + + self.sess.note( + &format!("a second default is defined on `{}`", elems.join(" "))); + } + } + self.sess.span_note(found.origin_span, - &format!("...that also applies to the same type variable here")); + &format!("...that also applies to the same type variable here")); } _ => {} } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 76886fc1275b..fd4cf6f28df9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1146,14 +1146,10 @@ fn ty_infer(&self, span: Span) -> Ty<'tcx> { // Grab the default doing subsitution let default = ty_param_def.and_then(|def| { - let definition_span = self.tcx() - .map - .opt_span(def.def_id.node); - def.default.map(|ty| type_variable::Default { ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), origin_span: span, - definition_span: definition_span.unwrap_or(codemap::DUMMY_SP) + def_id: def.default_def_id }) }); @@ -1850,7 +1846,7 @@ fn select_all_obligations_and_apply_defaults(&self) { .unwrap_or(type_variable::Default { ty: self.infcx().next_ty_var(), origin_span: codemap::DUMMY_SP, - definition_span: codemap::DUMMY_SP + def_id: local_def(0) // what do I put here? }); self.infcx().report_conflicting_default_types( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6bff90825f32..d31a29ecc0e2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1647,12 +1647,14 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // the node id for the Self type parameter. let param_id = trait_id; + let parent = ccx.tcx.map.get_parent(param_id); + let def = ty::TypeParameterDef { space: SelfSpace, index: 0, name: special_idents::type_self.name, def_id: local_def(param_id), - default_def_id: local_def(param_id), + default_def_id: local_def(parent), default: None, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, }; @@ -1921,13 +1923,15 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, compute_object_lifetime_default(ccx, param.id, ¶m.bounds, &ast_generics.where_clause); + let parent = tcx.map.get_parent(param.id); + let def = ty::TypeParameterDef { space: space, index: index, name: param.ident.name, def_id: local_def(param.id), // what do I return? should this be an option as well - default_def_id: local_def(param.default.as_ref().map(|d| d.id).unwrap_or(param.id)), + default_def_id: local_def(parent), default: default, object_lifetime_default: object_lifetime_default, }; From 77165415b7b4aecff6b5959647f675ddf34c222a Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 20 Jul 2015 12:48:24 -0700 Subject: [PATCH 13/18] Address tidy --- src/librustc/middle/ty.rs | 18 +++++++++++------- src/librustc_typeck/check/method/confirm.rs | 4 +++- src/librustc_typeck/check/method/mod.rs | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3bda1730e63b..ea5ca8acb094 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5453,7 +5453,8 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { expected.ty, found.ty)); - match (expected.def_id.krate == ast::LOCAL_CRATE, self.map.opt_span(expected.def_id.node)) { + match (expected.def_id.krate == ast::LOCAL_CRATE, + self.map.opt_span(expected.def_id.node)) { (true, Some(span)) => { self.sess.span_note(span, &format!("a default was defined here...")); @@ -5464,15 +5465,17 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { .map(|p| p.to_string()) .collect::>(); self.sess.note( - &format!("a default is defined on `{}`", + &format!("a default is defined on `{}`", elems.join("::"))); } } - self.sess.span_note(expected.origin_span, - &format!("...that was applied to an unconstrained type variable here")); + self.sess.span_note( + expected.origin_span, + &format!("...that was applied to an unconstrained type variable here")); - match (found.def_id.krate == ast::LOCAL_CRATE, self.map.opt_span(found.def_id.node)) { + match (found.def_id.krate == ast::LOCAL_CRATE, + self.map.opt_span(found.def_id.node)) { (true, Some(span)) => { self.sess.span_note(span, &format!("a second default was defined here...")); @@ -5488,8 +5491,9 @@ pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { } } - self.sess.span_note(found.origin_span, - &format!("...that also applies to the same type variable here")); + self.sess.span_note( + found.origin_span, + &format!("...that also applies to the same type variable here")); } _ => {} } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 12e14dbcb92f..e9869e2a00e5 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -349,7 +349,9 @@ fn instantiate_method_substs(&mut self, } else if num_supplied_types != num_method_types { span_err!(self.tcx().sess, self.span, E0036, "incorrect number of type parameters given for this method"); - final_substs.types.replace(subst::FnSpace, vec![self.tcx().types.err; num_method_types]); + final_substs.types.replace( + subst::FnSpace, + vec![self.tcx().types.err; num_method_types]); } else { final_substs.types.replace(subst::FnSpace, supplied_method_types); } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 1bcb7a5ce031..e3f55cca9ee5 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -190,7 +190,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, type_parameter_defs); } } - + let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)); // Construct an obligation From d732f7323b07cd62bf2a9f7e4785407d6f82ee63 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 20 Jul 2015 12:49:03 -0700 Subject: [PATCH 14/18] Add cross-crate error message tests --- .../default_ty_param_cross_crate_crate.rs | 19 ++++++++++++++++++ .../default_ty_param_conflict_cross_crate.rs | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/auxiliary/default_ty_param_cross_crate_crate.rs create mode 100644 src/test/compile-fail/default_ty_param_conflict_cross_crate.rs diff --git a/src/test/auxiliary/default_ty_param_cross_crate_crate.rs b/src/test/auxiliary/default_ty_param_cross_crate_crate.rs new file mode 100644 index 000000000000..270cfdcb7f65 --- /dev/null +++ b/src/test/auxiliary/default_ty_param_cross_crate_crate.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. + +#![crate_type = "lib"] +#![crate_name = "default_param_test"] + +use std::marker::PhantomData; + +pub struct Foo(PhantomData<(A, B)>); + +pub fn bleh() -> Foo { Foo(PhantomData) } + diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs new file mode 100644 index 000000000000..bc79d3713e55 --- /dev/null +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -0,0 +1,20 @@ +// 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. + +use std::fmt::Debug; +use std::collections::HashMap; + +fn foo(x: HashMap) -> HashMap { x } +fn bar(x: HashMap) {} + +fn main() { + let x: HashMap = foo(panic!()); + bar(x); +} From 9da04b2bd1fdcd147f6d0ebcdbb5108f63bf7576 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 21 Jul 2015 14:52:21 -0700 Subject: [PATCH 15/18] Make default error reporting deterministic --- src/librustc_typeck/check/mod.rs | 19 ++++++++++++++++--- src/librustc_typeck/collect.rs | 1 - .../compile-fail/default_ty_param_conflict.rs | 7 +++++++ .../default_ty_param_conflict_cross_crate.rs | 18 ++++++++++++------ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd4cf6f28df9..95e916f1a0d1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1800,6 +1800,8 @@ fn select_all_obligations_and_apply_defaults(&self) { // We wrap this in a transaction for error reporting, if we detect a conflict // we will rollback the inference context to its prior state so we can probe // for conflicts and correctly report them. + + let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { for ty in &unbound_tyvars { if self.infcx().type_var_diverges(ty) { @@ -1849,10 +1851,21 @@ fn select_all_obligations_and_apply_defaults(&self) { def_id: local_def(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( - conflicting_default.origin_span, - conflicting_default, - default) + first_default.origin_span, + first_default, + second_default) } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d31a29ecc0e2..236a1e690e88 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1930,7 +1930,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, index: index, name: param.ident.name, def_id: local_def(param.id), - // what do I return? should this be an option as well default_def_id: local_def(parent), default: default, object_lifetime_default: object_lifetime_default, diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 900945da1136..42de545f9d05 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -12,12 +12,19 @@ // 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_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index bc79d3713e55..804a864e074e 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -7,14 +7,20 @@ // , 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 +extern crate default_param_test; -use std::fmt::Debug; -use std::collections::HashMap; +use default_param_test::{Foo, bleh}; -fn foo(x: HashMap) -> HashMap { x } -fn bar(x: HashMap) {} +fn meh(x: Foo) {} +//~^ NOTE: a default was defined here... fn main() { - let x: HashMap = foo(panic!()); - bar(x); + 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` } From 55621b6199dcef7090bdbb660a5ab9354b3effa6 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Fri, 24 Jul 2015 13:39:11 -0700 Subject: [PATCH 16/18] Add feature gate --- src/doc/reference.md | 2 + src/librustc_typeck/check/mod.rs | 40 ++++++++++++++++++- src/libsyntax/feature_gate.rs | 9 ++++- .../compile-fail/default_ty_param_conflict.rs | 2 + .../default_ty_param_conflict_cross_crate.rs | 3 ++ ...param_default_dependent_associated_type.rs | 3 ++ .../default_ty_param_dependent_defaults.rs | 1 + .../default_ty_param_method_call_test.rs | 2 + src/test/run-pass/default_ty_param_struct.rs | 2 + .../default_ty_param_struct_and_type_alias.rs | 2 + .../run-pass/default_ty_param_trait_impl.rs | 8 ++-- .../default_ty_param_trait_impl_simple.rs | 8 ++-- .../run-pass/default_ty_param_type_alias.rs | 2 + 13 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 26fd2fd8d20d..59721edda707 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2368,6 +2368,8 @@ The currently implemented features of the reference compiler are: internally without imposing on callers (i.e. making them behave like function calls in terms of encapsulation). +* - `default_type_parameter_fallback` - Allows type parameter defaults to + influence type inference. If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 95e916f1a0d1..eb0ef30d396c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1709,10 +1709,47 @@ fn check_casts(&self) { } } + /// Apply "fallbacks" to some types + /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. + pub fn default_type_parameters(&self) { + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + for ty in &self.infcx().unsolved_variables() { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if self.infcx().type_var_diverges(resolved) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + 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 => { } + } + } + } + } + fn select_all_obligations_and_apply_defaults(&self) { + if self.tcx().sess.features.borrow().default_type_parameter_fallback { + self.new_select_all_obligations_and_apply_defaults(); + } else { + self.old_select_all_obligations_and_apply_defaults(); + } + } + + // Implements old type inference fallback algorithm + fn old_select_all_obligations_and_apply_defaults(&self) { + self.select_obligations_where_possible(); + self.default_type_parameters(); + self.select_obligations_where_possible(); + } + + fn new_select_all_obligations_and_apply_defaults(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - // For the time being this errs on the side of being memory wasteful but provides better + // 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(); @@ -1934,6 +1971,7 @@ fn select_all_obligations_or_error(&self) { assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); match fulfillment_cx.select_all_or_error(self.infcx()) { Ok(()) => { } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ee895fb1a96e..af7e4a6855f7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -163,6 +163,8 @@ // Allows the definition recursive static items. ("static_recursion", "1.3.0", Active), +// Allows default type parameters to influence type inference. + ("default_type_parameter_fallback", "1.3.0", Active) ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -341,7 +343,8 @@ pub struct Features { /// #![feature] attrs for non-language (library) features pub declared_lib_features: Vec<(InternedString, Span)>, pub const_fn: bool, - pub static_recursion: bool + pub static_recursion: bool, + pub default_type_parameter_fallback: bool, } impl Features { @@ -366,7 +369,8 @@ pub fn new() -> Features { declared_stable_lang_features: Vec::new(), declared_lib_features: Vec::new(), const_fn: false, - static_recursion: false + static_recursion: false, + default_type_parameter_fallback: false, } } } @@ -865,6 +869,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, declared_lib_features: unknown_features, const_fn: cx.has_feature("const_fn"), static_recursion: cx.has_feature("static_recursion") + default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), } } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 42de545f9d05..48c5cd1ff770 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -8,6 +8,8 @@ // 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 diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index 804a864e074e..4d60724372ad 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -9,6 +9,9 @@ // 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}; diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs index fe8c1063c96d..8fc2c2e6bce7 100644 --- a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs +++ b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs @@ -8,6 +8,9 @@ // 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 { diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs index eba86415af4c..ac833d0f5474 100644 --- a/src/test/run-pass/default_ty_param_dependent_defaults.rs +++ b/src/test/run-pass/default_ty_param_dependent_defaults.rs @@ -9,6 +9,7 @@ // except according to those terms. // +#![feature(default_type_parameter_fallback)] use std::marker::PhantomData; struct Foo { t: T, data: PhantomData } diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs index 35f0fcab0017..e8d93092ec53 100644 --- a/src/test/run-pass/default_ty_param_method_call_test.rs +++ b/src/test/run-pass/default_ty_param_method_call_test.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + struct Foo; impl Foo { diff --git a/src/test/run-pass/default_ty_param_struct.rs b/src/test/run-pass/default_ty_param_struct.rs index b94b759fd113..d9ac51fc23b0 100644 --- a/src/test/run-pass/default_ty_param_struct.rs +++ b/src/test/run-pass/default_ty_param_struct.rs @@ -8,6 +8,8 @@ // 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 { diff --git a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs index 0a8543c03b13..6e3e60a02e5e 100644 --- a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs +++ b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs @@ -9,6 +9,8 @@ // except according to those terms. // +#![feature(default_type_parameter_fallback)] + use std::marker::PhantomData; struct DeterministicHasher; diff --git a/src/test/run-pass/default_ty_param_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs index fbceb60b9a8e..c67d3a49aff3 100644 --- a/src/test/run-pass/default_ty_param_trait_impl.rs +++ b/src/test/run-pass/default_ty_param_trait_impl.rs @@ -8,14 +8,16 @@ // 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 1 -impl Bar for usize { } // Impl 2 +impl Foo for Vec {} +impl Bar for usize {} -fn takes_foo(f: F) { } +fn takes_foo(f: F) {} fn main() { let x = Vec::new(); // x: Vec<$0> diff --git a/src/test/run-pass/default_ty_param_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs index 00d7ccf43bec..067ad524922c 100644 --- a/src/test/run-pass/default_ty_param_trait_impl_simple.rs +++ b/src/test/run-pass/default_ty_param_trait_impl_simple.rs @@ -8,17 +8,17 @@ // 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 1 +} -impl Bar for usize { } // Impl 2 - -// fn takes_foo(f: F) { } +impl Bar for usize {} fn main() { let x = Vec::new(); // x: Vec<$0> diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs index c3e44e55beeb..1b4747406d0c 100644 --- a/src/test/run-pass/default_ty_param_type_alias.rs +++ b/src/test/run-pass/default_ty_param_type_alias.rs @@ -8,6 +8,8 @@ // 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; From 8ea9672f825118c11dcc3586bbc69a0d7e75b49b Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sat, 25 Jul 2015 19:27:15 -0700 Subject: [PATCH 17/18] Address nit --- src/librustc_typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eb0ef30d396c..85df5d67ff6e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1711,7 +1711,7 @@ fn check_casts(&self) { /// Apply "fallbacks" to some types /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. - pub fn default_type_parameters(&self) { + fn default_type_parameters(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; for ty in &self.infcx().unsolved_variables() { let resolved = self.infcx().resolve_type_vars_if_possible(ty); From 5ad36cb887dadc7fe564cfed1ccac52d009a59c8 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sat, 25 Jul 2015 21:22:38 -0700 Subject: [PATCH 18/18] Add omitted trailing comma --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index af7e4a6855f7..c3338f02ee43 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -868,7 +868,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, declared_stable_lang_features: accepted_features, declared_lib_features: unknown_features, const_fn: cx.has_feature("const_fn"), - static_recursion: cx.has_feature("static_recursion") + static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), } }