]> git.lizzy.rs Git - rust.git/commitdiff
Make the `Fn` traits inherit from one another and remove the bridging
authorNiko Matsakis <niko@alum.mit.edu>
Sun, 15 Feb 2015 20:09:26 +0000 (15:09 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 23 Mar 2015 20:46:02 +0000 (16:46 -0400)
impls.

This requires:

1. modifying trait selection a bit so that when we synthesize impls for
   fn pointers and closures;
2. adding code to trans so that we can synthesize a `FnMut`/`FnOnce`
   impl for a `Fn` closure and so forth.

12 files changed:
src/libcore/ops.rs
src/libcore/str/mod.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/ty.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/meth.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/collect.rs

index 6324e8fa874439bf54d850809716a54146753534..fc3f4b426d8615700fd85442a6adb7408ca3b388 100644 (file)
@@ -1136,6 +1136,7 @@ fn deref_mut(&mut self) -> &mut T { *self }
 #[lang="fn"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
+#[cfg(stage0)]
 pub trait Fn<Args> {
     /// The returned type after the call operator is used.
     type Output;
@@ -1144,10 +1145,21 @@ pub trait Fn<Args> {
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
 }
 
+/// A version of the call operator that takes an immutable receiver.
+#[lang="fn"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_paren_sugar]
+#[cfg(not(stage0))]
+pub trait Fn<Args> : FnMut<Args> {
+    /// This is called when the call operator is used.
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
 /// A version of the call operator that takes a mutable receiver.
 #[lang="fn_mut"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
+#[cfg(stage0)]
 pub trait FnMut<Args> {
     /// The returned type after the call operator is used.
     type Output;
@@ -1156,6 +1168,16 @@ pub trait FnMut<Args> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 }
 
+/// A version of the call operator that takes a mutable receiver.
+#[lang="fn_mut"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_paren_sugar]
+#[cfg(not(stage0))]
+pub trait FnMut<Args> : FnOnce<Args> {
+    /// This is called when the call operator is used.
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
 /// A version of the call operator that takes a by-value receiver.
 #[lang="fn_once"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1168,6 +1190,7 @@ pub trait FnOnce<Args> {
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
 
+#[cfg(stage0)]
 impl<F: ?Sized, A> FnMut<A> for F
     where F : Fn<A>
 {
@@ -1178,6 +1201,7 @@ extern "rust-call" fn call_mut(&mut self, args: A) -> <F as Fn<A>>::Output {
     }
 }
 
+#[cfg(stage0)]
 impl<F,A> FnOnce<A> for F
     where F : FnMut<A>
 {
index e8181395b5c1e5a19538eb3eef1942014577daa4..dd7144636dfb7ea4dd7c16e6d641fd781517c6d2 100644 (file)
@@ -29,7 +29,7 @@
 use marker::Sized;
 use mem;
 use num::Int;
-use ops::{Fn, FnMut};
+use ops::{Fn, FnMut, FnOnce};
 use option::Option::{self, None, Some};
 use raw::{Repr, Slice};
 use result::Result::{self, Ok, Err};
@@ -524,6 +524,7 @@ fn next_back(&mut self) -> Option<(usize, char)> {
 #[derive(Copy, Clone)]
 struct BytesDeref;
 
+#[cfg(stage0)]
 impl<'a> Fn<(&'a u8,)> for BytesDeref {
     type Output = u8;
 
@@ -533,6 +534,32 @@ extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
     }
 }
 
+#[cfg(not(stage0))]
+impl<'a> Fn<(&'a u8,)> for BytesDeref {
+    #[inline]
+    extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
+        *ptr
+    }
+}
+
+#[cfg(not(stage0))]
+impl<'a> FnMut<(&'a u8,)> for BytesDeref {
+    #[inline]
+    extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
+        Fn::call(&*self, (ptr,))
+    }
+}
+
+#[cfg(not(stage0))]
+impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
+    type Output = u8;
+
+    #[inline]
+    extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
+        Fn::call(&self, (ptr,))
+    }
+}
+
 /// An iterator over the substrings of a string, separated by `sep`.
 struct CharSplits<'a, P: Pattern<'a>> {
     /// The slice remaining to be iterated
index 6b66d7227d300d00ca6e4280ebf7ea778b69d18c..b4f21492ca10b0c95a9bb678c91e89c5f15780c9 100644 (file)
@@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>(
            obligation.repr(tcx),
            fn_sig.repr(tcx));
 
+    // the `Output` associated type is declared on `FnOnce`
+    let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
+
     // Note: we unwrap the binder here but re-create it below (1)
     let ty::Binder((trait_ref, ret_type)) =
         util::closure_trait_ref_and_return_type(tcx,
-                                                obligation.predicate.trait_ref.def_id,
+                                                fn_once_def_id,
                                                 obligation.predicate.trait_ref.self_ty(),
                                                 fn_sig,
                                                 flag);
index 7dfbccea0dccd160f4c8ecfb6a0470083d6c28c1..764e342a0c5af353dfde0a112d4764f92e45202f 100644 (file)
@@ -1071,7 +1071,7 @@ fn assemble_closure_candidates(&mut self,
         match self.closure_typer.closure_kind(closure_def_id) {
             Some(closure_kind) => {
                 debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
-                if closure_kind == kind {
+                if closure_kind.extends(kind) {
                     candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
                 }
             }
@@ -1090,10 +1090,8 @@ fn assemble_fn_pointer_candidates(&mut self,
                                       candidates: &mut SelectionCandidateSet<'tcx>)
                                       -> Result<(),SelectionError<'tcx>>
     {
-        // We provide a `Fn` impl for fn pointers. There is no need to provide
-        // the other traits (e.g. `FnMut`) since those are provided by blanket
-        // impls.
-        if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
+        // We provide impl of all fn traits for fn pointers.
+        if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
             return Ok(());
         }
 
index 99c35c6e5425824a20b3e8ba2144f5d885dd4aba..4b8c4ee88c05da0189238958223157e8147eff3f 100644 (file)
@@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> {
     pub substs: Substs<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
 pub enum ClosureKind {
+    // Warning: Ordering is significant here! The ordering is chosen
+    // because the trait Fn is a subtrait of FnMut and so in turn, and
+    // hence we order it so that Fn < FnMut < FnOnce.
     FnClosureKind,
     FnMutClosureKind,
     FnOnceClosureKind,
@@ -2484,6 +2487,20 @@ pub fn trait_did(&self, cx: &ctxt) -> ast::DefId {
             Err(err) => cx.sess.fatal(&err[..]),
         }
     }
+
+    /// True if this a type that impls this closure kind
+    /// must also implement `other`.
+    pub fn extends(self, other: ty::ClosureKind) -> bool {
+        match (self, other) {
+            (FnClosureKind, FnClosureKind) => true,
+            (FnClosureKind, FnMutClosureKind) => true,
+            (FnClosureKind, FnOnceClosureKind) => true,
+            (FnMutClosureKind, FnMutClosureKind) => true,
+            (FnMutClosureKind, FnOnceClosureKind) => true,
+            (FnOnceClosureKind, FnOnceClosureKind) => true,
+            _ => false,
+        }
+    }
 }
 
 pub trait ClosureTyper<'tcx> {
index cf36ec1f3ed96f49954a1ec836a582ae23c6460c..07c94097e2df8a17cb2c7d5720998ba04c639d57 100644 (file)
@@ -264,14 +264,29 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// but for the bare function type given.
 pub fn trans_fn_pointer_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
+    closure_kind: ty::ClosureKind,
     bare_fn_ty: Ty<'tcx>)
     -> ValueRef
 {
     let _icx = push_ctxt("trans_fn_pointer_shim");
     let tcx = ccx.tcx();
 
+    // Normalize the type for better caching.
     let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
-    match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
+
+    // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
+    let is_by_ref = match closure_kind {
+        ty::FnClosureKind | ty::FnMutClosureKind => true,
+        ty::FnOnceClosureKind => false,
+    };
+    let bare_fn_ty_maybe_ref = if is_by_ref {
+        ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty)
+    } else {
+        bare_fn_ty
+    };
+
+    // Check if we already trans'd this shim.
+    match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
         Some(&llval) => { return llval; }
         None => { }
     }
@@ -279,9 +294,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     debug!("trans_fn_pointer_shim(bare_fn_ty={})",
            bare_fn_ty.repr(tcx));
 
-    // This is an impl of `Fn` trait, so receiver is `&self`.
-    let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty);
-
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
     let (opt_def_id, sig) =
@@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
                                          unsafety: ast::Unsafety::Normal,
                                          abi: synabi::RustCall,
                                          sig: ty::Binder(ty::FnSig {
-                                             inputs: vec![bare_fn_ty_ref,
+                                             inputs: vec![bare_fn_ty_maybe_ref,
                                                           tuple_input_ty],
                                              output: sig.output,
                                              variadic: false
@@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let mut bcx = init_function(&fcx, false, sig.output);
 
     // the first argument (`self`) will be ptr to the the fn pointer
-    let llfnpointer =
-        Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
+    let llfnpointer = if is_by_ref {
+        Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32))
+    } else {
+        get_param(fcx.llfn, fcx.arg_pos(0) as u32)
+    };
 
     // the remaining arguments will be the untupled values
     let llargs: Vec<_> =
@@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
 
-    ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
+    ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
 
     llfn
 }
index c1bc7219ad8253942eb826dcdbbc22aa739ac9b4..5a48b8e4bce1d37acb4ae77844ff80a2e674c864 100644 (file)
@@ -8,24 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use back::link::mangle_internal_name_by_path_and_seq;
-use llvm::ValueRef;
+use arena::TypedArena;
+use back::link::{self, mangle_internal_name_by_path_and_seq};
+use llvm::{ValueRef, get_param};
 use middle::mem_categorization::Typer;
 use trans::adt;
 use trans::base::*;
 use trans::build::*;
-use trans::cleanup::{CleanupMethods, ScopeId};
+use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
+use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
 use trans::common::*;
-use trans::datum::{Datum, rvalue_scratch_datum};
-use trans::datum::{Rvalue, ByValue};
-use trans::debuginfo;
+use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue};
+use trans::debuginfo::{self, DebugLoc};
 use trans::expr;
 use trans::monomorphize::{self, MonoId};
 use trans::type_of::*;
 use middle::ty::{self, ClosureTyper};
 use middle::subst::{Substs};
 use session::config::FullDebugInfo;
+use util::ppaux::Repr;
 
+use syntax::abi::RustCall;
 use syntax::ast;
 use syntax::ast_util;
 
@@ -239,11 +242,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
     // Create the closure.
     for (i, freevar) in freevars.iter().enumerate() {
         let datum = expr::trans_local_var(bcx, freevar.def);
-        let upvar_slot_dest = adt::trans_field_ptr(bcx,
-                                                   &*repr,
-                                                   dest_addr,
-                                                   0,
-                                                   i);
+        let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i);
         let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
                                      closure_expr_id: id };
         match tcx.upvar_capture(upvar_id).unwrap() {
@@ -259,3 +258,186 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
 
     Some(bcx)
 }
+
+pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
+                                      closure_def_id: ast::DefId,
+                                      substs: Substs<'tcx>,
+                                      node: ExprOrMethodCall,
+                                      param_substs: &'tcx Substs<'tcx>,
+                                      trait_closure_kind: ty::ClosureKind)
+                                      -> ValueRef
+{
+    // The substitutions should have no type parameters remaining
+    // after passing through fulfill_obligation
+    let llfn = callee::trans_fn_ref_with_substs(ccx,
+                                                closure_def_id,
+                                                node,
+                                                param_substs,
+                                                substs.clone()).val;
+
+    // If the closure is a Fn closure, but a FnOnce is needed (etc),
+    // then adapt the self type
+    let closure_kind = ccx.tcx().closure_kind(closure_def_id);
+    trans_closure_adapter_shim(ccx,
+                               closure_def_id,
+                               substs,
+                               closure_kind,
+                               trait_closure_kind,
+                               llfn)
+}
+
+fn trans_closure_adapter_shim<'a, 'tcx>(
+    ccx: &'a CrateContext<'a, 'tcx>,
+    closure_def_id: ast::DefId,
+    substs: Substs<'tcx>,
+    llfn_closure_kind: ty::ClosureKind,
+    trait_closure_kind: ty::ClosureKind,
+    llfn: ValueRef)
+    -> ValueRef
+{
+    let _icx = push_ctxt("trans_closure_adapter_shim");
+    let tcx = ccx.tcx();
+
+    debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
+           trait_closure_kind={:?}, \
+           llfn={})",
+           llfn_closure_kind,
+           trait_closure_kind,
+           ccx.tn().val_to_string(llfn));
+
+    match (llfn_closure_kind, trait_closure_kind) {
+        (ty::FnClosureKind, ty::FnClosureKind) |
+        (ty::FnMutClosureKind, ty::FnMutClosureKind) |
+        (ty::FnOnceClosureKind, ty::FnOnceClosureKind) => {
+            // No adapter needed.
+            llfn
+        }
+        (ty::FnClosureKind, ty::FnMutClosureKind) => {
+            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
+            // `fn(&mut self, ...)`. In fact, at trans time, these are
+            // basically the same thing, so we can just return llfn.
+            llfn
+        }
+        (ty::FnClosureKind, ty::FnOnceClosureKind) |
+        (ty::FnMutClosureKind, ty::FnOnceClosureKind) => {
+            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
+            // self, ...)`.  We want a `fn(self, ...)`. We can produce
+            // this by doing something like:
+            //
+            //     fn call_once(self, ...) { call_mut(&self, ...) }
+            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
+            //
+            // These are both the same at trans time.
+            trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
+        }
+        _ => {
+            tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
+                                  llfn_closure_kind,
+                                  trait_closure_kind));
+        }
+    }
+}
+
+fn trans_fn_once_adapter_shim<'a, 'tcx>(
+    ccx: &'a CrateContext<'a, 'tcx>,
+    closure_def_id: ast::DefId,
+    substs: Substs<'tcx>,
+    llreffn: ValueRef)
+    -> ValueRef
+{
+    debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})",
+           closure_def_id.repr(ccx.tcx()),
+           substs.repr(ccx.tcx()),
+           ccx.tn().val_to_string(llreffn));
+
+    let tcx = ccx.tcx();
+    let typer = NormalizingClosureTyper::new(tcx);
+
+    // Find a version of the closure type. Substitute static for the
+    // region since it doesn't really matter.
+    let substs = tcx.mk_substs(substs);
+    let closure_ty = ty::mk_closure(tcx, closure_def_id, substs);
+    let ref_closure_ty = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), closure_ty);
+
+    // Make a version with the type of by-ref closure.
+    let ty::ClosureTy { unsafety, abi, mut sig } = typer.closure_type(closure_def_id, substs);
+    sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
+    let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
+                                                               abi: abi,
+                                                               sig: sig.clone() });
+    let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty);
+    debug!("trans_fn_once_adapter_shim: llref_fn_ty={}",
+           llref_fn_ty.repr(tcx));
+
+    // Make a version of the closure type with the same arguments, but
+    // with argument #0 being by value.
+    assert_eq!(abi, RustCall);
+    sig.0.inputs[0] = closure_ty;
+    let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
+                                                                abi: abi,
+                                                                sig: sig });
+    let llonce_fn_ty = ty::mk_bare_fn(tcx, None, llonce_bare_fn_ty);
+
+    // Create the by-value helper.
+    let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
+    let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name);
+
+    let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig);
+    let (block_arena, fcx): (TypedArena<_>, FunctionContext);
+    block_arena = TypedArena::new();
+    fcx = new_fn_ctxt(ccx,
+                      lloncefn,
+                      ast::DUMMY_NODE_ID,
+                      false,
+                      sig.output,
+                      substs,
+                      None,
+                      &block_arena);
+    let mut bcx = init_function(&fcx, false, sig.output);
+
+    // the first argument (`self`) will be the (by value) closure env.
+    let self_scope = fcx.push_custom_cleanup_scope();
+    let self_scope_id = CustomScope(self_scope);
+    let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty);
+    let llself = get_param(lloncefn, fcx.arg_pos(0) as u32);
+    let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode));
+    let env_datum = unpack_datum!(bcx,
+                                  env_datum.to_lvalue_datum_in_scope(bcx, "self",
+                                                                     self_scope_id));
+
+    debug!("trans_fn_once_adapter_shim: env_datum={}",
+           bcx.val_to_string(env_datum.val));
+
+    // the remaining arguments will be packed up in a tuple.
+    let input_tys = match sig.inputs[1].sty {
+        ty::ty_tup(ref tys) => &**tys,
+        _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \
+                                      closure_def_id={}",
+                                     closure_def_id.repr(tcx)))
+    };
+    let llargs: Vec<_> =
+        input_tys.iter()
+                 .enumerate()
+                 .map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32))
+                 .collect();
+
+    let dest =
+        fcx.llretslotptr.get().map(
+            |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
+
+    let callee_data = TraitItem(MethodData { llfn: llreffn,
+                                             llself: env_datum.val });
+
+    bcx = callee::trans_call_inner(bcx,
+                                   DebugLoc::None,
+                                   llref_fn_ty,
+                                   |bcx, _| Callee { bcx: bcx, data: callee_data },
+                                   ArgVals(&llargs),
+                                   dest).bcx;
+
+    fcx.pop_custom_cleanup_scope(self_scope);
+
+    finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
+
+    lloncefn
+}
index 4da17972c55fb68e4eda4207eb20911b0c67374c..aa038f8ddca3148d51e15f047d2daeab516ab4f4 100644 (file)
 use middle::subst::VecPerParamSpace;
 use middle::subst;
 use middle::traits;
