Ensure that, for every trait Foo
, the predicate Foo : Foo
holds.
This commit is contained in:
parent
19dcecb225
commit
dabd7507b6
src
libcore/fmt
librustc/middle
librustc_trans/trans
librustc_typeck/check
@ -605,9 +605,6 @@ impl<'a, Sized? T: Show> Show for &'a T {
|
||||
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 {
|
||||
|
@ -217,6 +217,9 @@ pub enum Vtable<'tcx, N> {
|
||||
/// for some type parameter.
|
||||
VtableParam,
|
||||
|
||||
/// Virtual calls through an object
|
||||
VtableObject(VtableObjectData<'tcx>),
|
||||
|
||||
/// Successful resolution for a builtin trait.
|
||||
VtableBuiltin(VtableBuiltinData<N>),
|
||||
|
||||
@ -252,6 +255,13 @@ pub struct 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,
|
||||
@ -372,6 +382,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
VtableFnPointer(..) => (&[]).iter(),
|
||||
VtableUnboxedClosure(..) => (&[]).iter(),
|
||||
VtableParam => (&[]).iter(),
|
||||
VtableObject(_) => (&[]).iter(),
|
||||
VtableBuiltin(ref i) => i.iter_nested(),
|
||||
}
|
||||
}
|
||||
@ -382,6 +393,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
@ -394,6 +406,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
VtableFnPointer(sig) => VtableFnPointer(sig),
|
||||
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
|
||||
VtableParam => VtableParam,
|
||||
VtableObject(p) => VtableObject(p),
|
||||
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
|
||||
}
|
||||
}
|
||||
|
@ -377,20 +377,14 @@ fn project_type<'cx,'tcx>(
|
||||
ambiguous: false,
|
||||
};
|
||||
|
||||
assemble_candidates_from_object_type(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
assemble_candidates_from_param_env(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));
|
||||
}
|
||||
if let Err(e) = assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates) {
|
||||
return Err(ProjectionTyError::TraitSelectionError(e));
|
||||
}
|
||||
|
||||
debug!("{} candidates, ambiguous={}",
|
||||
@ -467,18 +461,22 @@ fn assemble_candidates_from_predicates<'cx,'tcx>(
|
||||
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();
|
||||
@ -515,6 +513,10 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
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:
|
||||
|
@ -24,8 +24,10 @@ use super::{ObligationCauseCode, BuiltinDerivedObligation};
|
||||
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;
|
||||
@ -147,6 +149,8 @@ enum SelectionCandidate<'tcx> {
|
||||
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
|
||||
FnPointerCandidate,
|
||||
|
||||
ObjectCandidate,
|
||||
|
||||
ErrorCandidate,
|
||||
}
|
||||
|
||||
@ -717,6 +721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,7 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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));
|
||||
@ -945,7 +950,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -991,6 +996,67 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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
|
||||
//
|
||||
@ -1544,6 +1610,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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));
|
||||
@ -1727,6 +1798,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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>>
|
||||
@ -1962,12 +2075,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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()));
|
||||
|
||||
@ -2161,6 +2274,9 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'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))
|
||||
}
|
||||
|
@ -238,6 +238,12 @@ impl<'tcx, N> fmt::Show for VtableImplData<'tcx, N> {
|
||||
}
|
||||
}
|
||||
|
||||
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>,
|
||||
@ -366,6 +372,10 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
|
||||
format!("VtableFnPointer({})",
|
||||
d.repr(tcx)),
|
||||
|
||||
super::VtableObject(ref d) =>
|
||||
format!("VtableObject({})",
|
||||
d.repr(tcx)),
|
||||
|
||||
super::VtableParam =>
|
||||
format!("VtableParam"),
|
||||
|
||||
@ -391,6 +401,13 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -503,6 +503,15 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,12 @@
|
||||
// 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;
|
||||
@ -370,6 +370,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
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(
|
||||
@ -503,6 +507,137 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
};
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
@ -560,6 +695,14 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
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",
|
||||
|
@ -9,7 +9,6 @@
|
||||
// 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user