about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJared Roesch <roeschinc@gmail.com>2015-07-07 15:50:02 -0700
committerJared Roesch <jroesch@MacBook.home>2015-07-25 19:57:57 -0700
commitbbcb13da88f7a4b25506ec85f2f170e6f78d5a58 (patch)
tree6a872075699ea6996313f46ed03983da066c423a /src
parent7276d8b7613c81c09feeec3bf94d47c4a5174bc8 (diff)
downloadrust-bbcb13da88f7a4b25506ec85f2f170e6f78d5a58.tar.gz
rust-bbcb13da88f7a4b25506ec85f2f170e6f78d5a58.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/infer/mod.rs78
-rw-r--r--src/librustc/middle/infer/type_variable.rs9
-rw-r--r--src/librustc/middle/ty.rs11
-rw-r--r--src/librustc_data_structures/unify/mod.rs8
-rw-r--r--src/librustc_typeck/check/method/confirm.rs10
-rw-r--r--src/librustc_typeck/check/method/mod.rs5
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs128
-rw-r--r--src/test/compile-fail/default_ty_param_conflict.rs23
-rw-r--r--src/test/compile-fail/default_ty_param_type_alias.rs17
-rw-r--r--src/test/run-pass/default_ty_param_method_call_test.rs22
-rw-r--r--src/test/run-pass/default_ty_param_struct.rs21
-rw-r--r--src/test/run-pass/default_ty_param_trait_impl.rs23
-rw-r--r--src/test/run-pass/default_ty_param_trait_impl_simple.rs26
14 files changed, 340 insertions, 45 deletions
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index c6df1c395cc..5339464503b 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<FnvHashMap<Ty<'tcx>, 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<ty::Ty<'tcx>> {
+        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<ty::Ty<'tcx>> {
+        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<T>(
         &self,
         span: Span,
diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs
index 6f1de3ee635..ebecb0898b4 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<ty::TyVid> {
+        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 84ca7cd437a..a08c5e1f73f 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2068,6 +2068,7 @@ pub enum TypeError<'tcx> {
     ConvergenceMismatch(ExpectedFound<bool>),
     ProjectionNameMismatched(ExpectedFound<ast::Name>),
     ProjectionBoundsLength(ExpectedFound<usize>),
+    terr_ty_param_default_mismatch(expected_found<Ty<'tcx>>)
 }
 
 /// 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 a899bbacc03..7582b7ff61d 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<K>
     pub fn probe(&mut self, a_id: K) -> Option<V> {
         self.get(a_id).value.clone()
     }
-}
 
+    pub fn unsolved_variables(&mut self) -> Vec<K> {
+        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 a8c56b2660c..e3b9b990cb9 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 a74c004389b..2ca5a88fb06 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 a960123efc6..88bd000cfdd 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 082dafc72bc..e226b0b21a1 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 00000000000..900945da113
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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:Default=usize>() -> F { F::default() }
+fn bar<B:Debug=isize>(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 00000000000..c3e44e55bee
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+
+type IntMap<K=usize> = HashMap<K, usize>;
+
+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 00000000000..35f0fcab001
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo;
+
+impl Foo {
+    fn method<A:Default=String>(&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 00000000000..b94b759fd11
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo<A>(A);
+
+impl<A:Default=i32> Foo<A> {
+    fn new() -> Foo<A> {
+        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 00000000000..fbceb60b9a8
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T:Bar=usize> Foo for Vec<T> {} // Impl 1
+impl Bar for usize { } // Impl 2
+
+fn takes_foo<F: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 00000000000..00d7ccf43be
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T:Bar=usize> Foo for Vec<T> {
+    fn takes_foo(&self) {}
+} // Impl 1
+
+impl Bar for usize { } // Impl 2
+
+// fn takes_foo<F:Foo>(f: F) { }
+
+fn main() {
+    let x = Vec::new(); // x: Vec<$0>
+    x.takes_foo(); // adds oblig Vec<$0> : Foo
+}