+use middle::ty::ClosureTyper;
 use trans::base::*;
 use trans::build::*;
 use trans::callee::*;
 use trans::callee;
 use trans::cleanup;
+use trans::closure;
 use trans::common::*;
 use trans::consts;
 use trans::datum::*;
@@ -358,19 +360,21 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         traits::VtableClosure(closure_def_id, substs) => {
             // The substitutions should have no type parameters remaining
             // after passing through fulfill_obligation
-            let llfn = trans_fn_ref_with_substs(bcx.ccx(),
-                                                closure_def_id,
-                                                MethodCallKey(method_call),
-                                                bcx.fcx.param_substs,
-                                                substs).val;
-
+            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = closure::trans_closure_method(bcx.ccx(),
+                                                     closure_def_id,
+                                                     substs,
+                                                     MethodCallKey(method_call),
+                                                     bcx.fcx.param_substs,
+                                                     trait_closure_kind);
             Callee {
                 bcx: bcx,
                 data: Fn(llfn),
             }
         }
         traits::VtableFnPointer(fn_ty) => {
-            let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
+            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
             Callee { bcx: bcx, data: Fn(llfn) }
         }
         traits::VtableObject(ref data) => {
@@ -645,9 +649,6 @@ pub fn trans_object_shim<'a, 'tcx>(
 
     assert!(!fcx.needs_ret_allocas);
 
-    let sig =
-        ty::erase_late_bound_regions(bcx.tcx(), &fty.sig);
-
     let dest =
         fcx.llretslotptr.get().map(
             |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
@@ -714,17 +715,18 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
             }
             traits::VtableClosure(closure_def_id, substs) => {
-                let llfn = trans_fn_ref_with_substs(
-                    ccx,
-                    closure_def_id,
-                    ExprId(0),
-                    param_substs,
-                    substs).val;
-
+                let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
+                let llfn = closure::trans_closure_method(ccx,
+                                                         closure_def_id,
+                                                         substs,
+                                                         ExprId(0),
+                                                         param_substs,
+                                                         trait_closure_kind);
                 vec![llfn].into_iter()
             }
             traits::VtableFnPointer(bare_fn_ty) => {
-                vec![trans_fn_pointer_shim(ccx, bare_fn_ty)].into_iter()
+                let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
+                vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
             }
             traits::VtableObject(ref data) => {
                 // this would imply that the Self type being erased is
index 28e7027b2124a2e2135e7d0b4007851de08b46ff..4f06346fb45cc53d199b91969504693fa6e6d4da 100644 (file)
@@ -55,7 +55,7 @@
 use middle::privacy::{AllPublic, LastMod};
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::traits;
-use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty::{self, RegionEscape, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
@@ -608,24 +608,16 @@ pub fn instantiate_poly_trait_ref<'tcx>(
     poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
     -> ty::PolyTraitRef<'tcx>
 {
-    let mut projections = Vec::new();
-
-    // The trait reference introduces a binding level here, so
-    // we need to shift the `rscope`. It'd be nice if we could
-    // do away with this rscope stuff and work this knowledge
-    // into resolve_lifetimes, as we do with non-omitted
-    // lifetimes. Oh well, not there yet.
-    let shifted_rscope = ShiftedRscope::new(rscope);
-
-    let trait_ref = instantiate_trait_ref(this, &shifted_rscope,
-                                          &ast_trait_ref.trait_ref,
-                                          None, self_ty, Some(&mut projections));
-
-    for projection in projections {
-        poly_projections.push(ty::Binder(projection));
-    }
-
-    ty::Binder(trait_ref)
+    let trait_ref = &ast_trait_ref.trait_ref;
+    let trait_def_id = trait_def_id(this, trait_ref);
+    ast_path_to_poly_trait_ref(this,
+                               rscope,
+                               trait_ref.path.span,
+                               PathParamMode::Explicit,
+                               trait_def_id,
+                               self_ty,
+                               trait_ref.path.segments.last().unwrap(),
+                               poly_projections)
 }
 
 /// Instantiates the path for the given trait reference, assuming that it's
@@ -634,31 +626,27 @@ pub fn instantiate_poly_trait_ref<'tcx>(
 ///
 /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
 /// are disallowed. Otherwise, they are pushed onto the vector given.
-pub fn instantiate_trait_ref<'tcx>(
+pub fn instantiate_mono_trait_ref<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
     trait_ref: &ast::TraitRef,
-    impl_id: Option<ast::NodeId>,
-    self_ty: Option<Ty<'tcx>>,
-    projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
+    self_ty: Option<Ty<'tcx>>)
     -> Rc<ty::TraitRef<'tcx>>
 {
+    let trait_def_id = trait_def_id(this, trait_ref);
+    ast_path_to_mono_trait_ref(this,
+                               rscope,
+                               trait_ref.path.span,
+                               PathParamMode::Explicit,
+                               trait_def_id,
+                               self_ty,
+                               trait_ref.path.segments.last().unwrap())
+}
+
+fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId {
     let path = &trait_ref.path;
     match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
-        def::DefTrait(trait_def_id) => {
-            let trait_ref = ast_path_to_trait_ref(this,
-                                                  rscope,
-                                                  path.span,
-                                                  PathParamMode::Explicit,
-                                                  trait_def_id,
-                                                  self_ty,
-                                                  path.segments.last().unwrap(),
-                                                  projections);
-            if let Some(id) = impl_id {
-                this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone());
-            }
-            trait_ref
-        }
+        def::DefTrait(trait_def_id) => trait_def_id,
         _ => {
             span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
                         path.user_string(this.tcx()));
@@ -676,24 +664,17 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
     mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
     -> ty::PolyTraitRef<'tcx>
 {
-    // we are introducing a binder here, so shift the
-    // anonymous regions depth to account for that
-    let shifted_rscope = ShiftedRscope::new(rscope);
-
-    let mut tmp = Vec::new();
-    let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
-                                                     &shifted_rscope,
-                                                     span,
-                                                     param_mode,
-                                                     trait_def_id,
-                                                     None,
-                                                     trait_segment,
-                                                     Some(&mut tmp)));
-    projections.extend(tmp.into_iter().map(ty::Binder));
-    trait_ref
+    ast_path_to_poly_trait_ref(this,
+                               rscope,
+                               span,
+                               param_mode,
+                               trait_def_id,
+                               None,
+                               trait_segment,
+                               projections)
 }
 
-fn ast_path_to_trait_ref<'a,'tcx>(
+fn ast_path_to_poly_trait_ref<'a,'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
     span: Span,
@@ -701,10 +682,78 @@ fn ast_path_to_trait_ref<'a,'tcx>(
     trait_def_id: ast::DefId,
     self_ty: Option<Ty<'tcx>>,
     trait_segment: &ast::PathSegment,
-    mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
-    -> Rc<ty::TraitRef<'tcx>>
+    poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+    -> ty::PolyTraitRef<'tcx>
+{
+    // The trait reference introduces a binding level here, so
+    // we need to shift the `rscope`. It'd be nice if we could
+    // do away with this rscope stuff and work this knowledge
+    // into resolve_lifetimes, as we do with non-omitted
+    // lifetimes. Oh well, not there yet.
+    let shifted_rscope = &ShiftedRscope::new(rscope);
+
+    let (substs, assoc_bindings) =
+        create_substs_for_ast_trait_ref(this,
+                                        shifted_rscope,
+                                        span,
+                                        param_mode,
+                                        trait_def_id,
+                                        self_ty,
+                                        trait_segment);
+    let poly_trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_def_id, substs)));
+
+    {
+        let converted_bindings =
+            assoc_bindings
+            .iter()
+            .filter_map(|binding| {
+                // specify type to assert that error was already reported in Err case:
+                let predicate: Result<_, ErrorReported> =
+                    ast_type_binding_to_poly_projection_predicate(this,
+                                                                  poly_trait_ref.clone(),
+                                                                  self_ty,
+                                                                  binding);
+                predicate.ok() // ok to ignore Err() because ErrorReported (see above)
+            });
+        poly_projections.extend(converted_bindings);
+    }
+
+    poly_trait_ref
+}
+
+fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
+                                       rscope: &RegionScope,
+                                       span: Span,
+                                       param_mode: PathParamMode,
+                                       trait_def_id: ast::DefId,
+                                       self_ty: Option<Ty<'tcx>>,
+                                       trait_segment: &ast::PathSegment)
+                                       -> Rc<ty::TraitRef<'tcx>>
 {
-    debug!("ast_path_to_trait_ref {:?}", trait_segment);
+    let (substs, assoc_bindings) =
+        create_substs_for_ast_trait_ref(this,
+                                        rscope,
+                                        span,
+                                        param_mode,
+                                        trait_def_id,
+                                        self_ty,
+                                        trait_segment);
+    prohibit_projections(this.tcx(), &assoc_bindings);
+    Rc::new(ty::TraitRef::new(trait_def_id, substs))
+}
+
+fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
+                                            rscope: &RegionScope,
+                                            span: Span,
+                                            param_mode: PathParamMode,
+                                            trait_def_id: ast::DefId,
+                                            self_ty: Option<Ty<'tcx>>,
+                                            trait_segment: &ast::PathSegment)
+                                            -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
+{
+    debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
+           trait_segment);
+
     let trait_def = match this.get_trait_def(span, trait_def_id) {
         Ok(trait_def) => trait_def,
         Err(ErrorReported) => {
@@ -752,34 +801,16 @@ fn ast_path_to_trait_ref<'a,'tcx>(
                                             self_ty,
                                             types,
                                             regions);
-    let substs = this.tcx().mk_substs(substs);
 
-    let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
-
-    match projections {
-        None => {
-            prohibit_projections(this.tcx(), &assoc_bindings);
-        }
-        Some(ref mut v) => {
-            for binding in &assoc_bindings {
-                match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
-                                                               self_ty, binding) {
-                    Ok(pp) => { v.push(pp); }
-                    Err(ErrorReported) => { }
-                }
-            }
-        }
-    }
-
-    trait_ref
+    (this.tcx().mk_substs(substs), assoc_bindings)
 }
 
