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.
#[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;
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;
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")]
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>
{
}
}
+#[cfg(stage0)]
impl<F,A> FnOnce<A> for F
where F : FnMut<A>
{
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};
#[derive(Copy, Clone)]
struct BytesDeref;
+#[cfg(stage0)]
impl<'a> Fn<(&'a u8,)> for BytesDeref {
type Output = u8;
}
}
+#[cfg(not(stage0))]
+impl<'a> Fn<(&'a u8,)> for BytesDeref {
+ #[inline]
+ extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
+ *ptr
+ }
+}
+
+#[cfg(not(stage0))]
+impl<'a> FnMut<(&'a u8,)> for BytesDeref {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
+ Fn::call(&*self, (ptr,))
+ }
+}
+
+#[cfg(not(stage0))]
+impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
+ type Output = u8;
+
+ #[inline]
+ extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
+ Fn::call(&self, (ptr,))
+ }
+}
+
/// An iterator over the substrings of a string, separated by `sep`.
struct CharSplits<'a, P: Pattern<'a>> {
/// The slice remaining to be iterated
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);
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()));
}
}
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(());
}
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,
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> {
/// 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 => { }
}
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) =
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
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<_> =
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
}
// 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;
// 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() {
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
+}
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::*;
traits::VtableClosure(closure_def_id, substs) => {
// The substitutions should have no type parameters remaining
// after passing through fulfill_obligation
- let llfn = trans_fn_ref_with_substs(bcx.ccx(),
- closure_def_id,
- MethodCallKey(method_call),
- bcx.fcx.param_substs,
- substs).val;
-
+ let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+ let llfn = closure::trans_closure_method(bcx.ccx(),
+ closure_def_id,
+ substs,
+ MethodCallKey(method_call),
+ bcx.fcx.param_substs,
+ trait_closure_kind);
Callee {
bcx: bcx,
data: Fn(llfn),
}
}
traits::VtableFnPointer(fn_ty) => {
- let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
+ let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+ let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableObject(ref data) => {
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")));
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
}
traits::VtableClosure(closure_def_id, substs) => {
- let llfn = trans_fn_ref_with_substs(
- ccx,
- closure_def_id,
- ExprId(0),
- param_substs,
- substs).val;
-
+ let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
+ let llfn = closure::trans_closure_method(ccx,
+ closure_def_id,
+ substs,
+ ExprId(0),
+ param_substs,
+ trait_closure_kind);
vec![llfn].into_iter()
}
traits::VtableFnPointer(bare_fn_ty) => {
- vec![trans_fn_pointer_shim(ccx, bare_fn_ty)].into_iter()
+ let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
+ vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
}
traits::VtableObject(ref data) => {
// this would imply that the Self type being erased is
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};
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
///
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
/// are disallowed. Otherwise, they are pushed onto the vector given.
-pub fn instantiate_trait_ref<'tcx>(
+pub fn instantiate_mono_trait_ref<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
trait_ref: &ast::TraitRef,
- impl_id: Option<ast::NodeId>,
- self_ty: Option<Ty<'tcx>>,
- projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
+ self_ty: Option<Ty<'tcx>>)
-> Rc<ty::TraitRef<'tcx>>
{
+ let trait_def_id = trait_def_id(this, trait_ref);
+ ast_path_to_mono_trait_ref(this,
+ rscope,
+ trait_ref.path.span,
+ PathParamMode::Explicit,
+ trait_def_id,
+ self_ty,
+ trait_ref.path.segments.last().unwrap())
+}
+
+fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId {
let path = &trait_ref.path;
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
- def::DefTrait(trait_def_id) => {
- let trait_ref = ast_path_to_trait_ref(this,
- rscope,
- path.span,
- PathParamMode::Explicit,
- trait_def_id,
- self_ty,
- path.segments.last().unwrap(),
- projections);
- if let Some(id) = impl_id {
- this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone());
- }
- trait_ref
- }
+ def::DefTrait(trait_def_id) => trait_def_id,
_ => {
span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
path.user_string(this.tcx()));
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
- // we are introducing a binder here, so shift the
- // anonymous regions depth to account for that
- let shifted_rscope = ShiftedRscope::new(rscope);
-
- let mut tmp = Vec::new();
- let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
- &shifted_rscope,
- span,
- param_mode,
- trait_def_id,
- None,
- trait_segment,
- Some(&mut tmp)));
- projections.extend(tmp.into_iter().map(ty::Binder));
- trait_ref
+ ast_path_to_poly_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ None,
+ trait_segment,
+ projections)
}
-fn ast_path_to_trait_ref<'a,'tcx>(
+fn ast_path_to_poly_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
trait_segment: &ast::PathSegment,
- mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
- -> Rc<ty::TraitRef<'tcx>>
+ poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+ -> ty::PolyTraitRef<'tcx>
+{
+ // The trait reference introduces a binding level here, so
+ // we need to shift the `rscope`. It'd be nice if we could
+ // do away with this rscope stuff and work this knowledge
+ // into resolve_lifetimes, as we do with non-omitted
+ // lifetimes. Oh well, not there yet.
+ let shifted_rscope = &ShiftedRscope::new(rscope);
+
+ let (substs, assoc_bindings) =
+ create_substs_for_ast_trait_ref(this,
+ shifted_rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ self_ty,
+ trait_segment);
+ let poly_trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_def_id, substs)));
+
+ {
+ let converted_bindings =
+ assoc_bindings
+ .iter()
+ .filter_map(|binding| {
+ // specify type to assert that error was already reported in Err case:
+ let predicate: Result<_, ErrorReported> =
+ ast_type_binding_to_poly_projection_predicate(this,
+ poly_trait_ref.clone(),
+ self_ty,
+ binding);
+ predicate.ok() // ok to ignore Err() because ErrorReported (see above)
+ });
+ poly_projections.extend(converted_bindings);
+ }
+
+ poly_trait_ref
+}
+
+fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
+ trait_def_id: ast::DefId,
+ self_ty: Option<Ty<'tcx>>,
+ trait_segment: &ast::PathSegment)
+ -> Rc<ty::TraitRef<'tcx>>
{
- debug!("ast_path_to_trait_ref {:?}", trait_segment);
+ let (substs, assoc_bindings) =
+ create_substs_for_ast_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ self_ty,
+ trait_segment);
+ prohibit_projections(this.tcx(), &assoc_bindings);
+ Rc::new(ty::TraitRef::new(trait_def_id, substs))
+}
+
+fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
+ trait_def_id: ast::DefId,
+ self_ty: Option<Ty<'tcx>>,
+ trait_segment: &ast::PathSegment)
+ -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
+{
+ debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
+ trait_segment);
+
let trait_def = match this.get_trait_def(span, trait_def_id) {
Ok(trait_def) => trait_def,
Err(ErrorReported) => {
self_ty,
types,
regions);
- let substs = this.tcx().mk_substs(substs);
- let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
-
- match projections {
- None => {
- prohibit_projections(this.tcx(), &assoc_bindings);
- }
- Some(ref mut v) => {
- for binding in &assoc_bindings {
- match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
- self_ty, binding) {
- Ok(pp) => { v.push(pp); }
- Err(ErrorReported) => { }
- }
- }
- }
- }
-
- trait_ref
+ (this.tcx().mk_substs(substs), assoc_bindings)
}
-fn ast_type_binding_to_projection_predicate<'tcx>(
+fn ast_type_binding_to_poly_projection_predicate<'tcx>(
this: &AstConv<'tcx>,
- mut trait_ref: Rc<ty::TraitRef<'tcx>>,
+ mut trait_ref: ty::PolyTraitRef<'tcx>,
self_ty: Option<Ty<'tcx>>,
binding: &ConvertedBinding<'tcx>)
- -> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
+ -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
{
let tcx = this.tcx();
// 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
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();
}
};
- 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>(
debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
- let trait_ref = ast_path_to_trait_ref(this,
- rscope,
- span,
- param_mode,
- trait_def_id,
- Some(self_ty),
- trait_segment,
- None);
+ let trait_ref =
+ ast_path_to_mono_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ Some(self_ty),
+ trait_segment);
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
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;
ty::ty_trait(ref object_type) => {
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
fcx.tcx().types.err);
- let expectations =
- proj_bounds.iter()
- .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
- .next();
-
- match expectations {
- Some((sig, kind)) => (Some(sig), Some(kind)),
- None => (None, None)
- }
+ let sig = proj_bounds.iter()
+ .filter_map(|pb| deduce_sig_from_projection(fcx, pb))
+ .next();
+ let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
+ (sig, kind)
}
ty::ty_infer(ty::TyVar(vid)) => {
deduce_expectations_from_obligations(fcx, vid)
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()
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
})
.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()
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
.and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
})
- .next();
+ .fold(None, pick_most_restrictive_closure_kind);
+
+ (expected_sig, expected_kind)
+}
- (None, expected_kind)
+fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
+ cur: ty::ClosureKind)
+ -> Option<ty::ClosureKind>
+{
+ match best {
+ None => Some(cur),
+ Some(best) => Some(cmp::min(best, cur))
+ }
}
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
/// everything we need to know about a closure.
-fn deduce_expectations_from_projection<'a,'tcx>(
+fn deduce_sig_from_projection<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
projection: &ty::PolyProjectionPredicate<'tcx>)
- -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
+ -> Option<ty::FnSig<'tcx>>
{
let tcx = fcx.tcx();
- debug!("deduce_expectations_from_projection({})",
+ debug!("deduce_sig_from_projection({})",
projection.repr(tcx));
let trait_ref = projection.to_poly_trait_ref();
- let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
- Some(k) => k,
- None => { return None; }
- };
-
- debug!("found object type {:?}", kind);
+ if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
+ return None;
+ }
let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
- debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
+ debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx));
let input_tys = match arg_param_ty.sty {
ty::ty_tup(ref tys) => { (*tys).clone() }
_ => { return None; }
};
- debug!("input_tys {}", input_tys.repr(tcx));
+ debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx));
let ret_param_ty = projection.0.ty;
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
- debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
+ debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx));
let fn_sig = ty::FnSig {
inputs: input_tys,
output: ty::FnConverging(ret_param_ty),
variadic: false
};
- debug!("fn_sig {}", fn_sig.repr(tcx));
+ debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx));
- return Some((fn_sig, kind));
+ Some(fn_sig)
}
fn self_type_matches_expected_vid<'a,'tcx>(
};
// this closure doesn't implement the right kind of `Fn` trait
- if closure_kind != kind {
+ if !closure_kind.extends(kind) {
continue;
}
&enum_definition.variants);
},
ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
- let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()),
- &ExplicitRscope,
- ast_trait_ref,
- Some(it.id),
- None,
- None);
+ let trait_ref =
+ astconv::instantiate_mono_trait_ref(&ccx.icx(&()),
+ &ExplicitRscope,
+ ast_trait_ref,
+ None);
ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
+
+ tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
}
ast::ItemImpl(_, _,
ref generics,
}
}
- if let Some(ref trait_ref) = *opt_trait_ref {
- astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates),
- &ExplicitRscope,
- trait_ref,
- Some(it.id),
- Some(selfty),
- None);
+ if let Some(ref ast_trait_ref) = *opt_trait_ref {
+ let trait_ref =
+ astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
+ &ExplicitRscope,
+ ast_trait_ref,
+ Some(selfty));
+
+ tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
}
enforce_impl_ty_params_are_constrained(tcx,