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 c6df1c395ccec..5339464503b3e 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 6f1de3ee63597..ebecb0898b4df 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -195,6 +195,15 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 84ca7cd437a96..a08c5e1f73fa2 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 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { 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 @@ impl<'tcx> ctxt<'tcx> { &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 a899bbacc0301..7582b7ff61d88 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -339,5 +339,11 @@ impl<'tcx,K,V> UnificationTable 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 a8c56b2660ce0..e3b9b990cb9e5 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -309,15 +309,17 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // 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 a74c004389b4d..2ca5a88fb06dd 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 a960123efc6b8..88bd000cfdd65 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1207,8 +1207,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { !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 082dafc72bc6f..e226b0b21a1e3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -108,6 +108,7 @@ use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; 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 @@ impl<'a, 'tcx> FnCtxt<'a, '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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'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 0000000000000..900945da1136b --- /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 0000000000000..c3e44e55beeb2 --- /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 0000000000000..35f0fcab00175 --- /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 0000000000000..b94b759fd113f --- /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 0000000000000..fbceb60b9a8e7 --- /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 0000000000000..00d7ccf43becc --- /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 5339464503b3e..59ca795e5f751 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1328,9 +1328,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) }; - 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 c448af2288a65..5ed1da2fedebc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -111,7 +111,7 @@ pub trait AstConv<'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 e226b0b21a1e3..ae2b3448e01d3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1138,8 +1138,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { 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 5a6519cb4b7a2..695991a97f061 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } } - 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 59ca795e5f751..db6e0ad1d4a83 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// Returns a type variable's default fallback if any exists. A default + /// must be attached to the variable when created, if it is created + /// without a default, this will return None. + /// + /// 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 ebecb0898b4df..6ba289d3665aa 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { }; 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { } 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 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { 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 ae2b3448e01d3..f6a4dbca291bb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,6 +87,7 @@ use fmt_macros::{Parser, Piece, Position}; 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 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 0000000000000..402399f14b936 --- /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 0000000000000..4f492bed9d4f2 --- /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 0000000000000..d42e65d90fee2 --- /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 6ba289d3665aa..fa7cd143e3b21 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 8d66ffac5d17c..fbf19a10d93bf 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -893,8 +893,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { 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 db6e0ad1d4a83..d38417143ce06 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -40,6 +40,7 @@ use syntax::codemap; 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { variables.extend(unbound_ty_vars); variables.extend(unbound_int_vars); variables.extend(unbound_float_vars); - + return variables; } @@ -1047,15 +1048,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 fa7cd143e3b21..8707306a149c7 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 a08c5e1f73fa2..19add679bbfdc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -54,6 +54,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte 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 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { 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 @@ impl<'tcx> ctxt<'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 @@ impl<'tcx> ctxt<'tcx> { 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 5ed1da2fedebc..3925f4e751c20 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -111,7 +111,7 @@ pub trait AstConv<'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 e3b9b990cb9e5..488428833ac13 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -315,11 +315,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 2ca5a88fb06dd..767797e843caf 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 88bd000cfdd65..b190e7a7a4830 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1207,7 +1207,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { !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 f6a4dbca291bb..3a93c7ed9161d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1139,8 +1139,9 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // If there are no more fallbacks to apply at this point we have applied all possible + // defaults and type inference will procede as normal. if 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - 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 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'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 695991a97f061..8b38c58ce7a1b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } } - 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 c37d3747da75c..8e4f8ea581502 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 3a93c7ed9161d..d93848f408caf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1141,7 +1141,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { 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 0000000000000..fe8c1063c96dc --- /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 0000000000000..9322c9ad165ae --- /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 d42e65d90fee2..0a8543c03b139 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 402399f14b936..0000000000000 --- 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 4f492bed9d4f2..0000000000000 --- 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 d38417143ce06..eaa5b6d58f899 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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 19add679bbfdc..4945e0766e757 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 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { 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 @@ impl<'tcx> ctxt<'tcx> { 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 d93848f408caf..c9b10cec44a97 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1785,7 +1785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 c9b10cec44a97..42b28dcbc1b54 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1784,43 +1784,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 conflicts.len() > 0 { - self.infcx().rollback_to(snapshot); + // If there are conflicts we rollback, otherwise commit + if conflicts.len() > 0 { + Err(()) + } else { + Ok(()) + } + }); - // Loop through each conflicting default compute the conflict - // and then report the error. + if conflicts.len() > 0 { + // Loop through each conflicting default, figuring out the default that caused + // a unification failure and then report an error for each. for (conflict, default) in conflicts { let conflicting_default = self.find_conflicting_default( @@ -1832,13 +1838,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 | 26 ++++++---- src/librustc_typeck/check/method/probe.rs | 15 +++--- src/librustc_typeck/check/mod.rs | 11 ++-- 6 files changed, 98 insertions(+), 61 deletions(-) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index eaa5b6d58f899..253f6379d155d 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1047,12 +1047,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 4e98ef2753105..7d8a20c42e36e 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -154,7 +154,7 @@ impl<'tcx> 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 488428833ac13..12e14dbcb92f8 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -84,9 +84,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { 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 767797e843caf..1bcb7a5ce031f 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 { + + 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 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()); - input_types + substs.types.replace(subst::ParamSpace::TypeSpace, input_types); } None => { - fcx.inh.infcx.type_vars_for_defs(span, type_parameter_defs) + fcx.inh.infcx.type_vars_for_defs( + span, + subst::ParamSpace::TypeSpace, + &mut substs, + 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 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 b190e7a7a4830..44d769a799f1d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1200,16 +1200,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { .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 42b28dcbc1b54..fd99d1ddba9cd 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 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'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 bdb481bc93859..10552791d8b86 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 @@ impl<'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 @@ impl<'ast> MapEntry<'ast> { EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, + EntryTyParam(id, _) => id, _ => return None }) } @@ -213,6 +217,7 @@ impl<'ast> MapEntry<'ast> { EntryBlock(_, n) => NodeBlock(n), EntryStructCtor(_, n) => NodeStructCtor(n), EntryLifetime(_, n) => NodeLifetime(n), + EntryTyParam(_, n) => NodeTyParam(n), _ => return None }) } @@ -573,6 +578,7 @@ impl<'ast> Map<'ast> { 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 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { 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 @@ impl<'a> NodePrinter for pprust::State<'a> { 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 72e1525b506d1..54c55d76a8270 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 c77e96f164888..597401daccfd2 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 253f6379d155d..d10dd7073532b 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -40,7 +40,6 @@ use syntax::codemap; 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 4945e0766e757..a4f714b3bf9c7 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 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { 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 @@ impl<'tcx> ctxt<'tcx> { 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 b6bb82ad7b15b..0c694926ba4b5 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -340,6 +340,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { 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 217181da1421a..31e4b9c48e20b 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 3925f4e751c20..120cfcbca3748 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use middle::def; 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 @@ pub trait AstConv<'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 fd99d1ddba9cd..76886fc1275bd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1139,14 +1139,31 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'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 8b38c58ce7a1b..6bff90825f328 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -404,7 +404,11 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } } - 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 8e4f8ea581502..c37d3747da75c 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 9322c9ad165ae..eba86415af4c9 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 7d50e6f6917cc..fb11aaed61958 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 d10dd7073532b..f63154af72426 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1061,11 +1061,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 8707306a149c7..3684651f85be6 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -12,6 +12,7 @@ pub use self::RelationDir::*; 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 a4f714b3bf9c7..3bda1730e63b8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -79,6 +79,7 @@ use std::ops; 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 @@ impl<'tcx> ctxt<'tcx> { 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 76886fc1275bd..fd4cf6f28df91 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1146,14 +1146,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .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 6bff90825f328..d31a29ecc0e2c 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 3bda1730e63b8..ea5ca8acb094f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5453,7 +5453,8 @@ impl<'tcx> ctxt<'tcx> { 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 @@ impl<'tcx> ctxt<'tcx> { .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 @@ impl<'tcx> ctxt<'tcx> { } } - 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 12e14dbcb92f8..e9869e2a00e5d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -349,7 +349,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } 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 1bcb7a5ce031f..e3f55cca9ee51 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 0000000000000..270cfdcb7f651 --- /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 0000000000000..bc79d3713e558 --- /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 fd4cf6f28df91..95e916f1a0d14 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1800,6 +1800,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 d31a29ecc0e2c..236a1e690e88c 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 900945da1136b..42de545f9d050 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 @@ use std::fmt::Debug; // Example from the RFC fn foo() -> F { F::default() } +//~^ NOTE: a default was defined here... + fn bar(b: B) { println!("{:?}", b); } +//~^ NOTE: a second default was defined here... fn main() { // Here, F is instantiated with $0=uint let x = foo(); + //~^ ERROR: mismatched types + //~| NOTE: conflicting type parameter defaults `usize` and `isize` + //~| NOTE: ...that was applied to an unconstrained type variable here // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. bar(x); + //~^ NOTE: ...that also applies to the same type variable here } diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index bc79d3713e558..804a864e074e6 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 26fd2fd8d20d6..59721edda707b 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 95e916f1a0d14..eb0ef30d396cd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1709,10 +1709,47 @@ impl<'a, 'tcx> FnCtxt<'a, '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 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 ee895fb1a96eb..af7e4a6855f7a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -163,6 +163,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // 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 @@ impl 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 42de545f9d050..48c5cd1ff7706 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 804a864e074e6..4d60724372ada 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 fe8c1063c96dc..8fc2c2e6bce70 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 eba86415af4c9..ac833d0f54744 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 35f0fcab00175..e8d93092ec53d 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 b94b759fd113f..d9ac51fc23b02 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 0a8543c03b139..6e3e60a02e5e2 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 fbceb60b9a8e7..c67d3a49aff3d 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 00d7ccf43becc..067ad524922c0 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 c3e44e55beeb2..1b4747406d0c6 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 eb0ef30d396cd..85df5d67ff6eb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1711,7 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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 af7e4a6855f7a..c3338f02ee43c 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"), } }