-fn ast_type_binding_to_projection_predicate<'tcx>(
+fn ast_type_binding_to_poly_projection_predicate<'tcx>(
     this: &AstConv<'tcx>,
-    mut trait_ref: Rc<ty::TraitRef<'tcx>>,
+    mut trait_ref: ty::PolyTraitRef<'tcx>,
     self_ty: Option<Ty<'tcx>>,
     binding: &ConvertedBinding<'tcx>)
-    -> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
+    -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
 {
     let tcx = this.tcx();
 
@@ -800,14 +831,14 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
     // We want to produce `<B as SuperTrait<int>>::T == foo`.
 
     // Simple case: X is defined in the current trait.
-    if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) {
-        return Ok(ty::ProjectionPredicate {
-            projection_ty: ty::ProjectionTy {
-                trait_ref: trait_ref,
+    if this.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
+        return Ok(ty::Binder(ty::ProjectionPredicate {      // <-------------------+
+            projection_ty: ty::ProjectionTy {               //                     |
+                trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+
                 item_name: binding.item_name,
             },
             ty: binding.ty,
-        });
+        }));
     }
 
     // Otherwise, we have to walk through the supertraits to find
@@ -820,17 +851,17 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
 
     let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
     if self_ty.is_none() { // if converting for an object type
-        let mut dummy_substs = trait_ref.substs.clone();
-        assert!(dummy_substs.self_ty().is_none());
-        dummy_substs.types.push(SelfSpace, dummy_self_ty);
-        trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
-                                              tcx.mk_substs(dummy_substs)));
+        let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+
+        assert!(dummy_substs.self_ty().is_none());                     //                    |
+        dummy_substs.types.push(SelfSpace, dummy_self_ty);             //                    |
+        trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_ref.def_id(), // <------------+
+                                                         tcx.mk_substs(dummy_substs))));
     }
 
