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
12 changed files with 495 additions and 202 deletions
|
@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
|
||||||
#[lang="fn"]
|
#[lang="fn"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_paren_sugar]
|
#[rustc_paren_sugar]
|
||||||
|
#[cfg(stage0)]
|
||||||
pub trait Fn<Args> {
|
pub trait Fn<Args> {
|
||||||
/// The returned type after the call operator is used.
|
/// The returned type after the call operator is used.
|
||||||
type Output;
|
type Output;
|
||||||
|
@ -1144,10 +1145,21 @@ pub trait Fn<Args> {
|
||||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
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.
|
/// A version of the call operator that takes a mutable receiver.
|
||||||
#[lang="fn_mut"]
|
#[lang="fn_mut"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_paren_sugar]
|
#[rustc_paren_sugar]
|
||||||
|
#[cfg(stage0)]
|
||||||
pub trait FnMut<Args> {
|
pub trait FnMut<Args> {
|
||||||
/// The returned type after the call operator is used.
|
/// The returned type after the call operator is used.
|
||||||
type Output;
|
type Output;
|
||||||
|
@ -1156,6 +1168,16 @@ pub trait FnMut<Args> {
|
||||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
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.
|
/// A version of the call operator that takes a by-value receiver.
|
||||||
#[lang="fn_once"]
|
#[lang="fn_once"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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;
|
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
impl<F: ?Sized, A> FnMut<A> for F
|
impl<F: ?Sized, A> FnMut<A> for F
|
||||||
where F : Fn<A>
|
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
|
impl<F,A> FnOnce<A> for F
|
||||||
where F : FnMut<A>
|
where F : FnMut<A>
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
|
||||||
use marker::Sized;
|
use marker::Sized;
|
||||||
use mem;
|
use mem;
|
||||||
use num::Int;
|
use num::Int;
|
||||||
use ops::{Fn, FnMut};
|
use ops::{Fn, FnMut, FnOnce};
|
||||||
use option::Option::{self, None, Some};
|
use option::Option::{self, None, Some};
|
||||||
use raw::{Repr, Slice};
|
use raw::{Repr, Slice};
|
||||||
use result::Result::{self, Ok, Err};
|
use result::Result::{self, Ok, Err};
|
||||||
|
@ -524,6 +524,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct BytesDeref;
|
struct BytesDeref;
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||||
type Output = u8;
|
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`.
|
/// An iterator over the substrings of a string, separated by `sep`.
|
||||||
struct CharSplits<'a, P: Pattern<'a>> {
|
struct CharSplits<'a, P: Pattern<'a>> {
|
||||||
/// The slice remaining to be iterated
|
/// The slice remaining to be iterated
|
||||||
|
|
|
@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>(
|
||||||
obligation.repr(tcx),
|
obligation.repr(tcx),
|
||||||
fn_sig.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)
|
// Note: we unwrap the binder here but re-create it below (1)
|
||||||
let ty::Binder((trait_ref, ret_type)) =
|
let ty::Binder((trait_ref, ret_type)) =
|
||||||
util::closure_trait_ref_and_return_type(tcx,
|
util::closure_trait_ref_and_return_type(tcx,
|
||||||
obligation.predicate.trait_ref.def_id,
|
fn_once_def_id,
|
||||||
obligation.predicate.trait_ref.self_ty(),
|
obligation.predicate.trait_ref.self_ty(),
|
||||||
fn_sig,
|
fn_sig,
|
||||||
flag);
|
flag);
|
||||||
|
|
|
@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
match self.closure_typer.closure_kind(closure_def_id) {
|
match self.closure_typer.closure_kind(closure_def_id) {
|
||||||
Some(closure_kind) => {
|
Some(closure_kind) => {
|
||||||
debug!("assemble_unboxed_candidates: closure_kind = {:?}", 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()));
|
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1090,10 +1090,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||||
-> Result<(),SelectionError<'tcx>>
|
-> Result<(),SelectionError<'tcx>>
|
||||||
{
|
{
|
||||||
// We provide a `Fn` impl for fn pointers. There is no need to provide
|
// We provide impl of all fn traits for fn pointers.
|
||||||
// the other traits (e.g. `FnMut`) since those are provided by blanket
|
if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
|
||||||
// impls.
|
|
||||||
if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> {
|
||||||
pub substs: Substs<'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 {
|
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,
|
FnClosureKind,
|
||||||
FnMutClosureKind,
|
FnMutClosureKind,
|
||||||
FnOnceClosureKind,
|
FnOnceClosureKind,
|
||||||
|
@ -2484,6 +2487,20 @@ impl ClosureKind {
|
||||||
Err(err) => cx.sess.fatal(&err[..]),
|
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> {
|
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.
|
/// but for the bare function type given.
|
||||||
pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
ccx: &'a CrateContext<'a, 'tcx>,
|
ccx: &'a CrateContext<'a, 'tcx>,
|
||||||
|
closure_kind: ty::ClosureKind,
|
||||||
bare_fn_ty: Ty<'tcx>)
|
bare_fn_ty: Ty<'tcx>)
|
||||||
-> ValueRef
|
-> ValueRef
|
||||||
{
|
{
|
||||||
let _icx = push_ctxt("trans_fn_pointer_shim");
|
let _icx = push_ctxt("trans_fn_pointer_shim");
|
||||||
let tcx = ccx.tcx();
|
let tcx = ccx.tcx();
|
||||||
|
|
||||||
|
// Normalize the type for better caching.
|
||||||
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
|
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; }
|
Some(&llval) => { return llval; }
|
||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
@ -279,9 +294,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
debug!("trans_fn_pointer_shim(bare_fn_ty={})",
|
debug!("trans_fn_pointer_shim(bare_fn_ty={})",
|
||||||
bare_fn_ty.repr(tcx));
|
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`,
|
// 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.
|
// which is the fn pointer, and `args`, which is the arguments tuple.
|
||||||
let (opt_def_id, sig) =
|
let (opt_def_id, sig) =
|
||||||
|
@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
unsafety: ast::Unsafety::Normal,
|
unsafety: ast::Unsafety::Normal,
|
||||||
abi: synabi::RustCall,
|
abi: synabi::RustCall,
|
||||||
sig: ty::Binder(ty::FnSig {
|
sig: ty::Binder(ty::FnSig {
|
||||||
inputs: vec![bare_fn_ty_ref,
|
inputs: vec![bare_fn_ty_maybe_ref,
|
||||||
tuple_input_ty],
|
tuple_input_ty],
|
||||||
output: sig.output,
|
output: sig.output,
|
||||||
variadic: false
|
variadic: false
|
||||||
|
@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
let mut bcx = init_function(&fcx, false, sig.output);
|
let mut bcx = init_function(&fcx, false, sig.output);
|
||||||
|
|
||||||
// the first argument (`self`) will be ptr to the the fn pointer
|
// the first argument (`self`) will be ptr to the the fn pointer
|
||||||
let llfnpointer =
|
let llfnpointer = if is_by_ref {
|
||||||
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
|
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
|
// the remaining arguments will be the untupled values
|
||||||
let llargs: Vec<_> =
|
let llargs: Vec<_> =
|
||||||
|
@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
|
|
||||||
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
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
|
llfn
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,24 +8,27 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use back::link::mangle_internal_name_by_path_and_seq;
|
use arena::TypedArena;
|
||||||
use llvm::ValueRef;
|
use back::link::{self, mangle_internal_name_by_path_and_seq};
|
||||||
|
use llvm::{ValueRef, get_param};
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use trans::adt;
|
use trans::adt;
|
||||||
use trans::base::*;
|
use trans::base::*;
|
||||||
use trans::build::*;
|
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::common::*;
|
||||||
use trans::datum::{Datum, rvalue_scratch_datum};
|
use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue};
|
||||||
use trans::datum::{Rvalue, ByValue};
|
use trans::debuginfo::{self, DebugLoc};
|
||||||
use trans::debuginfo;
|
|
||||||
use trans::expr;
|
use trans::expr;
|
||||||
use trans::monomorphize::{self, MonoId};
|
use trans::monomorphize::{self, MonoId};
|
||||||
use trans::type_of::*;
|
use trans::type_of::*;
|
||||||
use middle::ty::{self, ClosureTyper};
|
use middle::ty::{self, ClosureTyper};
|
||||||
use middle::subst::{Substs};
|
use middle::subst::{Substs};
|
||||||
use session::config::FullDebugInfo;
|
use session::config::FullDebugInfo;
|
||||||
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
use syntax::abi::RustCall;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_util;
|
use syntax::ast_util;
|
||||||
|
|
||||||
|
@ -239,11 +242,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||||
// Create the closure.
|
// Create the closure.
|
||||||
for (i, freevar) in freevars.iter().enumerate() {
|
for (i, freevar) in freevars.iter().enumerate() {
|
||||||
let datum = expr::trans_local_var(bcx, freevar.def);
|
let datum = expr::trans_local_var(bcx, freevar.def);
|
||||||
let upvar_slot_dest = adt::trans_field_ptr(bcx,
|
let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i);
|
||||||
&*repr,
|
|
||||||
dest_addr,
|
|
||||||
0,
|
|
||||||
i);
|
|
||||||
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
|
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
|
||||||
closure_expr_id: id };
|
closure_expr_id: id };
|
||||||
match tcx.upvar_capture(upvar_id).unwrap() {
|
match tcx.upvar_capture(upvar_id).unwrap() {
|
||||||
|
@ -259,3 +258,186 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||||
|
|
||||||
Some(bcx)
|
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::VecPerParamSpace;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
|
use middle::ty::ClosureTyper;
|
||||||
use trans::base::*;
|
use trans::base::*;
|
||||||
use trans::build::*;
|
use trans::build::*;
|
||||||
use trans::callee::*;
|
use trans::callee::*;
|
||||||
use trans::callee;
|
use trans::callee;
|
||||||
use trans::cleanup;
|
use trans::cleanup;
|
||||||
|
use trans::closure;
|
||||||
use trans::common::*;
|
use trans::common::*;
|
||||||
use trans::consts;
|
use trans::consts;
|
||||||
use trans::datum::*;
|
use trans::datum::*;
|
||||||
|
@ -358,19 +360,21 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
traits::VtableClosure(closure_def_id, substs) => {
|
traits::VtableClosure(closure_def_id, substs) => {
|
||||||
// The substitutions should have no type parameters remaining
|
// The substitutions should have no type parameters remaining
|
||||||
// after passing through fulfill_obligation
|
// 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();
|
||||||
closure_def_id,
|
let llfn = closure::trans_closure_method(bcx.ccx(),
|
||||||
MethodCallKey(method_call),
|
closure_def_id,
|
||||||
bcx.fcx.param_substs,
|
substs,
|
||||||
substs).val;
|
MethodCallKey(method_call),
|
||||||
|
bcx.fcx.param_substs,
|
||||||
|
trait_closure_kind);
|
||||||
Callee {
|
Callee {
|
||||||
bcx: bcx,
|
bcx: bcx,
|
||||||
data: Fn(llfn),
|
data: Fn(llfn),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
traits::VtableFnPointer(fn_ty) => {
|
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) }
|
Callee { bcx: bcx, data: Fn(llfn) }
|
||||||
}
|
}
|
||||||
traits::VtableObject(ref data) => {
|
traits::VtableObject(ref data) => {
|
||||||
|
@ -645,9 +649,6 @@ pub fn trans_object_shim<'a, 'tcx>(
|
||||||
|
|
||||||
assert!(!fcx.needs_ret_allocas);
|
assert!(!fcx.needs_ret_allocas);
|
||||||
|
|
||||||
let sig =
|
|
||||||
ty::erase_late_bound_regions(bcx.tcx(), &fty.sig);
|
|
||||||
|
|
||||||
let dest =
|
let dest =
|
||||||
fcx.llretslotptr.get().map(
|
fcx.llretslotptr.get().map(
|
||||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
|
|_| 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()
|
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
|
||||||
}
|
}
|
||||||
traits::VtableClosure(closure_def_id, substs) => {
|
traits::VtableClosure(closure_def_id, substs) => {
|
||||||
let llfn = trans_fn_ref_with_substs(
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
||||||
ccx,
|
let llfn = closure::trans_closure_method(ccx,
|
||||||
closure_def_id,
|
closure_def_id,
|
||||||
ExprId(0),
|
substs,
|
||||||
param_substs,
|
ExprId(0),
|
||||||
substs).val;
|
param_substs,
|
||||||
|
trait_closure_kind);
|
||||||
vec![llfn].into_iter()
|
vec![llfn].into_iter()
|
||||||
}
|
}
|
||||||
traits::VtableFnPointer(bare_fn_ty) => {
|
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) => {
|
traits::VtableObject(ref data) => {
|
||||||
// this would imply that the Self type being erased is
|
// 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::privacy::{AllPublic, LastMod};
|
||||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
use middle::ty::{self, RegionEscape, Ty};
|
||||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
|
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
|
||||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
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>>)
|
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||||
-> ty::PolyTraitRef<'tcx>
|
-> ty::PolyTraitRef<'tcx>
|
||||||
{
|
{
|
||||||
let mut projections = Vec::new();
|
let trait_ref = &ast_trait_ref.trait_ref;
|
||||||
|
let trait_def_id = trait_def_id(this, trait_ref);
|
||||||
// The trait reference introduces a binding level here, so
|
ast_path_to_poly_trait_ref(this,
|
||||||
// we need to shift the `rscope`. It'd be nice if we could
|
rscope,
|
||||||
// do away with this rscope stuff and work this knowledge
|
trait_ref.path.span,
|
||||||
// into resolve_lifetimes, as we do with non-omitted
|
PathParamMode::Explicit,
|
||||||
// lifetimes. Oh well, not there yet.
|
trait_def_id,
|
||||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
self_ty,
|
||||||
|
trait_ref.path.segments.last().unwrap(),
|
||||||
let trait_ref = instantiate_trait_ref(this, &shifted_rscope,
|
poly_projections)
|
||||||
&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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiates the path for the given trait reference, assuming that it's
|
/// 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>`
|
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
|
||||||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
/// 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>,
|
this: &AstConv<'tcx>,
|
||||||
rscope: &RegionScope,
|
rscope: &RegionScope,
|
||||||
trait_ref: &ast::TraitRef,
|
trait_ref: &ast::TraitRef,
|
||||||
impl_id: Option<ast::NodeId>,
|
self_ty: Option<Ty<'tcx>>)
|
||||||
self_ty: Option<Ty<'tcx>>,
|
|
||||||
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
|
||||||
-> Rc<ty::TraitRef<'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;
|
let path = &trait_ref.path;
|
||||||
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
|
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
|
||||||
def::DefTrait(trait_def_id) => {
|
def::DefTrait(trait_def_id) => 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
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
|
span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
|
||||||
path.user_string(this.tcx()));
|
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>>)
|
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||||
-> ty::PolyTraitRef<'tcx>
|
-> ty::PolyTraitRef<'tcx>
|
||||||
{
|
{
|
||||||
// we are introducing a binder here, so shift the
|
ast_path_to_poly_trait_ref(this,
|
||||||
// anonymous regions depth to account for that
|
rscope,
|
||||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
span,
|
||||||
|
param_mode,
|
||||||
let mut tmp = Vec::new();
|
trait_def_id,
|
||||||
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
|
None,
|
||||||
&shifted_rscope,
|
trait_segment,
|
||||||
span,
|
projections)
|
||||||
param_mode,
|
|
||||||
trait_def_id,
|
|
||||||
None,
|
|
||||||
trait_segment,
|
|
||||||
Some(&mut tmp)));
|
|
||||||
projections.extend(tmp.into_iter().map(ty::Binder));
|
|
||||||
trait_ref
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_path_to_trait_ref<'a,'tcx>(
|
fn ast_path_to_poly_trait_ref<'a,'tcx>(
|
||||||
this: &AstConv<'tcx>,
|
this: &AstConv<'tcx>,
|
||||||
rscope: &RegionScope,
|
rscope: &RegionScope,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -701,10 +682,78 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||||
trait_def_id: ast::DefId,
|
trait_def_id: ast::DefId,
|
||||||
self_ty: Option<Ty<'tcx>>,
|
self_ty: Option<Ty<'tcx>>,
|
||||||
trait_segment: &ast::PathSegment,
|
trait_segment: &ast::PathSegment,
|
||||||
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||||
-> Rc<ty::TraitRef<'tcx>>
|
-> ty::PolyTraitRef<'tcx>
|
||||||
{
|
{
|
||||||
debug!("ast_path_to_trait_ref {:?}", trait_segment);
|
// 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>>
|
||||||
|
{
|
||||||
|
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) {
|
let trait_def = match this.get_trait_def(span, trait_def_id) {
|
||||||
Ok(trait_def) => trait_def,
|
Ok(trait_def) => trait_def,
|
||||||
Err(ErrorReported) => {
|
Err(ErrorReported) => {
|
||||||
|
@ -752,34 +801,16 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||||
self_ty,
|
self_ty,
|
||||||
types,
|
types,
|
||||||
regions);
|
regions);
|
||||||
let substs = this.tcx().mk_substs(substs);
|
|
||||||
|
|
||||||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
|
(this.tcx().mk_substs(substs), assoc_bindings)
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_type_binding_to_projection_predicate<'tcx>(
|
fn ast_type_binding_to_poly_projection_predicate<'tcx>(
|
||||||
this: &AstConv<'tcx>,
|
this: &AstConv<'tcx>,
|
||||||
mut trait_ref: Rc<ty::TraitRef<'tcx>>,
|
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
self_ty: Option<Ty<'tcx>>,
|
self_ty: Option<Ty<'tcx>>,
|
||||||
binding: &ConvertedBinding<'tcx>)
|
binding: &ConvertedBinding<'tcx>)
|
||||||
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
|
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
|
||||||
{
|
{
|
||||||
let tcx = this.tcx();
|
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`.
|
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||||
|
|
||||||
// Simple case: X is defined in the current trait.
|
// Simple case: X is defined in the current trait.
|
||||||
if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) {
|
if this.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||||
return Ok(ty::ProjectionPredicate {
|
return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+
|
||||||
projection_ty: ty::ProjectionTy {
|
projection_ty: ty::ProjectionTy { // |
|
||||||
trait_ref: trait_ref,
|
trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+
|
||||||
item_name: binding.item_name,
|
item_name: binding.item_name,
|
||||||
},
|
},
|
||||||
ty: binding.ty,
|
ty: binding.ty,
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we have to walk through the supertraits to find
|
// 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));
|
let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
|
||||||
if self_ty.is_none() { // if converting for an object type
|
if self_ty.is_none() { // if converting for an object type
|
||||||
let mut dummy_substs = trait_ref.substs.clone();
|
let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+
|
||||||
assert!(dummy_substs.self_ty().is_none());
|
assert!(dummy_substs.self_ty().is_none()); // |
|
||||||
dummy_substs.types.push(SelfSpace, dummy_self_ty);
|
dummy_substs.types.push(SelfSpace, dummy_self_ty); // |
|
||||||
trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
|
trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_ref.def_id(), // <------------+
|
||||||
tcx.mk_substs(dummy_substs)));
|
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> =
|
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))
|
.filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -865,21 +896,13 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if ty::binds_late_bound_regions(tcx, &candidate) {
|
Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+
|
||||||
span_err!(tcx.sess, binding.span, E0219,
|
projection_ty: ty::ProjectionTy { // |
|
||||||
"associated type `{}` defined in higher-ranked supertrait `{}`",
|
trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+
|
||||||
token::get_name(binding.item_name),
|
|
||||||
candidate.user_string(tcx));
|
|
||||||
return Err(ErrorReported);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ty::ProjectionPredicate {
|
|
||||||
projection_ty: ty::ProjectionTy {
|
|
||||||
trait_ref: candidate.0,
|
|
||||||
item_name: binding.item_name,
|
item_name: binding.item_name,
|
||||||
},
|
},
|
||||||
ty: binding.ty,
|
ty: binding.ty,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_path_to_ty<'tcx>(
|
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));
|
debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
|
||||||
|
|
||||||
let trait_ref = ast_path_to_trait_ref(this,
|
let trait_ref =
|
||||||
rscope,
|
ast_path_to_mono_trait_ref(this,
|
||||||
span,
|
rscope,
|
||||||
param_mode,
|
span,
|
||||||
trait_def_id,
|
param_mode,
|
||||||
Some(self_ty),
|
trait_def_id,
|
||||||
trait_segment,
|
Some(self_ty),
|
||||||
None);
|
trait_segment);
|
||||||
|
|
||||||
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
|
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ use astconv;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::ty::{self, ToPolyTraitRef, Ty};
|
use middle::ty::{self, ToPolyTraitRef, Ty};
|
||||||
|
use std::cmp;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_util;
|
use syntax::ast_util;
|
||||||
|
@ -109,15 +110,11 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
|
||||||
ty::ty_trait(ref object_type) => {
|
ty::ty_trait(ref object_type) => {
|
||||||
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
|
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
|
||||||
fcx.tcx().types.err);
|
fcx.tcx().types.err);
|
||||||
let expectations =
|
let sig = proj_bounds.iter()
|
||||||
proj_bounds.iter()
|
.filter_map(|pb| deduce_sig_from_projection(fcx, pb))
|
||||||
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
|
.next();
|
||||||
.next();
|
let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
|
||||||
|
(sig, kind)
|
||||||
match expectations {
|
|
||||||
Some((sig, kind)) => (Some(sig), Some(kind)),
|
|
||||||
None => (None, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::ty_infer(ty::TyVar(vid)) => {
|
ty::ty_infer(ty::TyVar(vid)) => {
|
||||||
deduce_expectations_from_obligations(fcx, 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();
|
let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
|
||||||
// Here `expected_ty` is known to be a type inference variable.
|
// Here `expected_ty` is known to be a type inference variable.
|
||||||
|
|
||||||
let expected_sig_and_kind =
|
let expected_sig =
|
||||||
fulfillment_cx
|
fulfillment_cx
|
||||||
.pending_obligations()
|
.pending_obligations()
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -150,7 +147,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
||||||
ty::Predicate::Projection(ref proj_predicate) => {
|
ty::Predicate::Projection(ref proj_predicate) => {
|
||||||
let trait_ref = proj_predicate.to_poly_trait_ref();
|
let trait_ref = proj_predicate.to_poly_trait_ref();
|
||||||
self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
|
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
|
None
|
||||||
|
@ -159,14 +156,10 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
||||||
})
|
})
|
||||||
.next();
|
.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
|
// 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
|
// 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 =
|
let expected_kind =
|
||||||
fulfillment_cx
|
fulfillment_cx
|
||||||
.pending_obligations()
|
.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| 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()))
|
.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
|
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
||||||
/// everything we need to know about a closure.
|
/// 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>,
|
fcx: &FnCtxt<'a,'tcx>,
|
||||||
projection: &ty::PolyProjectionPredicate<'tcx>)
|
projection: &ty::PolyProjectionPredicate<'tcx>)
|
||||||
-> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
|
-> Option<ty::FnSig<'tcx>>
|
||||||
{
|
{
|
||||||
let tcx = fcx.tcx();
|
let tcx = fcx.tcx();
|
||||||
|
|
||||||
debug!("deduce_expectations_from_projection({})",
|
debug!("deduce_sig_from_projection({})",
|
||||||
projection.repr(tcx));
|
projection.repr(tcx));
|
||||||
|
|
||||||
let trait_ref = projection.to_poly_trait_ref();
|
let trait_ref = projection.to_poly_trait_ref();
|
||||||
|
|
||||||
let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
|
if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
|
||||||
Some(k) => k,
|
return None;
|
||||||
None => { return None; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
debug!("found object type {:?}", kind);
|
|
||||||
|
|
||||||
let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
|
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);
|
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 {
|
let input_tys = match arg_param_ty.sty {
|
||||||
ty::ty_tup(ref tys) => { (*tys).clone() }
|
ty::ty_tup(ref tys) => { (*tys).clone() }
|
||||||
_ => { return None; }
|
_ => { 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 = projection.0.ty;
|
||||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_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 {
|
let fn_sig = ty::FnSig {
|
||||||
inputs: input_tys,
|
inputs: input_tys,
|
||||||
output: ty::FnConverging(ret_param_ty),
|
output: ty::FnConverging(ret_param_ty),
|
||||||
variadic: false
|
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>(
|
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
|
// this closure doesn't implement the right kind of `Fn` trait
|
||||||
if closure_kind != kind {
|
if !closure_kind.extends(kind) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -784,14 +784,15 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
&enum_definition.variants);
|
&enum_definition.variants);
|
||||||
},
|
},
|
||||||
ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
|
ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
|
||||||
let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()),
|
let trait_ref =
|
||||||
&ExplicitRscope,
|
astconv::instantiate_mono_trait_ref(&ccx.icx(&()),
|
||||||
ast_trait_ref,
|
&ExplicitRscope,
|
||||||
Some(it.id),
|
ast_trait_ref,
|
||||||
None,
|
None);
|
||||||
None);
|
|
||||||
|
|
||||||
ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
|
ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
|
||||||
|
|
||||||
|
tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
|
||||||
}
|
}
|
||||||
ast::ItemImpl(_, _,
|
ast::ItemImpl(_, _,
|
||||||
ref generics,
|
ref generics,
|
||||||
|
@ -890,13 +891,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref trait_ref) = *opt_trait_ref {
|
if let Some(ref ast_trait_ref) = *opt_trait_ref {
|
||||||
astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates),
|
let trait_ref =
|
||||||
&ExplicitRscope,
|
astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
|
||||||
trait_ref,
|
&ExplicitRscope,
|
||||||
Some(it.id),
|
ast_trait_ref,
|
||||||
Some(selfty),
|
Some(selfty));
|
||||||
None);
|
|
||||||
|
tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce_impl_ty_params_are_constrained(tcx,
|
enforce_impl_ty_params_are_constrained(tcx,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue