impl<'a, Sized? T: Show> Show for &'a mut T {
fn fmt(&self, f: &mut Formatter) -> Result { (**self).fmt(f) }
}
-impl<'a> Show for &'a (Show+'a) {
- fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) }
-}
impl Show for bool {
fn fmt(&self, f: &mut Formatter) -> Result {
/// for some type parameter.
VtableParam,
+ /// Virtual calls through an object
+ VtableObject(VtableObjectData<'tcx>),
+
/// Successful resolution for a builtin trait.
VtableBuiltin(VtableBuiltinData<N>),
pub nested: subst::VecPerParamSpace<N>
}
+/// A vtable for some object-safe trait `Foo` automatically derived
+/// for the object type `Foo`.
+#[deriving(PartialEq,Eq,Clone)]
+pub struct VtableObjectData<'tcx> {
+ pub object_ty: Ty<'tcx>,
+}
+
/// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
/// of a trait, not an inherent impl.
pub fn is_orphan_impl(tcx: &ty::ctxt,
VtableFnPointer(..) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam => (&[]).iter(),
+ VtableObject(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
}
}
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
VtableParam => VtableParam,
+ VtableObject(ref p) => VtableObject(p.clone()),
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
}
}
VtableFnPointer(sig) => VtableFnPointer(sig),
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
VtableParam => VtableParam,
+ VtableObject(p) => VtableObject(p),
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
}
}
ambiguous: false,
};
- assemble_candidates_from_object_type(selcx,
- obligation,
- &mut candidates);
-
- if candidates.vec.is_empty() {
- assemble_candidates_from_param_env(selcx,
- obligation,
- &mut candidates);
-
- if let Err(e) = assemble_candidates_from_impls(selcx,
- obligation,
- &mut candidates) {
- return Err(ProjectionTyError::TraitSelectionError(e));
- }
+ assemble_candidates_from_param_env(selcx,
+ obligation,
+ &mut candidates);
+
+ if let Err(e) = assemble_candidates_from_impls(selcx,
+ obligation,
+ &mut candidates) {
+ return Err(ProjectionTyError::TraitSelectionError(e));
}
debug!("{} candidates, ambiguous={}",
fn assemble_candidates_from_object_type<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
+ candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+ object_ty: Ty<'tcx>)
{
let infcx = selcx.infcx();
- let trait_ref = infcx.resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
- debug!("assemble_candidates_from_object_type(trait_ref={})",
- trait_ref.repr(infcx.tcx));
- let self_ty = trait_ref.self_ty();
- let data = match self_ty.sty {
+ debug!("assemble_candidates_from_object_type(object_ty={})",
+ object_ty.repr(infcx.tcx));
+ let data = match object_ty.sty {
ty::ty_trait(ref data) => data,
- _ => { return; }
+ _ => {
+ selcx.tcx().sess.span_bug(
+ obligation.cause.span,
+ format!("assemble_candidates_from_object_type called with non-object: {}",
+ object_ty.repr(selcx.tcx()))[]);
+ }
};
- let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), self_ty);
+ let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
let env_predicates = projection_bounds.iter()
.map(|p| p.as_predicate())
.collect();
candidate_set.vec.push(
ProjectionTyCandidate::Impl(data));
}
+ super::VtableObject(data) => {
+ assemble_candidates_from_object_type(
+ selcx, obligation, candidate_set, data.object_ty);
+ }
super::VtableParam(..) => {
// This case tell us nothing about the value of an
// associated type. Consider:
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
use super::{Selection};
use super::{SelectionResult};
-use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
-use super::{VtableImplData, VtableBuiltinData};
+use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure,
+ VtableFnPointer, VtableObject};
+use super::{VtableImplData, VtableObjectData, VtableBuiltinData};
+use super::object_safety;
use super::{util};
use middle::fast_reject;
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
FnPointerCandidate,
+ ObjectCandidate,
+
ErrorCandidate,
}
try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec));
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
}
let matching_bounds =
all_bounds.filter(
|bound| self.infcx.probe(
- |_| self.match_where_clause(obligation, bound.clone())).is_ok());
+ |_| self.match_poly_trait_ref(obligation, bound.clone())).is_ok());
let param_candidates =
matching_bounds.map(|bound| ParamCandidate(bound));
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
match self_ty.sty {
- ty::ty_infer(..) => {
+ ty::ty_infer(ty::TyVar(_)) => {
candidates.ambiguous = true; // could wind up being a fn() type
}
Ok(())
}
+ /// Search for impls that might apply to `obligation`.
+ fn assemble_candidates_from_object_ty(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>)
+ {
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
+ debug!("assemble_candidates_from_object_ty(self_ty={})",
+ self_ty.repr(self.tcx()));
+
+ // Object-safety candidates are only applicable to object-safe
+ // traits. Including this check is useful because it helps
+ // inference in cases of traits like `BorrowFrom`, which are
+ // not object-safe, and which rely on being able to infer the
+ // self-type from one of the other inputs. Without this check,
+ // these cases wind up being considered ambiguous due to a
+ // (spurious) ambiguity introduced here.
+ if !object_safety::is_object_safe(self.tcx(), obligation.predicate.to_poly_trait_ref()) {
+ return;
+ }
+
+ let poly_trait_ref = match self_ty.sty {
+ ty::ty_trait(ref data) => {
+ data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
+ }
+ ty::ty_infer(ty::TyVar(_)) => {
+ debug!("assemble_candidates_from_object_ty: ambiguous");
+ candidates.ambiguous = true; // could wind up being an object type
+ return;
+ }
+ _ => {
+ return;
+ }
+ };
+
+ debug!("assemble_candidates_from_object_ty: poly_trait_ref={}",
+ poly_trait_ref.repr(self.tcx()));
+
+ // see whether the object trait can be upcast to the trait we are looking for
+ let obligation_def_id = obligation.predicate.def_id();
+ let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) {
+ Some(r) => r,
+ None => { return; }
+ };
+
+ debug!("assemble_candidates_from_object_ty: upcast_trait_ref={}",
+ upcast_trait_ref.repr(self.tcx()));
+
+ // check whether the upcast version of the trait-ref matches what we are looking for
+ match
+ self.infcx.probe(
+ |_| self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()))
+ {
+ Ok(()) => {
+ debug!("assemble_candidates_from_object_ty: matched, pushing candidate");
+ candidates.vec.push(ObjectCandidate);
+ }
+ Err(()) => { }
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// WINNOW
//
Ok(VtableUnboxedClosure(closure_def_id, substs))
}
+ ObjectCandidate => {
+ let data = self.confirm_object_candidate(obligation);
+ Ok(VtableObject(data))
+ }
+
FnPointerCandidate => {
let fn_type =
try!(self.confirm_fn_pointer_candidate(obligation));
nested: impl_predicates }
}
+ fn confirm_object_candidate(&mut self,
+ obligation: &TraitObligation<'tcx>)
+ -> VtableObjectData<'tcx>
+ {
+ debug!("confirm_object_candidate({})",
+ obligation.repr(self.tcx()));
+
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+ let poly_trait_ref = match self_ty.sty {
+ ty::ty_trait(ref data) => {
+ data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
+ }
+ _ => {
+ self.tcx().sess.span_bug(obligation.cause.span,
+ "object candidate with non-object");
+ }
+ };
+
+ let obligation_def_id = obligation.predicate.def_id();
+ let upcast_trait_ref = match util::upcast(self.tcx(),
+ poly_trait_ref.clone(),
+ obligation_def_id) {
+ Some(r) => r,
+ None => {
+ self.tcx().sess.span_bug(obligation.cause.span,
+ format!("unable to upcast from {} to {}",
+ poly_trait_ref.repr(self.tcx()),
+ obligation_def_id.repr(self.tcx())).as_slice());
+ }
+ };
+
+ match self.match_poly_trait_ref(obligation, upcast_trait_ref) {
+ Ok(()) => { }
+ Err(()) => {
+ self.tcx().sess.span_bug(obligation.cause.span,
+ "failed to match trait refs");
+ }
+ }
+
+ VtableObjectData { object_ty: self_ty }
+ }
+
fn confirm_fn_pointer_candidate(&mut self,
obligation: &TraitObligation<'tcx>)
-> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
})
}
- fn match_where_clause(&mut self,
- obligation: &TraitObligation<'tcx>,
- where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<(),()>
+ fn match_poly_trait_ref(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
+ -> Result<(),()>
{
- debug!("match_where_clause: obligation={} where_clause_trait_ref={}",
+ debug!("match_poly_trait_ref: obligation={} where_clause_trait_ref={}",
obligation.repr(self.tcx()),
where_clause_trait_ref.repr(self.tcx()));
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
ProjectionCandidate => format!("ProjectionCandidate"),
FnPointerCandidate => format!("FnPointerCandidate"),
+ ObjectCandidate => {
+ format!("ObjectCandidate")
+ }
UnboxedClosureCandidate(c, ref s) => {
format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx))
}
}
}
+impl<'tcx> fmt::Show for super::VtableObjectData<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableObject(...)")
+ }
+}
+
/// See `super::obligations_for_generics`
pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
cause: ObligationCause<'tcx>,
format!("VtableFnPointer({})",
d.repr(tcx)),
+ super::VtableObject(ref d) =>
+ format!("VtableObject({})",
+ d.repr(tcx)),
+
super::VtableParam =>
format!("VtableParam"),
}
}
+impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+ format!("VtableObject(object_ty={})",
+ self.object_ty.repr(tcx))
+ }
+}
+
impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
}
traits::VtableParam => traits::VtableParam,
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
+ traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
+ traits::VtableObjectData {
+ object_ty: self.object_ty.fold_with(folder)
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+use arena::TypedArena;
use back::abi;
-use llvm;
-use llvm::ValueRef;
+use back::link;
+use llvm::{mod, ValueRef, get_param};
use metadata::csearch;
-use middle::subst::{Substs};
+use middle::subst::{Subst, Substs};
use middle::subst::VecPerParamSpace;
use middle::subst;
use middle::traits;
let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
Callee { bcx: bcx, data: Fn(llfn) }
}
+ traits::VtableObject(ref data) => {
+ let llfn = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
+ Callee { bcx: bcx, data: Fn(llfn) }
+ }
traits::VtableBuiltin(..) |
traits::VtableParam(..) => {
bcx.sess().bug(
};
}
+/// Generate a shim function that allows an object type like `SomeTrait` to
+/// implement the type `SomeTrait`. Imagine a trait definition:
+///
+/// trait SomeTrait { fn get(&self) -> int; ... }
+///
+/// And a generic bit of code:
+///
+/// fn foo<T:SomeTrait>(t: &T) {
+/// let x = SomeTrait::get;
+/// x(t)
+/// }
+///
+/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`?
+/// The answer is that it it is a shim function generate by this
+/// routine:
+///
+/// fn shim(t: &SomeTrait) -> int {
+/// // ... call t.get() virtually ...
+/// }
+///
+/// In fact, all virtual calls can be thought of as normal trait calls
+/// that go through this shim function.
+pub fn trans_object_shim<'a, 'tcx>(
+ ccx: &'a CrateContext<'a, 'tcx>,
+ object_ty: Ty<'tcx>,
+ trait_id: ast::DefId,
+ method_offset_in_trait: uint)
+ -> ValueRef
+{
+ let _icx = push_ctxt("trans_object_shim");
+ let tcx = ccx.tcx();
+
+ debug!("trans_object_shim(object_ty={}, trait_id={}, n_method={})",
+ object_ty.repr(tcx),
+ trait_id.repr(tcx),
+ method_offset_in_trait);
+
+ let object_trait_ref =
+ match object_ty.sty {
+ ty::ty_trait(ref data) => {
+ data.principal_trait_ref_with_self_ty(tcx, object_ty)
+ }
+ _ => {
+ tcx.sess.bug(format!("trans_object_shim() called on non-object: {}",
+ object_ty.repr(tcx)).as_slice());
+ }
+ };
+
+ // Upcast to the trait in question and extract out the substitutions.
+ let upcast_trait_ref = traits::upcast(ccx.tcx(), object_trait_ref.clone(), trait_id).unwrap();
+ let object_substs = upcast_trait_ref.substs().clone().erase_regions();
+ debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));
+
+ // Lookup the type of this method as deeclared in the trait and apply substitutions.
+ let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
+ ty::MethodTraitItem(method) => method,
+ ty::TypeTraitItem(_) => {
+ tcx.sess.bug("can't create a method shim for an associated type")
+ }
+ };
+ let fty = method_ty.fty.subst(tcx, &object_substs);
+ let fty = tcx.mk_bare_fn(fty);
+ debug!("trans_object_shim: fty={}", fty.repr(tcx));
+
+ //
+ let method_bare_fn_ty =
+ ty::mk_bare_fn(tcx, None, fty);
+ let function_name =
+ link::mangle_internal_name_by_type_and_seq(ccx, method_bare_fn_ty, "object_shim");
+ let llfn =
+ decl_internal_rust_fn(ccx, method_bare_fn_ty, function_name.as_slice());
+
+ //
+ let block_arena = TypedArena::new();
+ let empty_substs = Substs::trans_empty();
+ let fcx = new_fn_ctxt(ccx,
+ llfn,
+ ast::DUMMY_NODE_ID,
+ false,
+ fty.sig.0.output,
+ &empty_substs,
+ None,
+ &block_arena);
+ let mut bcx = init_function(&fcx, false, fty.sig.0.output);
+
+ // the first argument (`self`) will be a trait object
+ let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
+
+ debug!("trans_object_shim: llobject={}",
+ bcx.val_to_string(llobject));
+
+ // the remaining arguments will be, well, whatever they are
+ let llargs: Vec<_> =
+ fty.sig.0.inputs[1..].iter()
+ .enumerate()
+ .map(|(i, _)| {
+ let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32);
+ debug!("trans_object_shim: input #{} == {}",
+ i, bcx.val_to_string(llarg));
+ llarg
+ })
+ .collect();
+ assert!(!fcx.needs_ret_allocas);
+
+ let dest =
+ fcx.llretslotptr.get().map(
+ |_| expr::SaveIn(fcx.get_ret_slot(bcx, fty.sig.0.output, "ret_slot")));
+
+ let method_offset_in_vtable =
+ traits::get_vtable_index_of_object_method(bcx.tcx(),
+ object_trait_ref.clone(),
+ trait_id,
+ method_offset_in_trait);
+ debug!("trans_object_shim: method_offset_in_vtable={}",
+ method_offset_in_vtable);
+
+ bcx = trans_call_inner(bcx,
+ None,
+ method_bare_fn_ty,
+ |bcx, _| trans_trait_callee_from_llval(bcx,
+ method_bare_fn_ty,
+ method_offset_in_vtable,
+ llobject),
+ ArgVals(llargs.as_slice()),
+ dest).bcx;
+
+ finish_fn(&fcx, bcx, fty.sig.0.output);
+
+ llfn
+}
+
/// Creates a returns a dynamic vtable for the given type and vtable origin.
/// This is used only for objects.
///
let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)];
llfn.into_iter()
}
+ traits::VtableObject(ref data) => {
+ // this would imply that the Self type being erased is
+ // an object type; this cannot happen because we
+ // cannot cast an unsized type into a trait object
+ bcx.sess().bug(
+ format!("cannot get vtable for an object type: {}",
+ data.repr(bcx.tcx())).as_slice());
+ }
traits::VtableParam => {
bcx.sess().bug(
format!("resolved vtable for {} to bad vtable {} in trans",
// except according to those terms.
use check::{FnCtxt, structurally_resolved_type};
-use middle::subst::{FnSpace, SelfSpace};
use middle::traits::{mod, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;