-    try!(this.ensure_super_predicates(binding.span, trait_ref.def_id));
+    try!(this.ensure_super_predicates(binding.span, trait_ref.def_id()));
 
     let mut candidates: Vec<ty::PolyTraitRef> =
-        traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
+        traits::supertraits(tcx, trait_ref.clone())
         .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
         .collect();
 
@@ -865,21 +896,13 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
         }
     };
 
-    if ty::binds_late_bound_regions(tcx, &candidate) {
-        span_err!(tcx.sess, binding.span, E0219,
-            "associated type `{}` defined in higher-ranked supertrait `{}`",
-                    token::get_name(binding.item_name),
-                    candidate.user_string(tcx));
-        return Err(ErrorReported);
-    }
-
-    Ok(ty::ProjectionPredicate {
-        projection_ty: ty::ProjectionTy {
-            trait_ref: candidate.0,
+    Ok(ty::Binder(ty::ProjectionPredicate {             // <-------------------------+
+        projection_ty: ty::ProjectionTy {               //                           |
+            trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+
             item_name: binding.item_name,
         },
         ty: binding.ty,
-    })
+    }))
 }
 
 fn ast_path_to_ty<'tcx>(
@@ -1134,14 +1157,14 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
 
-    let trait_ref = ast_path_to_trait_ref(this,
-                                          rscope,
-                                          span,
-                                          param_mode,
-                                          trait_def_id,
-                                          Some(self_ty),
-                                          trait_segment,
-                                          None);
+    let trait_ref =
+        ast_path_to_mono_trait_ref(this,
+                                   rscope,
+                                   span,
+                                   param_mode,
+                                   trait_def_id,
+                                   Some(self_ty),
+                                   trait_segment);
 
     debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
 
