about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/reference.md2
-rw-r--r--src/librustc/ast_map/mod.rs21
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/metadata/tydecode.rs2
-rw-r--r--src/librustc/metadata/tyencode.rs4
-rw-r--r--src/librustc/middle/infer/error_reporting.rs4
-rw-r--r--src/librustc/middle/infer/mod.rs127
-rw-r--r--src/librustc/middle/infer/type_variable.rs71
-rw-r--r--src/librustc/middle/subst.rs2
-rw-r--r--src/librustc/middle/ty.rs65
-rw-r--r--src/librustc/middle/ty_fold.rs1
-rw-r--r--src/librustc_data_structures/unify/mod.rs8
-rw-r--r--src/librustc_trans/trans/monomorphize.rs1
-rw-r--r--src/librustc_typeck/astconv.rs22
-rw-r--r--src/librustc_typeck/check/method/confirm.rs65
-rw-r--r--src/librustc_typeck/check/method/mod.rs27
-rw-r--r--src/librustc_typeck/check/method/probe.rs15
-rw-r--r--src/librustc_typeck/check/mod.rs313
-rw-r--r--src/librustc_typeck/collect.rs12
-rw-r--r--src/libsyntax/feature_gate.rs11
-rw-r--r--src/test/auxiliary/default_ty_param_cross_crate_crate.rs19
-rw-r--r--src/test/compile-fail/default_ty_param_conflict.rs32
-rw-r--r--src/test/compile-fail/default_ty_param_conflict_cross_crate.rs29
-rw-r--r--src/test/run-pass/default_ty_param_default_dependent_associated_type.rs36
-rw-r--r--src/test/run-pass/default_ty_param_dependent_defaults.rs19
-rw-r--r--src/test/run-pass/default_ty_param_method_call_test.rs24
-rw-r--r--src/test/run-pass/default_ty_param_struct.rs23
-rw-r--r--src/test/run-pass/default_ty_param_struct_and_type_alias.rs40
-rw-r--r--src/test/run-pass/default_ty_param_trait_impl.rs25
-rw-r--r--src/test/run-pass/default_ty_param_trait_impl_simple.rs26
-rw-r--r--src/test/run-pass/default_ty_param_type_alias.rs19
31 files changed, 949 insertions, 117 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 26fd2fd8d20..59721edda70 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/ast_map/mod.rs b/src/librustc/ast_map/mod.rs
index bdb481bc938..10552791d8b 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/lib.rs b/src/librustc/lib.rs
index 7d50e6f6917..fb11aaed619 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/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 72e1525b506..54c55d76a82 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 c77e96f1648..597401daccf 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/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 8d66ffac5d1..fbf19a10d93 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 c6df1c395cc..f63154af724 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -653,6 +653,50 @@ 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.
+    ///
+    /// 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<type_variable::Default<'tcx>> {
+        match ty.sty {
+            ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid),
+            _ => None
+        }
+    }
+
+    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,
@@ -956,13 +1000,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<type_variable::Default<'tcx>>) -> 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))
     }
