Make the Fn
traits inherit from one another and remove the bridging
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.
This commit is contained in:
parent
b0aad7dd4f
commit
37601131a0
@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
|
||||
#[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 @@ impl<F: ?Sized, A> FnMut<A> for F
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<F,A> FnOnce<A> for F
|
||||
where F : FnMut<A>
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
|
||||
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 @@ delegate_iter!{exact u8 : Bytes<'a>}
|
||||
#[derive(Copy, Clone)]
|
||||
struct BytesDeref;
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||
type Output = u8;
|
||||
|
||||
@ -533,6 +534,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -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);
|
||||
|
@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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(());
|
||||
}
|
||||
|
||||
|
@ -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 @@ impl ClosureKind {
|
||||
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> {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -17,11 +17,13 @@ use middle::subst::Substs;
|
||||
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(),
|
||||
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,
|
||||
substs).val;
|
||||
|
||||
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,
|
||||
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,
|
||||
substs).val;
|
||||
|
||||
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
|
||||
|
@ -55,7 +55,7 @@ use middle::resolve_lifetime as rl;
|
||||
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 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,
|
||||
let trait_def_id = trait_def_id(this, trait_ref);
|
||||
ast_path_to_mono_trait_ref(this,
|
||||
rscope,
|
||||
path.span,
|
||||
trait_ref.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
|
||||
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) => 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,
|
||||
ast_path_to_poly_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
None,
|
||||
trait_segment,
|
||||
Some(&mut tmp)));
|
||||
projections.extend(tmp.into_iter().map(ty::Binder));
|
||||
trait_ref
|
||||
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>>>)
|
||||
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) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
(this.tcx().mk_substs(substs), assoc_bindings)
|
||||
}
|
||||
|
||||
trait_ref
|
||||
}
|
||||
|
||||
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,
|
||||
let trait_ref =
|
||||
ast_path_to_mono_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
Some(self_ty),
|
||||
trait_segment,
|
||||
None);
|
||||
trait_segment);
|
||||
|
||||
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
|
||||
|
||||
|
@ -16,6 +16,7 @@ use astconv;
|
||||
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))
|
||||
let sig = proj_bounds.iter()
|
||||
.filter_map(|pb| deduce_sig_from_projection(fcx, pb))
|
||||
.next();
|
||||
|
||||
match expectations {
|
||||
Some((sig, kind)) => (Some(sig), Some(kind)),
|
||||
None => (None, None)
|
||||
}
|
||||
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);
|
||||
|
||||
(None, expected_kind)
|
||||
(expected_sig, 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>(
|
||||
|
@ -725,7 +725,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
};
|
||||
|
||||
// this closure doesn't implement the right kind of `Fn` trait
|
||||
if closure_kind != kind {
|
||||
if !closure_kind.extends(kind) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -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(&()),
|
||||
let trait_ref =
|
||||
astconv::instantiate_mono_trait_ref(&ccx.icx(&()),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
Some(it.id),
|
||||
None,
|
||||
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),
|
||||
if let Some(ref ast_trait_ref) = *opt_trait_ref {
|
||||
let trait_ref =
|
||||
astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
|
||||
&ExplicitRscope,
|
||||
trait_ref,
|
||||
Some(it.id),
|
||||
Some(selfty),
|
||||
None);
|
||||
ast_trait_ref,
|
||||
Some(selfty));
|
||||
|
||||
tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
|
||||
}
|
||||
|
||||
enforce_impl_ty_params_are_constrained(tcx,
|
||||
|
Loading…
x
Reference in New Issue
Block a user