index 32f91a175f3c3eed8d9eb73355aea543127124a8..d2a06fcf9909138d1a1b354350c9dc1ea903b5ce 100644 (file)
@@ -16,6 +16,7 @@
 use middle::region;
 use middle::subst;
 use middle::ty::{self, ToPolyTraitRef, Ty};
+use std::cmp;
 use syntax::abi;
 use syntax::ast;
 use syntax::ast_util;
@@ -109,15 +110,11 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
         ty::ty_trait(ref object_type) => {
             let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
                                                                          fcx.tcx().types.err);
-            let expectations =
-                proj_bounds.iter()
-                           .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
-                           .next();
-
-            match expectations {
-                Some((sig, kind)) => (Some(sig), Some(kind)),
-                None => (None, None)
-            }
+            let sig = proj_bounds.iter()
+                                 .filter_map(|pb| deduce_sig_from_projection(fcx, pb))
+                                 .next();
+            let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
+            (sig, kind)
         }
         ty::ty_infer(ty::TyVar(vid)) => {
             deduce_expectations_from_obligations(fcx, vid)
@@ -136,7 +133,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
     let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
     // Here `expected_ty` is known to be a type inference variable.
 
-    let expected_sig_and_kind =
+    let expected_sig =
         fulfillment_cx
         .pending_obligations()
         .iter()
@@ -150,7 +147,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 ty::Predicate::Projection(ref proj_predicate) => {
                     let trait_ref = proj_predicate.to_poly_trait_ref();
                     self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
-                        .and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
+                        .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate))
                 }
                 _ => {
                     None
@@ -159,14 +156,10 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
         })
         .next();
 