@@ -996,6 +1049,31 @@ 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,
+                              space: subst::ParamSpace,
+                              substs: &mut Substs<'tcx>,
+                              defs: &[ty::TypeParameterDef<'tcx>]) {
+
+        let mut vars = Vec::with_capacity(defs.len());
+
+        for def in defs.iter() {
+            let default = def.default.map(|default| {
+                type_variable::Default {
+                    ty: default.subst_spanned(self.tcx, substs, Some(span)),
+                    origin_span: span,
+                    def_id: def.default_def_id
+                }
+            });
+
+            let ty_var = self.next_ty_var_with_default(default);
+            substs.types.push(space, ty_var);
+            vars.push(ty_var)
+        }
+    }
+
     /// 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,13 +1081,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                      generics: &ty::Generics<'tcx>)
                                      -> subst::Substs<'tcx>
     {
-        let type_params =
-            generics.types.map(
-                |_| self.next_ty_var());
+        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
@@ -1027,13 +1115,17 @@ 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_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 {
@@ -1268,6 +1360,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.report_and_explain_type_error(trace, err);
     }
 
+    pub fn report_conflicting_default_types(&self,
+                                            span: Span,
+                                            expected: type_variable::Default<'tcx>,
+                                            actual: type_variable::Default<'tcx>) {
+        let trace = TypeTrace {
+            origin: Misc(span),
+            values: Types(ty::ExpectedFound {
+                expected: expected.ty,
+                found: actual.ty
+            })
+        };
+
+        self.report_and_explain_type_error(trace,
+            &TypeError::TyParamDefaultMismatch(ty::ExpectedFound {
+                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..3684651f85b 100644
--- a/src/librustc/middle/infer/type_variable.rs
+++ b/src/librustc/middle/infer/type_variable.rs
@@ -11,8 +11,10 @@
 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;
 use std::marker::PhantomData;
 use std::mem;
@@ -30,16 +32,30 @@ struct TypeVariableData<'tcx> {
 
 enum TypeVariableValue<'tcx> {
     Known(Ty<'tcx>),
-    Bounded(Vec<Relation>),
+    Bounded {
+        relations: Vec<Relation>,
+        default: Option<Default<'tcx>>
+    }
+}
+
+// We will use this to store the required information to recapitulate what happened when
+// an error occurs.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Default<'tcx> {
+    pub ty: Ty<'tcx>,
+    /// The span where the default was incurred
+    pub origin_span: Span,
+    /// The definition that the default originates from
+    pub def_id: DefId
 }
 
 pub struct Snapshot {
     snapshot: sv::Snapshot
 }
 
-enum UndoEntry {
+enum UndoEntry<'tcx> {
     // The type of the var was specified.
-    SpecifyVar(ty::TyVid, Vec<Relation>),
+    SpecifyVar(ty::TyVid, Vec<Relation>, Option<Default<'tcx>>),
     Relate(ty::TyVid, ty::TyVid),
 }
 
@@ -72,6 +88,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
         relations(self.values.get_mut(a.index as usize))
     }
 
+    pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
+        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
     }
@@ -101,8 +124,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
             mem::replace(value_ptr, Known(ty))
         };
 
-        let relations = match old_value {
-            Bounded(b) => b,
+        let (relations, default) = match old_value {
+            Bounded { relations, default } => (relations, default),
             Known(_) => panic!("Asked to instantiate variable that is \
                                already instantiated")
         };
@@ -111,12 +134,14 @@ 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, diverging: bool) -> ty::TyVid {
+    pub fn new_var(&mut self,
+                   diverging: bool,
+                   default: Option<Default<'tcx>>) -> 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 +149,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     pub fn probe(&self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
         match self.values.get(vid.index as usize).value {
-            Bounded(..) => None,
+            Bounded { .. } => None,
             Known(t) => Some(t)
         }
     }
@@ -179,7 +204,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.
@@ -195,16 +220,30 @@ 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> {
     type Value = TypeVariableData<'tcx>;
-    type Undo = UndoEntry;
+    type Undo = UndoEntry<'tcx>;
 
-    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: UndoEntry) {
+    fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: UndoEntry<'tcx>) {
         match action {
-            SpecifyVar(vid, relations) => {
-                values[vid.index as usize].value = Bounded(relations);
+            SpecifyVar(vid, relations, default) => {
+                values[vid.index as usize].value = Bounded {
+                    relations: relations,
+                    default: default
+                };
             }
 
             Relate(a, b) => {
@@ -218,6 +257,6 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
 fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec<Relation> {
     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/middle/subst.rs b/src/librustc/middle/subst.rs
index 4e98ef27531..7d8a20c42e3 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<F>(self, op: F) -> RegionSubsts where
+    pub fn map<F>(self, op: F) -> RegionSubsts where
         F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
     {
         match self {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 84ca7cd437a..ea5ca8acb09 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;
@@ -78,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};
@@ -114,8 +116,6 @@ pub struct Field<'tcx> {
     pub mt: TypeAndMut<'tcx>
 }
 
-
-
 // Enum information
 #[derive(Clone)]
 pub struct VariantInfo<'tcx> {
@@ -2038,7 +2038,7 @@ pub struct ExpectedFound<T> {
 }
 
 // Data structures used in type unification
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Debug)]
 pub enum TypeError<'tcx> {
     Mismatch,
     UnsafetyMismatch(ExpectedFound<ast::Unsafety>),
@@ -2068,6 +2068,7 @@ pub enum TypeError<'tcx> {
     ConvergenceMismatch(ExpectedFound<bool>),
     ProjectionNameMismatched(ExpectedFound<ast::Name>),
     ProjectionBoundsLength(ExpectedFound<usize>),
+    TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
 }
 
 /// Bounds suitable for an existentially quantified type parameter
@@ -2280,6 +2281,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<Ty<'tcx>>,
     pub object_lifetime_default: ObjectLifetimeDefault,
 }
@@ -5080,6 +5082,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                 write!(f, "expected {} associated type bindings, found {}",
                        values.expected,
                        values.found)
+            },
+            TyParamDefaultMismatch(ref values) => {
+                write!(f, "conflicting type parameter defaults `{}` and `{}`",
+                       values.expected.ty,
+                       values.found.ty)
             }
         }
     }
@@ -5399,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 ",
@@ -5437,6 +5444,56 @@ impl<'tcx> ctxt<'tcx> {
                         &format!("consider boxing your closure and/or \
                                   using it as a trait object"));
                 }
+            },
+            TyParamDefaultMismatch(values) => {
+                let expected = values.expected;
+                let found = values.found;
+                self.sess.span_note(sp,
+                                    &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::<Vec<_>>();
+                        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"));
+
+                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::<Vec<_>>();
+
+                        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"));
             }
             _ => {}
         }
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index b6bb82ad7b1..0c694926ba4 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_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_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 217181da142..31e4b9c48e2 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 d516c648d7e..332b84bfc7b 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, span: Span) -> Ty<'tcx>;
+        fn ty_infer(&self,
+                    param_and_substs: Option<ty::TypeParameterDef<'tcx>>,
+                    substs: Option<&mut Substs<'tcx>>,
+                    space: Option<ParamSpace>,
+                    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() {
-        (0..formal_ty_param_count).map(|_| this.ty_infer(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
     };
@@ -1654,7 +1662,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, None, None, ast_ty.span)
         }
     };
 
@@ -1670,7 +1678,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, None, None, a.ty.span),
         _ => ast_ty_to_ty(this, rscope, &*a.ty),
     }
 }
@@ -1789,7 +1797,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, None, None, output.span)),
         ast::Return(ref output) =>
             ty::FnConverging(convert_ty_with_lifetime_elision(this,
                                                               implied_output_region,
@@ -1929,7 +1937,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, 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/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index a8c56b2660c..e9869e2a00e 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,30 +305,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
     fn instantiate_method_substs(&mut self,
                                  pick: &probe::Pick<'tcx>,
-                                 supplied_method_types: Vec<Ty<'tcx>>)
-                                 -> (Vec<Ty<'tcx>>, Vec<ty::Region>)
+                                 supplied_method_types: Vec<Ty<'tcx>>,
+                                 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
         // 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_types = {
-            if num_supplied_types == 0 {
-                self.fcx.infcx().next_ty_vars(num_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)
-            } 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
-            }
-        };
+        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();
+
 
         // Create subst for early-bound lifetime parameters, combining
         // parameters from the type and those from the method.
@@ -337,7 +328,35 @@ 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 a74c004389b..e3f55cca9ee 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -167,23 +167,30 @@ 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 input_types = match opt_input_types {
+    let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
+    let expected_number_of_input_types = type_parameter_defs.len();
+
+    assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
+    assert!(trait_def.generics.regions.is_empty());
+
+    // Construct a trait-reference `self_ty : Trait<input_tys>`
+    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.next_ty_vars(expected_number_of_input_types)
+            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<input_tys>`
-    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 a960123efc6..44d769a799f 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().next_ty_vars(
-                    method.generics.types.len(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 082dafc72bc..85df5d67ff6 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};
@@ -108,6 +109,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};
@@ -1137,8 +1139,27 @@ 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,
+                ty_param_def: Option<ty::TypeParameterDef<'tcx>>,
+                substs: Option<&mut subst::Substs<'tcx>>,
+                space: Option<subst::ParamSpace>,
+                span: Span) -> Ty<'tcx> {
+        // Grab the default doing subsitution
+        let default = ty_param_def.and_then(|def| {
+            def.default.map(|ty| type_variable::Default {
+                ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)),
+                origin_span: span,
+                def_id: def.default_def_id
+            })
+        });
+
+        let ty_var = self.infcx().next_ty_var_with_default(default);
+
+        // Finally we add the type variable to the substs
+        match substs {
+            None => ty_var,
+            Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var }
+        }
     }
 
     fn projected_ty_from_poly_trait_ref(&self,
@@ -1255,28 +1276,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 {}",
@@ -1710,14 +1709,260 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Apply "fallbacks" to some types
+    /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64.
+    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) {
-        debug!("select_all_obligations_and_apply_defaults");
+        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
+        // 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();
+
+            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 | UnconstrainedFloat => {
+                            unbound_tyvars.insert(resolved);
+                        },
+                        Neither => {}
+                    }
+                }
+            }
+
+            // 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(_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, _default);
+
+                    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 there are no more fallbacks to apply at this point we have applied all possible
+            // defaults and type inference will procede as normal.
+            if unbound_tyvars.is_empty() {
+                break;
+            }
+
+            // Finally we 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 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));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // If there are conflicts we rollback, otherwise commit
+                if conflicts.len() > 0 {
+                    Err(())
+                } else {
+                    Ok(())
+                }
+            });
+
+            if conflicts.len() > 0 {
+                // Loop through each conflicting default, figuring out the default that caused
+                // a unification failure and then report an error for each.
+                for (conflict, default) in conflicts {
+                    let conflicting_default =
+                        self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
+                            .unwrap_or(type_variable::Default {
+                                ty: self.infcx().next_ty_var(),
+                                origin_span: codemap::DUMMY_SP,
+                                def_id: 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(
+                        first_default.origin_span,
+                        first_default,
+                        second_default)
+                }
+            }
+        }
+
+        self.select_obligations_where_possible();
+    }
+
+    // For use in error handling related to default type parameter fallback. We explicitly
+    // apply the default that caused conflict first to a local version of the type variable
+    // table then apply defaults until we find a conflict. That default must be the one
+    // that caused conflict earlier.
+    fn find_conflicting_default(&self,
+                                unbound_vars: &HashSet<Ty<'tcx>>,
+                                default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>,
+                                conflict: Ty<'tcx>)
+                                -> Option<type_variable::Default<'tcx>> {
+        use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};
+
+        // Ensure that we apply the conflicting default first
+        let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1);
+        unbound_tyvars.push(conflict);
+        unbound_tyvars.extend(unbound_vars.iter());
+
+        let mut result = None;
+        // We run the same code as above applying defaults in order, this time when
+        // we find the conflict we just return it for error reporting above.
+
+        // We also run this inside snapshot that never commits so we can do error
+        // reporting for more then one conflict.
+        for ty in &unbound_tyvars {
+            if self.infcx().type_var_diverges(ty) {
+                demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
+            } else {
+                match self.infcx().type_is_unconstrained_numeric(ty) {
+                    UnconstrainedInt => {
+                        demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32)
+                    },
+                    UnconstrainedFloat => {
+                        demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
+                    },
+                    Neither => {
+                        if let Some(default) = default_map.get(ty) {
+                            let default = default.clone();
+                            match infer::mk_eqty(self.infcx(), false,
+                                                 infer::Misc(default.origin_span),
+                                                 ty, default.ty) {
+                                Ok(()) => {}
+                                Err(_) => {
+                                    result = Some(default);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
     fn select_all_obligations_or_error(&self) {
         debug!("select_all_obligations_or_error");
 
@@ -1726,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(()) => { }
@@ -2421,14 +2667,18 @@ 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 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 }
@@ -4434,7 +4684,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));
@@ -4647,7 +4897,8 @@ 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, 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 b003f0fc4f8..00537f66bbc 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, span: Span) -> Ty<'tcx> {
+        fn ty_infer(&self,
+                    _ty_param_def: Option<ty::TypeParameterDef<'tcx>>,
+                    _substs: Option<&mut Substs<'tcx>>,
+                    _space: Option<ParamSpace>,
+                    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
@@ -1643,11 +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(parent),
         default: None,
         object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
     };
@@ -1916,11 +1923,14 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         compute_object_lifetime_default(ccx, param.id,
                                         &param.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),
+        default_def_id: local_def(parent),
         default: default,
         object_lifetime_default: object_lifetime_default,
     };
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ee895fb1a96..c3338f02ee4 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,
         }
     }
 }
@@ -864,7 +868,8 @@ fn check_crate_inner<F>(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"),
     }
 }
 
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 00000000000..270cfdcb7f6
--- /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 <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.
+
+#![crate_type = "lib"]
+#![crate_name = "default_param_test"]
+
+use std::marker::PhantomData;
+
+pub struct Foo<A, B>(PhantomData<(A, B)>);
+
+pub fn bleh<A=i32, X=char>() -> Foo<A, X> { Foo(PhantomData) }
+
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..48c5cd1ff77
--- /dev/null
+++ b/src/test/compile-fail/default_ty_param_conflict.rs
@@ -0,0 +1,32 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(default_type_parameter_fallback)]
+
+use std::fmt::Debug;
+
+// Example from the RFC
+fn foo<F:Default=usize>() -> F { F::default() }
+//~^ NOTE: a default was defined here...
+
+fn bar<B:Debug=isize>(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
new file mode 100644
index 00000000000..4d60724372a
--- /dev/null
+++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs
@@ -0,0 +1,29 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+//
+//aux-build:default_ty_param_cross_crate_crate.rs
+
+#![feature(default_type_parameter_fallback)]
+
+extern crate default_param_test;
+
+use default_param_test::{Foo, bleh};
+
+fn meh<X, B=bool>(x: Foo<X, B>) {}
+//~^ NOTE: a default was defined here...
+
+fn main() {
+    let foo = bleh();
+    //~^ NOTE: ...that also applies to the same type variable here
+
+    meh(foo);
+    //~^ ERROR: mismatched types:
+    //~| NOTE: conflicting type parameter defaults `bool` and `char`
+}
diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs
new file mode 100644
index 00000000000..8fc2c2e6bce
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+//
+
+#![feature(default_type_parameter_fallback)]
+
+use std::marker::PhantomData;
+
+trait Id {
+    type This;
+}
+
+impl<A> Id for A {
+    type This = A;
+}
+
+struct Foo<X: Default = usize, Y = <X as Id>::This> {
+    data: PhantomData<(X, Y)>
+}
+
+impl<X: Default, Y> Foo<X, Y> {
+    fn new() -> Foo<X, Y> {
+        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 00000000000..ac833d0f547
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_dependent_defaults.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+//
+
+#![feature(default_type_parameter_fallback)]
+use std::marker::PhantomData;
+
+struct Foo<T,U=T> { t: T, data: PhantomData<U> }
+
+fn main() {
+    let foo = Foo { t: 'a', 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
new file mode 100644
index 00000000000..e8d93092ec5
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_method_call_test.rs
@@ -0,0 +1,24 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(default_type_parameter_fallback)]
+
+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..d9ac51fc23b
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_struct.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(default_type_parameter_fallback)]
+
+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_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs
new file mode 100644
index 00000000000..6e3e60a02e5
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs
@@ -0,0 +1,40 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+//
+
+#![feature(default_type_parameter_fallback)]
+
+use std::marker::PhantomData;
+
+struct DeterministicHasher;
+struct RandomHasher;
+
+
+struct MyHashMap<K, V, H=DeterministicHasher> {
+    data: PhantomData<(K, V, H)>
+}
+
+impl<K, V, H> MyHashMap<K, V, H> {
+    fn new() -> MyHashMap<K, V, H> {
+        MyHashMap { data: PhantomData }
+    }
+}
+
+mod mystd {
+    use super::{MyHashMap, RandomHasher};
+    pub type HashMap<K, V, H=RandomHasher> = MyHashMap<K, V, H>;
+}
+
+fn try_me<H>(hash_map: mystd::HashMap<i32, i32, H>) {}
+
+fn main() {
+    let hash_map = mystd::HashMap::new();
+    try_me(hash_map);
+}
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..c67d3a49aff
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_trait_impl.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(default_type_parameter_fallback)]
+
+// Another example from the RFC
+trait Foo { }
+trait Bar { }
+
+impl<T:Bar=usize> Foo for Vec<T> {}
+impl Bar for usize {}
+
+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..067ad524922
--- /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.
+
+#![feature(default_type_parameter_fallback)]
+
+// 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 Bar for usize {}
+
+fn main() {
+    let x = Vec::new(); // x: Vec<$0>
+    x.takes_foo(); // adds oblig Vec<$0> : Foo
+}
diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs
new file mode 100644
index 00000000000..1b4747406d0
--- /dev/null
+++ b/src/test/run-pass/default_ty_param_type_alias.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![feature(default_type_parameter_fallback)]
+
+use std::collections::HashMap;
+
+type IntMap<K=usize> = HashMap<K, usize>;
+
+fn main() {
+    let x = IntMap::new();
+}