-    match expected_sig_and_kind {
-        Some((sig, kind)) => { return (Some(sig), Some(kind)); }
-        None => { }
-    }
-
     // Even if we can't infer the full signature, we may be able to
     // infer the kind. This can occur if there is a trait-reference
-    // like `F : Fn<A>`.
+    // like `F : Fn<A>`. Note that due to subtyping we could encounter
+    // many viable options, so pick the most restrictive.
     let expected_kind =
         fulfillment_cx
         .pending_obligations()
@@ -183,54 +176,61 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
                 .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
         })
-        .next();
+        .fold(None, pick_most_restrictive_closure_kind);
+
+    (expected_sig, expected_kind)
+}
 
-    (None, expected_kind)
+fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
+                                      cur: ty::ClosureKind)
+                                      -> Option<ty::ClosureKind>
+{
+    match best {
+        None => Some(cur),
+        Some(best) => Some(cmp::min(best, cur))
+    }
 }
 
 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
 /// everything we need to know about a closure.
-fn deduce_expectations_from_projection<'a,'tcx>(
+fn deduce_sig_from_projection<'a,'tcx>(
     fcx: &FnCtxt<'a,'tcx>,
     projection: &ty::PolyProjectionPredicate<'tcx>)
-    -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
+    -> Option<ty::FnSig<'tcx>>
 {
     let tcx = fcx.tcx();
 
-    debug!("deduce_expectations_from_projection({})",
+    debug!("deduce_sig_from_projection({})",
            projection.repr(tcx));
 
     let trait_ref = projection.to_poly_trait_ref();
 
-    let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
-        Some(k) => k,
-        None => { return None; }
-    };
-
-    debug!("found object type {:?}", kind);
+    if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
+        return None;
+    }
 
     let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
     let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
-    debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
+    debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx));
 
     let input_tys = match arg_param_ty.sty {
         ty::ty_tup(ref tys) => { (*tys).clone() }
         _ => { return None; }
     };
-    debug!("input_tys {}", input_tys.repr(tcx));
+    debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx));
 
     let ret_param_ty = projection.0.ty;
     let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
-    debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
+    debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx));
 
     let fn_sig = ty::FnSig {
         inputs: input_tys,
         output: ty::FnConverging(ret_param_ty),
         variadic: false
     };
-    debug!("fn_sig {}", fn_sig.repr(tcx));
+    debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx));
 
-    return Some((fn_sig, kind));
+    Some(fn_sig)
 }
 
 fn self_type_matches_expected_vid<'a,'tcx>(
index bc581a6af4154c516b2279fb0079a5e02e412243..b95e0ce8cb3c59e512d65101884e5fbd1d9b1697 100644 (file)
@@ -725,7 +725,7 @@ fn assemble_closure_candidates(&mut self,
             };
 
             // this closure doesn't implement the right kind of `Fn` trait
-            if closure_kind != kind {
+            if !closure_kind.extends(kind) {
                 continue;
             }
 
index 97cc3ac7c48a78aa2a79c1051be851fbf0e93b5e..8744df0e20249dd61aa3fefb43a26fd1024dd93e 100644 (file)
@@ -784,14 +784,15 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                                    &enum_definition.variants);
         },
         ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
-            let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()),
-                                                           &ExplicitRscope,
-                                                           ast_trait_ref,
-                                                           Some(it.id),
-                                                           None,
-                                                           None);
+            let trait_ref =
+                astconv::instantiate_mono_trait_ref(&ccx.icx(&()),
+                                                    &ExplicitRscope,
+                                                    ast_trait_ref,
+                                                    None);
 
             ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
+
+            tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
         }
         ast::ItemImpl(_, _,
                       ref generics,
@@ -890,13 +891,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                 }
             }
 
-            if let Some(ref trait_ref) = *opt_trait_ref {
-                astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates),
-                                               &ExplicitRscope,
-                                               trait_ref,
-                                               Some(it.id),
-                                               Some(selfty),
-                                               None);
+            if let Some(ref ast_trait_ref) = *opt_trait_ref {
+                let trait_ref =
+                    astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
+                                                        &ExplicitRscope,
+                                                        ast_trait_ref,
+                                                        Some(selfty));
+
+                tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
             }
 
             enforce_impl_ty_params_are_constrained(tcx,