mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-10 23:54:58 +00:00
Implement associated type projection and normalization.
This commit is contained in:
parent
f95bb55a1c
commit
4404592f36
@ -256,3 +256,6 @@ pub const tag_predicate_space: uint = 0xa9;
|
||||
pub const tag_predicate_data: uint = 0xb0;
|
||||
|
||||
pub const tag_unsafety: uint = 0xb1;
|
||||
|
||||
pub const tag_associated_type_names: uint = 0xb2;
|
||||
pub const tag_associated_type_name: uint = 0xb3;
|
||||
|
@ -369,6 +369,17 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
|
||||
let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
|
||||
let mut names = Vec::new();
|
||||
reader::tagged_docs(names_doc, tag_associated_type_name, |name_doc| {
|
||||
let name = token::intern(name_doc.as_str_slice());
|
||||
names.push(name);
|
||||
true
|
||||
});
|
||||
names
|
||||
}
|
||||
|
||||
pub fn get_trait_def<'tcx>(cdata: Cmd,
|
||||
item_id: ast::NodeId,
|
||||
tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
|
||||
@ -377,12 +388,14 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
|
||||
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
|
||||
let bounds = trait_def_bounds(item_doc, tcx, cdata);
|
||||
let unsafety = parse_unsafety(item_doc);
|
||||
let associated_type_names = parse_associated_type_names(item_doc);
|
||||
|
||||
ty::TraitDef {
|
||||
unsafety: unsafety,
|
||||
generics: generics,
|
||||
bounds: bounds,
|
||||
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
|
||||
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)),
|
||||
associated_type_names: associated_type_names,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1316,6 +1316,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_item_variances(rbml_w, ecx, item.id);
|
||||
let trait_def = ty::lookup_trait_def(tcx, def_id);
|
||||
encode_unsafety(rbml_w, trait_def.unsafety);
|
||||
encode_associated_type_names(rbml_w, trait_def.associated_type_names.as_slice());
|
||||
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
|
||||
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||
encode_name(rbml_w, item.ident.name);
|
||||
@ -1689,6 +1690,14 @@ fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
|
||||
rbml_w.wr_tagged_u8(tag_unsafety, byte);
|
||||
}
|
||||
|
||||
fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[ast::Name]) {
|
||||
rbml_w.start_tag(tag_associated_type_names);
|
||||
for &name in names.iter() {
|
||||
rbml_w.wr_tagged_str(tag_associated_type_name, token::get_name(name).get());
|
||||
}
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
|
||||
fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<decoder::CrateDep> {
|
||||
// Pull the cnums and name,vers,hash out of cstore
|
||||
|
@ -504,6 +504,12 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
||||
return ty::mk_unboxed_closure(st.tcx, did,
|
||||
st.tcx.mk_region(region), st.tcx.mk_substs(substs));
|
||||
}
|
||||
'P' => {
|
||||
assert_eq!(next(st), '[');
|
||||
let trait_ref = parse_trait_ref(st, |x,y| conv(x,y));
|
||||
let name = token::str_to_ident(parse_str(st, ']').as_slice()).name;
|
||||
return ty::mk_projection(tcx, trait_ref, name);
|
||||
}
|
||||
'e' => {
|
||||
return tcx.types.err;
|
||||
}
|
||||
@ -683,17 +689,32 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>,
|
||||
-> ty::Predicate<'tcx>
|
||||
{
|
||||
match next(st) {
|
||||
't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(),
|
||||
't' => ty::Binder(Rc::new(parse_trait_ref(st, conv))).as_predicate(),
|
||||
'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)),
|
||||
parse_ty(st, |x,y| conv(x,y)))).as_predicate(),
|
||||
'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)),
|
||||
parse_region(st, |x,y| conv(x,y)))).as_predicate(),
|
||||
'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)),
|
||||
parse_region(st, |x,y| conv(x,y)))).as_predicate(),
|
||||
'p' => ty::Binder(parse_projection_predicate(st, conv)).as_predicate(),
|
||||
c => panic!("Encountered invalid character in metadata: {}", c)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_projection_predicate<'a,'tcx>(
|
||||
st: &mut PState<'a, 'tcx>,
|
||||
conv: conv_did)
|
||||
-> ty::ProjectionPredicate<'tcx>
|
||||
{
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: Rc::new(parse_trait_ref(st, |x,y| conv(x,y))),
|
||||
item_name: token::str_to_ident(parse_str(st, '|').as_slice()).name,
|
||||
},
|
||||
ty: parse_ty(st, |x,y| conv(x,y)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint,
|
||||
crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>,
|
||||
conv: conv_did) -> ty::TypeParameterDef<'tcx>
|
||||
@ -710,10 +731,6 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
||||
assert_eq!(next(st), '|');
|
||||
let index = parse_u32(st);
|
||||
assert_eq!(next(st), '|');
|
||||
let associated_with = parse_opt(st, |st| {
|
||||
parse_def(st, NominalType, |x,y| conv(x,y))
|
||||
});
|
||||
assert_eq!(next(st), '|');
|
||||
let bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
|
||||
|
||||
@ -722,7 +739,6 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
||||
def_id: def_id,
|
||||
space: space,
|
||||
index: index,
|
||||
associated_with: associated_with,
|
||||
bounds: bounds,
|
||||
default: default
|
||||
}
|
||||
@ -768,7 +784,8 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
||||
let mut param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: builtin_bounds,
|
||||
trait_bounds: Vec::new()
|
||||
trait_bounds: Vec::new(),
|
||||
projection_bounds: Vec::new(),
|
||||
};
|
||||
loop {
|
||||
match next(st) {
|
||||
@ -778,7 +795,11 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
||||
}
|
||||
'I' => {
|
||||
param_bounds.trait_bounds.push(
|
||||
Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y)))));
|
||||
ty::Binder(Rc::new(parse_trait_ref(st, |x,y| conv(x,y)))));
|
||||
}
|
||||
'P' => {
|
||||
param_bounds.projection_bounds.push(
|
||||
ty::Binder(parse_projection_predicate(st, |x,y| conv(x,y))));
|
||||
}
|
||||
'.' => {
|
||||
return param_bounds;
|
||||
|
@ -149,6 +149,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
||||
enc_substs(w, cx, substs);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
mywrite!(w, "P[");
|
||||
enc_trait_ref(w, cx, &data.trait_ref);
|
||||
mywrite!(w, "{}]", token::get_name(data.item_name));
|
||||
}
|
||||
ty::ty_err => {
|
||||
mywrite!(w, "e");
|
||||
}
|
||||
@ -403,7 +408,12 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
||||
|
||||
for tp in bs.trait_bounds.iter() {
|
||||
mywrite!(w, "I");
|
||||
enc_trait_ref(w, cx, &tp.0);
|
||||
enc_trait_ref(w, cx, &*tp.0);
|
||||
}
|
||||
|
||||
for tp in bs.projection_bounds.iter() {
|
||||
mywrite!(w, "P");
|
||||
enc_projection_predicate(w, cx, &tp.0);
|
||||
}
|
||||
|
||||
mywrite!(w, ".");
|
||||
@ -414,8 +424,6 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
|
||||
mywrite!(w, "{}:{}|{}|{}|",
|
||||
token::get_name(v.name), (cx.ds)(v.def_id),
|
||||
v.space.to_uint(), v.index);
|
||||
enc_opt(w, v.associated_with, |w, did| mywrite!(w, "{}", (cx.ds)(did)));
|
||||
mywrite!(w, "|");
|
||||
enc_bounds(w, cx, &v.bounds);
|
||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||
}
|
||||
@ -427,7 +435,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
match *p {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
mywrite!(w, "t");
|
||||
enc_trait_ref(w, cx, &trait_ref.0);
|
||||
enc_trait_ref(w, cx, &*trait_ref.0.trait_ref);
|
||||
}
|
||||
ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
|
||||
mywrite!(w, "e");
|
||||
@ -444,5 +452,17 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
enc_ty(w, cx, a);
|
||||
enc_region(w, cx, b);
|
||||
}
|
||||
ty::Predicate::Projection(ty::Binder(ref data)) => {
|
||||
mywrite!(w, "p");
|
||||
enc_projection_predicate(w, cx, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_projection_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
cx: &ctxt<'a, 'tcx>,
|
||||
data: &ty::ProjectionPredicate<'tcx>) {
|
||||
enc_trait_ref(w, cx, &*data.projection_ty.trait_ref);
|
||||
mywrite!(w, "{}|", token::get_name(data.projection_ty.item_name));
|
||||
enc_ty(w, cx, data.ty);
|
||||
}
|
||||
|
@ -1284,7 +1284,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
rbml_w.emit_trait_ref(ecx, &trait_ref.0);
|
||||
rbml_w.emit_trait_ref(ecx, &*trait_ref.0);
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1364,7 +1364,7 @@ trait rbml_decoder_decoder_helpers<'tcx> {
|
||||
fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> Rc<ty::TraitRef<'tcx>>;
|
||||
fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>;
|
||||
-> ty::PolyTraitRef<'tcx>;
|
||||
fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::TypeParameterDef<'tcx>;
|
||||
fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
@ -1558,8 +1558,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
||||
}
|
||||
|
||||
fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>> {
|
||||
Rc::new(ty::Binder(self.read_opaque(|this, doc| {
|
||||
-> ty::PolyTraitRef<'tcx> {
|
||||
ty::Binder(Rc::new(self.read_opaque(|this, doc| {
|
||||
let ty = tydecode::parse_trait_ref_data(
|
||||
doc.data,
|
||||
dcx.cdata.cnum,
|
||||
@ -1786,7 +1786,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
||||
Ok(this.read_poly_trait_ref(dcx))
|
||||
}));
|
||||
Ok(ty::TyTrait {
|
||||
principal: (*principal).clone(),
|
||||
principal: ty::Binder((*principal.0).clone()),
|
||||
bounds: try!(this.read_struct_field("bounds", 1, |this| {
|
||||
Ok(this.read_existential_bounds(dcx))
|
||||
})),
|
||||
|
@ -58,7 +58,7 @@ pub fn simplify_type(tcx: &ty::ctxt,
|
||||
ty::ty_vec(..) => Some(VecSimplifiedType),
|
||||
ty::ty_ptr(_) => Some(PtrSimplifiedType),
|
||||
ty::ty_trait(ref trait_info) => {
|
||||
Some(TraitSimplifiedType(trait_info.principal.def_id()))
|
||||
Some(TraitSimplifiedType(trait_info.principal_def_id()))
|
||||
}
|
||||
ty::ty_struct(def_id, _) => {
|
||||
Some(StructSimplifiedType(def_id))
|
||||
@ -86,6 +86,9 @@ pub fn simplify_type(tcx: &ty::ctxt,
|
||||
ty::ty_bare_fn(_, ref f) => {
|
||||
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
|
||||
}
|
||||
ty::ty_projection(_) => {
|
||||
None
|
||||
}
|
||||
ty::ty_param(_) => {
|
||||
if can_simplify_params {
|
||||
Some(ParameterSimplifiedType)
|
||||
|
@ -51,6 +51,7 @@ use middle::ty_fold;
|
||||
use middle::ty_fold::{TypeFoldable};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{Onceness, Unsafety};
|
||||
use syntax::ast;
|
||||
use syntax::abi;
|
||||
@ -358,6 +359,18 @@ pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
|
||||
}
|
||||
|
||||
impl<'tcx,T> Combineable<'tcx> for Rc<T>
|
||||
where T : Combineable<'tcx>
|
||||
{
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &Rc<T>,
|
||||
b: &Rc<T>)
|
||||
-> cres<'tcx, Rc<T>>
|
||||
{
|
||||
Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &ty::TraitRef<'tcx>,
|
||||
@ -581,6 +594,15 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
||||
})
|
||||
}
|
||||
|
||||
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
|
||||
if a_data.item_name == b_data.item_name {
|
||||
let trait_ref = try!(this.trait_refs(&a_data.trait_ref, &b_data.trait_ref));
|
||||
Ok(ty::mk_projection(tcx, trait_ref, a_data.item_name))
|
||||
} else {
|
||||
Err(ty::terr_sorts(expected_found(this, a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
_ => Err(ty::terr_sorts(expected_found(this, a, b)))
|
||||
};
|
||||
|
||||
|
@ -1437,6 +1437,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
format!(" for {}in generic type",
|
||||
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
|
||||
}
|
||||
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
|
||||
format!(" for {}in trait containing associated type `{}`",
|
||||
bound_region_to_string(self.tcx, "lifetime parameter ", true, br),
|
||||
token::get_name(type_name))
|
||||
}
|
||||
infer::EarlyBoundRegion(_, name) => {
|
||||
format!(" for lifetime parameter `{}`",
|
||||
token::get_name(name).get())
|
||||
@ -1661,13 +1666,16 @@ impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Resolvable<'tcx> for Rc<ty::PolyTraitRef<'tcx>> {
|
||||
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>> {
|
||||
Rc::new(infcx.resolve_type_vars_if_possible(&**self))
|
||||
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
|
||||
fn resolve<'a>(&self,
|
||||
infcx: &InferCtxt<'a, 'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
|
||||
fn contains_error(&self) -> bool {
|
||||
ty::trait_ref_contains_error(&self.0)
|
||||
ty::trait_ref_contains_error(&*self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
||||
ty::ty_struct(..) |
|
||||
ty::ty_unboxed_closure(..) |
|
||||
ty::ty_tup(..) |
|
||||
ty::ty_projection(..) |
|
||||
ty::ty_param(..) => {
|
||||
ty_fold::super_fold_ty(self, t)
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ pub enum TypeOrigin {
|
||||
pub enum ValuePairs<'tcx> {
|
||||
Types(ty::expected_found<Ty<'tcx>>),
|
||||
TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>),
|
||||
PolyTraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
|
||||
PolyTraitRefs(ty::expected_found<ty::PolyTraitRef<'tcx>>),
|
||||
}
|
||||
|
||||
/// The trace designates the path through inference that we took to
|
||||
@ -231,6 +231,9 @@ pub enum LateBoundRegionConversionTime {
|
||||
|
||||
/// when two higher-ranked types are compared
|
||||
HigherRankedType,
|
||||
|
||||
/// when projecting an associated type
|
||||
AssocTypeProjection(ast::Name),
|
||||
}
|
||||
|
||||
/// Reasons to create a region inference variable
|
||||
@ -407,8 +410,8 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
a_is_expected: bool,
|
||||
origin: TypeOrigin,
|
||||
a: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
b: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
{
|
||||
debug!("mk_sub_trait_refs({} <: {})",
|
||||
@ -703,8 +706,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub fn sub_poly_trait_refs(&self,
|
||||
a_is_expected: bool,
|
||||
origin: TypeOrigin,
|
||||
a: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
b: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
{
|
||||
debug!("sub_poly_trait_refs({} <: {})",
|
||||
@ -715,7 +718,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
origin: origin,
|
||||
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
|
||||
};
|
||||
self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures()
|
||||
self.sub(a_is_expected, trace).binders(&a, &b).to_ures()
|
||||
})
|
||||
}
|
||||
|
||||
@ -750,7 +753,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx>
|
||||
{
|
||||
/*! See `higher_ranked::leak_check` */
|
||||
/*! See `higher_ranked::plug_leaks` */
|
||||
|
||||
higher_ranked::plug_leaks(self, skol_map, snapshot, value)
|
||||
}
|
||||
|
@ -45,7 +45,9 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(),
|
||||
Rc::new(ty::Binder(impl1_trait_ref)));
|
||||
ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: Rc::new(impl1_trait_ref),
|
||||
}));
|
||||
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
|
||||
selcx.evaluate_impl(impl2_def_id, &obligation)
|
||||
}
|
||||
@ -140,7 +142,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
}
|
||||
|
||||
ty::ty_trait(ref tt) => {
|
||||
tt.principal.def_id().krate == ast::LOCAL_CRATE
|
||||
tt.principal_def_id().krate == ast::LOCAL_CRATE
|
||||
}
|
||||
|
||||
// Type parameters may be bound to types that are not local to
|
||||
@ -149,6 +151,11 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// Associated types could be anything, I guess.
|
||||
ty::ty_projection(..) => {
|
||||
false
|
||||
}
|
||||
|
||||
ty::ty_infer(..) |
|
||||
ty::ty_open(..) |
|
||||
ty::ty_err => {
|
||||
|
@ -8,12 +8,18 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::{FulfillmentError, FulfillmentErrorCode,
|
||||
ObligationCauseCode, SelectionError,
|
||||
PredicateObligation, OutputTypeParameterMismatch};
|
||||
use super::{
|
||||
FulfillmentError,
|
||||
FulfillmentErrorCode,
|
||||
MismatchedProjectionTypes,
|
||||
ObligationCauseCode,
|
||||
OutputTypeParameterMismatch,
|
||||
PredicateObligation,
|
||||
SelectionError,
|
||||
};
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{mod};
|
||||
use middle::ty::{mod, AsPredicate, ReferencesError, ToPolyTraitRef};
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
@ -30,12 +36,32 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
FulfillmentErrorCode::CodeSelectionError(ref e) => {
|
||||
report_selection_error(infcx, &error.obligation, e);
|
||||
}
|
||||
FulfillmentErrorCode::CodeProjectionError(ref e) => {
|
||||
report_projection_error(infcx, &error.obligation, e);
|
||||
}
|
||||
FulfillmentErrorCode::CodeAmbiguity => {
|
||||
maybe_report_ambiguity(infcx, &error.obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &MismatchedProjectionTypes<'tcx>)
|
||||
{
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
if !predicate.references_error() {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"type mismatch resolving `{}`: {}",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &error.err)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>)
|
||||
@ -43,38 +69,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
match *error {
|
||||
SelectionError::Overflow => {
|
||||
// We could track the stack here more precisely if we wanted, I imagine.
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the trait `{}` for the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
trait_ref.self_ty().user_string(infcx.tcx))[]);
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.equality_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!("overflow evaluating lifetime predicate").as_slice());
|
||||
}
|
||||
}
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
|
||||
let current_limit = infcx.tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
@ -87,27 +88,25 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
SelectionError::Unimplemented => {
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**trait_ref);
|
||||
if !ty::type_is_error(trait_ref.self_ty()) {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_predicate =
|
||||
infcx.resolve_type_vars_if_possible(trait_predicate);
|
||||
if !trait_predicate.references_error() {
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` is not implemented for the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.equality_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
|
||||
&predicate).unwrap_err();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
@ -116,9 +115,22 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(&obligation.trait_ref);
|
||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.region_outlives_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
@ -128,12 +140,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
|
||||
let expected_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**expected_trait_ref);
|
||||
let actual_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**actual_trait_ref);
|
||||
let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
|
||||
let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
|
||||
if !ty::type_is_error(actual_trait_ref.self_ty()) {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
@ -150,24 +158,26 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
// Unable to successfully determine, probably means
|
||||
// insufficient type information, but could mean
|
||||
// ambiguous impls. The latter *ought* to be a
|
||||
// coherence violation, so we don't report it here.
|
||||
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref)
|
||||
let trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.trait_ref.repr(infcx.tcx)).as_slice());
|
||||
obligation.predicate.repr(infcx.tcx)).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
let self_ty = trait_ref.self_ty();
|
||||
|
||||
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
|
||||
@ -208,7 +218,7 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
locate the impl of the trait `{}` for \
|
||||
the type `{}`; type annotations required",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx))[]);
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
@ -221,56 +231,38 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
cannot locate the impl of the trait `{}` for \
|
||||
the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx))[]);
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
{
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref)
|
||||
}
|
||||
_ => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.trait_ref.repr(infcx.tcx)).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
note_obligation_cause_code(infcx,
|
||||
&trait_ref,
|
||||
&obligation.predicate,
|
||||
obligation.cause.span,
|
||||
&obligation.cause.code)
|
||||
&obligation.cause.code);
|
||||
}
|
||||
|
||||
fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
_predicate: &ty::Predicate<'tcx>,
|
||||
cause_span: Span,
|
||||
cause_code: &ObligationCauseCode<'tcx>)
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
let trait_name = ty::item_path_str(tcx, trait_ref.def_id());
|
||||
match *cause_code {
|
||||
ObligationCauseCode::MiscObligation => { }
|
||||
ObligationCauseCode::ItemObligation(item_def_id) => {
|
||||
let item_name = ty::item_path_str(tcx, item_def_id);
|
||||
tcx.sess.span_note(
|
||||
cause_span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented because it is required by `{}`",
|
||||
trait_name,
|
||||
item_name).as_slice());
|
||||
format!("required by `{}`", item_name).as_slice());
|
||||
}
|
||||
ObligationCauseCode::ObjectCastObligation(object_ty) => {
|
||||
tcx.sess.span_note(
|
||||
cause_span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented for the cast \
|
||||
to the object type `{}`",
|
||||
trait_name,
|
||||
"required for the cast to the object type `{}`",
|
||||
infcx.ty_to_string(object_ty)).as_slice());
|
||||
}
|
||||
ObligationCauseCode::RepeatVec => {
|
||||
@ -323,27 +315,23 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"shared static variables must have a type that implements `Sync`");
|
||||
}
|
||||
ObligationCauseCode::BuiltinDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
|
||||
let root_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(&**root_trait_ref);
|
||||
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"the type `{}` must implement `{}` because it appears within the type `{}`",
|
||||
trait_ref.self_ty().user_string(infcx.tcx),
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.self_ty().user_string(infcx.tcx));
|
||||
note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
|
||||
"required because it appears within the type `{}`",
|
||||
parent_trait_ref.0.self_ty().user_string(infcx.tcx));
|
||||
let parent_predicate = parent_trait_ref.as_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
|
||||
let root_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(&**root_trait_ref);
|
||||
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"the type `{}` must implement `{}` due to the requirements \
|
||||
on the impl of `{}` for the type `{}`",
|
||||
trait_ref.self_ty().user_string(infcx.tcx),
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.self_ty().user_string(infcx.tcx));
|
||||
note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
|
||||
"required because of the requirements on the impl of `{}` for `{}`",
|
||||
parent_trait_ref.user_string(infcx.tcx),
|
||||
parent_trait_ref.0.self_ty().user_string(infcx.tcx));
|
||||
let parent_predicate = parent_trait_ref.as_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::infer::{mod, InferCtxt};
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::default::Default;
|
||||
@ -21,15 +21,16 @@ use util::ppaux::Repr;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use super::CodeAmbiguity;
|
||||
use super::CodeProjectionError;
|
||||
use super::CodeSelectionError;
|
||||
use super::FulfillmentError;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::PredicateObligation;
|
||||
use super::Selection;
|
||||
use super::project;
|
||||
use super::select::SelectionContext;
|
||||
use super::poly_trait_ref_for_builtin_bound;
|
||||
use super::Unimplemented;
|
||||
use super::util::predicate_for_builtin_bound;
|
||||
|
||||
/// The fulfillment context is used to drive trait resolution. It
|
||||
/// consists of a list of obligations that must be (eventually)
|
||||
@ -101,35 +102,41 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_associated_type<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
item_name: ast::Name,
|
||||
cause: ObligationCause<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
assert!(!trait_ref.has_escaping_regions());
|
||||
|
||||
let ty_var = infcx.next_ty_var();
|
||||
let projection =
|
||||
ty::Binder(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy { trait_ref: trait_ref,
|
||||
item_name: item_name },
|
||||
ty: ty_var
|
||||
});
|
||||
let obligation = Obligation::new(cause, projection.as_predicate());
|
||||
self.register_predicate(infcx.tcx, obligation);
|
||||
ty_var
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) {
|
||||
Ok(trait_ref) => {
|
||||
self.register_trait_ref(tcx, trait_ref, cause);
|
||||
match predicate_for_builtin_bound(tcx, cause, builtin_bound, 0, ty) {
|
||||
Ok(predicate) => {
|
||||
self.register_predicate(tcx, predicate);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_trait_ref<'a>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
/*!
|
||||
* A convenience function for registering trait obligations.
|
||||
*/
|
||||
|
||||
let trait_obligation = Obligation { cause: cause,
|
||||
recursion_depth: 0,
|
||||
predicate: ty::Predicate::Trait(trait_ref) };
|
||||
self.register_predicate(tcx, trait_obligation)
|
||||
}
|
||||
|
||||
pub fn register_region_obligation(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
t_a: Ty<'tcx>,
|
||||
@ -232,7 +239,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
debug!("select_where_possible({} obligations) iteration",
|
||||
count);
|
||||
|
||||
let mut selections = Vec::new();
|
||||
let mut new_obligations = Vec::new();
|
||||
|
||||
// If we are only attempting obligations we haven't seen yet,
|
||||
// then set `skip` to the number of obligations we've already
|
||||
@ -253,7 +260,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
let processed =
|
||||
if skip == 0 {
|
||||
process_predicate(selcx, predicate,
|
||||
&mut selections, &mut errors, region_obligations)
|
||||
&mut new_obligations, &mut errors, region_obligations)
|
||||
} else {
|
||||
skip -= 1;
|
||||
false
|
||||
@ -271,8 +278,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
|
||||
// Now go through all the successful ones,
|
||||
// registering any nested obligations for the future.
|
||||
for selection in selections.into_iter() {
|
||||
selection.map_move_nested(|p| self.register_predicate(tcx, p));
|
||||
for new_obligation in new_obligations.into_iter() {
|
||||
self.register_predicate(tcx, new_obligation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,7 +297,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
|
||||
fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
selections: &mut Vec<Selection<'tcx>>,
|
||||
new_obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
errors: &mut Vec<FulfillmentError<'tcx>>,
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
|
||||
-> bool
|
||||
@ -304,14 +311,14 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_obligation = obligation.with(trait_ref.clone());
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let trait_obligation = obligation.with(data.clone());
|
||||
match selcx.select(&trait_obligation) {
|
||||
Ok(None) => {
|
||||
false
|
||||
}
|
||||
Ok(Some(s)) => {
|
||||
selections.push(s);
|
||||
s.map_move_nested(|p| new_obligations.push(p));
|
||||
true
|
||||
}
|
||||
Err(selection_err) => {
|
||||
@ -372,6 +379,111 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let project_obligation = obligation.with(data.clone());
|
||||
let result = project::poly_project_and_unify_type(selcx, &project_obligation);
|
||||
debug!("poly_project_and_unify_type({}) = {}",
|
||||
project_obligation.repr(tcx),
|
||||
result.repr(tcx));
|
||||
match result {
|
||||
Ok(()) => {
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TooManyCandidates) => {
|
||||
// Without more type information, we can't say much.
|
||||
false
|
||||
}
|
||||
Err(project::ProjectionError::NoCandidate) => {
|
||||
// This means that we have a type like `<T as
|
||||
// Trait>::name = U` but we couldn't find any more
|
||||
// information. This could just be that we're in a
|
||||
// function like:
|
||||
//
|
||||
// fn foo<T:Trait>(...)
|
||||
//
|
||||
// in which case this is not an error. But it
|
||||
// might also mean we're in a situation where we
|
||||
// don't actually know that `T : Trait` holds,
|
||||
// which would be weird (e.g., if `T` was not a
|
||||
// parameter type but a normal type, like `int`).
|
||||
//
|
||||
// So what we do is to (1) add a requirement that
|
||||
// `T : Trait` (just in case) and (2) try to unify
|
||||
// `U` with `<T as Trait>::name`.
|
||||
|
||||
if !ty::binds_late_bound_regions(selcx.tcx(), data) {
|
||||
// Check that `T : Trait` holds.
|
||||
let trait_ref = data.to_poly_trait_ref();
|
||||
new_obligations.push(obligation.with(trait_ref.as_predicate()));
|
||||
|
||||
// Fallback to `<T as Trait>::name`. If this
|
||||
// fails, then the output must be at least
|
||||
// somewhat constrained, and we cannot verify
|
||||
// that constraint, so yield an error.
|
||||
let ty_projection = ty::mk_projection(tcx,
|
||||
(*trait_ref.0).clone(),
|
||||
data.0.projection_ty.item_name);
|
||||
|
||||
debug!("process_predicate: falling back to projection {}",
|
||||
ty_projection.repr(selcx.tcx()));
|
||||
|
||||
match infer::mk_eqty(selcx.infcx(),
|
||||
true,
|
||||
infer::EquatePredicate(obligation.cause.span),
|
||||
ty_projection,
|
||||
data.0.ty) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
debug!("process_predicate: fallback failed to unify; error");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
// If we have something like
|
||||
//
|
||||
// for<'a> <T<'a> as Trait>::name == &'a int
|
||||
//
|
||||
// there is no "canonical form" for us to
|
||||
// make, so just report the lack of candidates
|
||||
// as an error.
|
||||
|
||||
debug!("process_predicate: can't fallback, higher-ranked");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
Err(project::ProjectionError::MismatchedTypes(e)) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeProjectionError(e)));
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TraitSelectionError(e)) => {
|
||||
// Extract just the `T : Trait` from `<T as
|
||||
// Trait>::Name == U`, so that when we report an
|
||||
// error to the user, it says something like "`T :
|
||||
// Trait` not satisfied".5D
|
||||
let trait_predicate = data.to_poly_trait_ref();
|
||||
let trait_obligation = obligation.with(trait_predicate.as_predicate());
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
trait_obligation,
|
||||
CodeSelectionError(e)));
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,28 +18,32 @@ pub use self::ObligationCauseCode::*;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::InferCtxt;
|
||||
use std::rc::Rc;
|
||||
use std::slice::Iter;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
||||
pub use self::project::MismatchedProjectionTypes;
|
||||
pub use self::project::project_type;
|
||||
pub use self::project::ProjectionResult;
|
||||
pub use self::select::SelectionContext;
|
||||
pub use self::select::SelectionCache;
|
||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::trait_ref_for_builtin_bound;
|
||||
pub use self::util::supertraits;
|
||||
pub use self::util::Supertraits;
|
||||
pub use self::util::search_trait_and_supertraits_from_bound;
|
||||
pub use self::util::transitive_bounds;
|
||||
pub use self::util::poly_trait_ref_for_builtin_bound;
|
||||
|
||||
mod coherence;
|
||||
mod error_reporting;
|
||||
mod fulfill;
|
||||
mod project;
|
||||
mod select;
|
||||
mod util;
|
||||
|
||||
@ -57,7 +61,7 @@ pub struct Obligation<'tcx, T> {
|
||||
}
|
||||
|
||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::PolyTraitRef<'tcx>>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||
|
||||
/// Why did we incur this obligation? Used for error reporting.
|
||||
#[deriving(Clone)]
|
||||
@ -107,9 +111,18 @@ pub enum ObligationCauseCode<'tcx> {
|
||||
// static items must have `Sync` type
|
||||
SharedStatic,
|
||||
|
||||
BuiltinDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
|
||||
|
||||
ImplDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
ImplDerivedObligation(DerivedObligationCause<'tcx>),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct DerivedObligationCause<'tcx> {
|
||||
/// Resolving this trait led to the current obligation
|
||||
parent_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
/// The parent trait had this cause
|
||||
parent_code: Rc<ObligationCauseCode<'tcx>>
|
||||
}
|
||||
|
||||
pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
|
||||
@ -122,8 +135,8 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
||||
pub enum SelectionError<'tcx> {
|
||||
Unimplemented,
|
||||
Overflow,
|
||||
OutputTypeParameterMismatch(Rc<ty::PolyTraitRef<'tcx>>,
|
||||
Rc<ty::PolyTraitRef<'tcx>>,
|
||||
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::type_err<'tcx>),
|
||||
}
|
||||
|
||||
@ -135,6 +148,7 @@ pub struct FulfillmentError<'tcx> {
|
||||
#[deriving(Clone)]
|
||||
pub enum FulfillmentErrorCode<'tcx> {
|
||||
CodeSelectionError(SelectionError<'tcx>),
|
||||
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||
CodeAmbiguity,
|
||||
}
|
||||
|
||||
@ -235,7 +249,7 @@ pub struct VtableBuiltinData<N> {
|
||||
#[deriving(PartialEq,Eq,Clone)]
|
||||
pub struct VtableParamData<'tcx> {
|
||||
// In the above example, this would `Eq`
|
||||
pub bound: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
pub bound: ty::PolyTraitRef<'tcx>,
|
||||
}
|
||||
|
||||
/// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
|
||||
@ -324,12 +338,6 @@ impl<'tcx,O> Obligation<'tcx,O> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.predicate.self_ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationCause<'tcx> {
|
||||
pub fn new(span: Span,
|
||||
body_id: ast::NodeId,
|
||||
@ -441,6 +449,13 @@ impl<'tcx> FulfillmentError<'tcx> {
|
||||
CodeAmbiguity => false,
|
||||
CodeSelectionError(Overflow) => true,
|
||||
CodeSelectionError(_) => false,
|
||||
CodeProjectionError(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.predicate.0.self_ty()
|
||||
}
|
||||
}
|
||||
|
374
src/librustc/middle/traits/project.rs
Normal file
374
src/librustc/middle/traits/project.rs
Normal file
@ -0,0 +1,374 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Code for projecting associated types out of trait references.
|
||||
|
||||
use super::elaborate_predicates;
|
||||
use super::Obligation;
|
||||
use super::PredicateObligation;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
use super::VtableImplData;
|
||||
|
||||
use middle::infer;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, ToPolyTraitRef, Ty};
|
||||
use std::fmt;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub type PolyProjectionObligation<'tcx> =
|
||||
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
|
||||
|
||||
pub type ProjectionObligation<'tcx> =
|
||||
Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
|
||||
|
||||
pub type ProjectionTyObligation<'tcx> =
|
||||
Obligation<'tcx, ty::ProjectionTy<'tcx>>;
|
||||
|
||||
/// When attempting to resolve `<T as TraitRef>::Name == U`...
|
||||
pub enum ProjectionError<'tcx> {
|
||||
NoCandidate,
|
||||
TooManyCandidates,
|
||||
|
||||
///
|
||||
MismatchedTypes(MismatchedProjectionTypes<'tcx>),
|
||||
|
||||
/// ...an error occurred matching `T : TraitRef`
|
||||
TraitSelectionError(SelectionError<'tcx>),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MismatchedProjectionTypes<'tcx> {
|
||||
pub err: ty::type_err<'tcx> // TODO expected/actual/etc
|
||||
}
|
||||
|
||||
pub type ProjectionResult<'tcx, T> = Result<T, ProjectionError<'tcx>>;
|
||||
|
||||
enum ProjectionTyCandidate<'tcx> {
|
||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
|
||||
}
|
||||
|
||||
struct ProjectionTyCandidateSet<'tcx> {
|
||||
vec: Vec<ProjectionTyCandidate<'tcx>>,
|
||||
ambiguous: bool
|
||||
}
|
||||
|
||||
pub fn poly_project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &PolyProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
debug!("poly_project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
infcx.try(|snapshot| {
|
||||
let (skol_predicate, skol_map) =
|
||||
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
|
||||
let skol_obligation = obligation.with(skol_predicate);
|
||||
let () = try!(project_and_unify_type(selcx, &skol_obligation));
|
||||
match infcx.leak_check(&skol_map, snapshot) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute result of projecting an associated type and unify it with
|
||||
/// `obligation.predicate.ty` (if we can).
|
||||
pub fn project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
debug!("project_and_unify(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let ty_obligation = obligation.with(obligation.predicate.projection_ty.clone());
|
||||
let projected_ty = try!(project_type(selcx, &ty_obligation));
|
||||
let infcx = selcx.infcx();
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
debug!("project_and_unify_type: projected_ty = {}", projected_ty.repr(selcx.tcx()));
|
||||
match infer::mk_eqty(infcx, true, origin, projected_ty, obligation.predicate.ty) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the result of a projection type (if we can).
|
||||
pub fn project_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
debug!("project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let mut candidates = ProjectionTyCandidateSet {
|
||||
vec: Vec::new(),
|
||||
ambiguous: false,
|
||||
};
|
||||
|
||||
let () = assemble_candidates_from_param_env(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
let () = try!(assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates));
|
||||
|
||||
debug!("{} candidates, ambiguous={}",
|
||||
candidates.vec.len(),
|
||||
candidates.ambiguous);
|
||||
|
||||
// We probably need some winnowing logic similar to select here.
|
||||
|
||||
if candidates.ambiguous || candidates.vec.len() > 1 {
|
||||
return Err(ProjectionError::TooManyCandidates);
|
||||
}
|
||||
|
||||
match candidates.vec.pop() {
|
||||
Some(candidate) => {
|
||||
Ok(try!(confirm_candidate(selcx, obligation, candidate)))
|
||||
}
|
||||
None => {
|
||||
Err(ProjectionError::NoCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The first thing we have to do is scan through the parameter
|
||||
/// environment to see whether there are any projection predicates
|
||||
/// there that can answer this question.
|
||||
fn assemble_candidates_from_param_env<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
let env_predicates = selcx.param_env().caller_bounds.predicates.clone();
|
||||
let env_predicates = env_predicates.iter().cloned().collect();
|
||||
for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
|
||||
match predicate {
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let is_match = infcx.probe(|_| {
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
let obligation_poly_trait_ref =
|
||||
obligation.predicate.trait_ref.to_poly_trait_ref();
|
||||
let data_poly_trait_ref =
|
||||
data.to_poly_trait_ref();
|
||||
infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
obligation_poly_trait_ref,
|
||||
data_poly_trait_ref).is_ok()
|
||||
});
|
||||
|
||||
if is_match {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::ParamEnv(data.clone()));
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||
let trait_ref =
|
||||
obligation.predicate.trait_ref.to_poly_trait_ref();
|
||||
let trait_obligation =
|
||||
obligation.with(trait_ref.to_poly_trait_predicate());
|
||||
let vtable = match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
Ok(None) => {
|
||||
candidate_set.ambiguous = true;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("assemble_candidates_from_impls: selection error {}",
|
||||
e.repr(selcx.tcx()));
|
||||
return Err(ProjectionError::TraitSelectionError(e));
|
||||
}
|
||||
};
|
||||
|
||||
match vtable {
|
||||
super::VtableImpl(data) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Impl(data));
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
//
|
||||
// ```
|
||||
// trait SomeTrait { type Foo; }
|
||||
// fn foo<T:SomeTrait>(...) { }
|
||||
// ```
|
||||
//
|
||||
// If the user writes `<T as SomeTrait>::Foo`, then the `T
|
||||
// : SomeTrait` binding does not help us decide what the
|
||||
// type `Foo` is (at least, not more specifically than
|
||||
// what we already knew).
|
||||
//
|
||||
// But wait, you say! What about an example like this:
|
||||
//
|
||||
// ```
|
||||
// fn bar<T:SomeTrait<Foo=uint>>(...) { ... }
|
||||
// ```
|
||||
//
|
||||
// Doesn't the `T : Sometrait<Foo=uint>` predicate help
|
||||
// resolve `T::Foo`? And of course it does, but in fact
|
||||
// that single predicate is desugared into two predicates
|
||||
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
||||
// projection. And the projection where clause is handled
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
}
|
||||
super::VtableBuiltin(..) |
|
||||
super::VtableUnboxedClosure(..) |
|
||||
super::VtableFnPointer(..) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Cannot project an associated type from `{}`",
|
||||
vtable.repr(selcx.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn confirm_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate: ProjectionTyCandidate<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
debug!("confirm_candidate(candidate={}, obligation={})",
|
||||
candidate.repr(infcx.tcx),
|
||||
obligation.repr(infcx.tcx));
|
||||
|
||||
let projected_ty = match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||
let projection =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_projection).0;
|
||||
|
||||
assert_eq!(projection.projection_ty.item_name,
|
||||
obligation.predicate.item_name);
|
||||
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match infcx.sub_trait_refs(false,
|
||||
origin,
|
||||
obligation.predicate.trait_ref.clone(),
|
||||
projection.projection_ty.trait_ref.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Failed to unify `{}` and `{}` in projection: {}",
|
||||
obligation.repr(selcx.tcx()),
|
||||
projection.repr(selcx.tcx()),
|
||||
ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
projection.ty
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Impl(impl_vtable) => {
|
||||
// there don't seem to be nicer accessors to these:
|
||||
let impl_items_map = selcx.tcx().impl_items.borrow();
|
||||
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
|
||||
|
||||
let impl_items = &impl_items_map[impl_vtable.impl_def_id];
|
||||
let mut impl_ty = None;
|
||||
for impl_item in impl_items.iter() {
|
||||
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
|
||||
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
|
||||
ty::MethodTraitItem(..) => { continue; }
|
||||
};
|
||||
|
||||
if assoc_type.name != obligation.predicate.item_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
|
||||
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
|
||||
break;
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("impl `{}` did not contain projection for `{}`",
|
||||
impl_vtable.repr(selcx.tcx()),
|
||||
obligation.repr(selcx.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(projected_ty)
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
self.err.repr(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ProjectionError::NoCandidate =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::TooManyCandidates =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::MismatchedTypes(ref m) =>
|
||||
format!("MismatchedTypes({})", m.repr(tcx)),
|
||||
ProjectionError::TraitSelectionError(ref e) =>
|
||||
format!("TraitSelectionError({})", e.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Show for super::MismatchedProjectionTypes<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MismatchedProjectionTypes(..)")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ProjectionTyCandidate::ParamEnv(ref data) =>
|
||||
format!("ParamEnv({})", data.repr(tcx)),
|
||||
ProjectionTyCandidate::Impl(ref data) =>
|
||||
format!("Impl({})", data.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,11 @@
|
||||
|
||||
pub use self::MethodMatchResult::*;
|
||||
pub use self::MethodMatchedData::*;
|
||||
use self::Candidate::*;
|
||||
use self::SelectionCandidate::*;
|
||||
use self::BuiltinBoundConditions::*;
|
||||
use self::EvaluationResult::*;
|
||||
|
||||
use super::{DerivedObligationCause};
|
||||
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
|
||||
use super::{ObligationCauseCode, BuiltinDerivedObligation};
|
||||
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
|
||||
@ -29,7 +30,7 @@ use super::{util};
|
||||
use middle::fast_reject;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, Ty};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use middle::infer;
|
||||
use middle::infer::{InferCtxt, TypeFreshener};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
@ -75,15 +76,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
|
||||
|
||||
/// Trait ref from `obligation` but skolemized with the
|
||||
/// selection-context's freshener. Used to check for recursion.
|
||||
fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct SelectionCache<'tcx> {
|
||||
hashmap: RefCell<HashMap<Rc<ty::PolyTraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, Candidate<'tcx>>>>,
|
||||
hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
|
||||
}
|
||||
|
||||
pub enum MethodMatchResult {
|
||||
@ -128,7 +129,7 @@ pub enum MethodMatchedData {
|
||||
/// clauses can give additional information (like, the types of output
|
||||
/// parameters) that would have to be inferred from the impl.
|
||||
#[deriving(PartialEq,Eq,Show,Clone)]
|
||||
enum Candidate<'tcx> {
|
||||
enum SelectionCandidate<'tcx> {
|
||||
BuiltinCandidate(ty::BuiltinBound),
|
||||
ParamCandidate(VtableParamData<'tcx>),
|
||||
ImplCandidate(ast::DefId),
|
||||
@ -144,8 +145,8 @@ enum Candidate<'tcx> {
|
||||
ErrorCandidate,
|
||||
}
|
||||
|
||||
struct CandidateSet<'tcx> {
|
||||
vec: Vec<Candidate<'tcx>>,
|
||||
struct SelectionCandidateSet<'tcx> {
|
||||
vec: Vec<SelectionCandidate<'tcx>>,
|
||||
ambiguous: bool
|
||||
}
|
||||
|
||||
@ -193,6 +194,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.infcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
@ -302,6 +307,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// evaluating trait matches
|
||||
EvaluatedToOk
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) => {
|
||||
// FIXME(#20296) -- we should be able to give a more precise answer here
|
||||
EvaluatedToAmbig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,9 +421,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot);
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
match self.match_impl(impl_def_id, obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref)) {
|
||||
&skol_map, skol_obligation_trait_ref.trait_ref.clone()) {
|
||||
Ok(substs) => {
|
||||
let vtable_impl = self.vtable_impl(impl_def_id,
|
||||
substs,
|
||||
@ -439,7 +449,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn candidate_from_obligation<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> SelectionResult<'tcx, Candidate<'tcx>>
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
|
||||
{
|
||||
// Watch out for overflow. This intentionally bypasses (and does
|
||||
// not update) the cache.
|
||||
@ -455,17 +465,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// separately rather than using `stack.fresh_trait_ref` -- this
|
||||
// is because we want the unbound variables to be replaced
|
||||
// with fresh skolemized types starting from index 0.
|
||||
let cache_fresh_trait_ref =
|
||||
let cache_fresh_trait_pred =
|
||||
self.infcx.freshen(stack.obligation.predicate.clone());
|
||||
debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})",
|
||||
cache_fresh_trait_ref.repr(self.tcx()),
|
||||
debug!("candidate_from_obligation(cache_fresh_trait_pred={}, obligation={})",
|
||||
cache_fresh_trait_pred.repr(self.tcx()),
|
||||
stack.repr(self.tcx()));
|
||||
assert!(!stack.obligation.predicate.has_escaping_regions());
|
||||
|
||||
match self.check_candidate_cache(cache_fresh_trait_ref.clone()) {
|
||||
match self.check_candidate_cache(&cache_fresh_trait_pred) {
|
||||
Some(c) => {
|
||||
debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}",
|
||||
cache_fresh_trait_ref.repr(self.tcx()),
|
||||
debug!("CACHE HIT: cache_fresh_trait_pred={}, candidate={}",
|
||||
cache_fresh_trait_pred.repr(self.tcx()),
|
||||
c.repr(self.tcx()));
|
||||
return c;
|
||||
}
|
||||
@ -474,17 +484,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
// If no match, compute result and insert into cache.
|
||||
let candidate = self.candidate_from_obligation_no_cache(stack);
|
||||
debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}",
|
||||
cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx()));
|
||||
self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone());
|
||||
debug!("CACHE MISS: cache_fresh_trait_pred={}, candidate={}",
|
||||
cache_fresh_trait_pred.repr(self.tcx()), candidate.repr(self.tcx()));
|
||||
self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
|
||||
candidate
|
||||
}
|
||||
|
||||
fn candidate_from_obligation_no_cache<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> SelectionResult<'tcx, Candidate<'tcx>>
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
|
||||
{
|
||||
if ty::type_is_error(stack.obligation.self_ty()) {
|
||||
if ty::type_is_error(stack.obligation.predicate.0.self_ty()) {
|
||||
return Ok(Some(ErrorCandidate));
|
||||
}
|
||||
|
||||
@ -576,7 +586,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
fn pick_candidate_cache(&self,
|
||||
cache_fresh_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>)
|
||||
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
|
||||
-> &SelectionCache<'tcx>
|
||||
{
|
||||
// High-level idea: we have to decide whether to consult the
|
||||
@ -598,7 +608,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// If the trait refers to any parameters in scope, then use
|
||||
// the cache of the param-environment.
|
||||
if
|
||||
cache_fresh_trait_ref.0.input_types().iter().any(
|
||||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
@ -611,7 +621,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// See the discussion in doc.rs for more details.
|
||||
if
|
||||
!self.param_env.caller_bounds.is_empty() &&
|
||||
cache_fresh_trait_ref.0.input_types().iter().any(
|
||||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_ty_infer(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
@ -622,32 +632,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
fn check_candidate_cache(&mut self,
|
||||
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
-> Option<SelectionResult<'tcx, Candidate<'tcx>>>
|
||||
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
|
||||
-> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
|
||||
{
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||
let cache = self.pick_candidate_cache(cache_fresh_trait_pred);
|
||||
let hashmap = cache.hashmap.borrow();
|
||||
hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone())
|
||||
hashmap.get(&cache_fresh_trait_pred.0.trait_ref).map(|c| (*c).clone())
|
||||
}
|
||||
|
||||
fn insert_candidate_cache(&mut self,
|
||||
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
candidate: SelectionResult<'tcx, Candidate<'tcx>>)
|
||||
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
|
||||
{
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_pred);
|
||||
let mut hashmap = cache.hashmap.borrow_mut();
|
||||
hashmap.insert(cache_fresh_trait_ref, candidate);
|
||||
hashmap.insert(cache_fresh_trait_pred.0.trait_ref.clone(), candidate);
|
||||
}
|
||||
|
||||
fn assemble_candidates<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> Result<CandidateSet<'tcx>, SelectionError<'tcx>>
|
||||
-> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
|
||||
{
|
||||
// Check for overflow.
|
||||
|
||||
let TraitObligationStack { obligation, .. } = *stack;
|
||||
|
||||
let mut candidates = CandidateSet {
|
||||
let mut candidates = SelectionCandidateSet {
|
||||
vec: Vec::new(),
|
||||
ambiguous: false
|
||||
};
|
||||
@ -658,7 +668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
|
||||
Some(ty::BoundCopy) => {
|
||||
debug!("obligation self ty is {}",
|
||||
obligation.self_ty().repr(self.tcx()));
|
||||
obligation.predicate.0.self_ty().repr(self.tcx()));
|
||||
|
||||
// If the user has asked for the older, compatibility
|
||||
// behavior, ignore user-defined impls here. This will
|
||||
@ -707,7 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// Never affects inference environment.
|
||||
fn assemble_candidates_from_caller_bounds(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
debug!("assemble_candidates_from_caller_bounds({})",
|
||||
@ -715,7 +725,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
let caller_trait_refs: Vec<_> =
|
||||
self.param_env.caller_bounds.predicates.iter()
|
||||
.filter_map(|o| o.to_trait())
|
||||
.filter_map(|o| o.to_opt_poly_trait_ref())
|
||||
.collect();
|
||||
|
||||
let all_bounds =
|
||||
@ -744,10 +754,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// unified during the confirmation step.
|
||||
fn assemble_unboxed_closure_candidates(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
let kind = match self.fn_family_trait_kind(obligation.predicate.def_id()) {
|
||||
let kind = match self.fn_family_trait_kind(obligation.predicate.0.def_id()) {
|
||||
Some(k) => k,
|
||||
None => { return Ok(()); }
|
||||
};
|
||||
@ -789,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// Implement one of the `Fn()` family for a fn pointer.
|
||||
fn assemble_fn_pointer_candidates(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
// We provide a `Fn` impl for fn pointers. There is no need to provide
|
||||
@ -827,16 +837,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// Search for impls that might apply to `obligation`.
|
||||
fn assemble_candidates_from_impls(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidate_vec: &mut Vec<Candidate<'tcx>>)
|
||||
candidate_vec: &mut Vec<SelectionCandidate<'tcx>>)
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
let all_impls = self.all_impls(obligation.predicate.def_id());
|
||||
for &impl_def_id in all_impls.iter() {
|
||||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot);
|
||||
let (skol_obligation_trait_pred, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
match self.match_impl(impl_def_id, obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref)) {
|
||||
&skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
|
||||
Ok(_) => {
|
||||
candidate_vec.push(ImplCandidate(impl_def_id));
|
||||
}
|
||||
@ -861,7 +871,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// scrutiny.
|
||||
fn winnow_candidate<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidate: &Candidate<'tcx>)
|
||||
candidate: &SelectionCandidate<'tcx>)
|
||||
-> EvaluationResult<'tcx>
|
||||
{
|
||||
debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx()));
|
||||
@ -918,8 +928,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// a case where doing the opposite caused us harm.
|
||||
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidate_i: &Candidate<'tcx>,
|
||||
candidate_j: &Candidate<'tcx>)
|
||||
candidate_i: &SelectionCandidate<'tcx>,
|
||||
candidate_j: &SelectionCandidate<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
match (candidate_i, candidate_j) {
|
||||
@ -931,16 +941,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(
|
||||
&*stack.obligation.predicate, snapshot);
|
||||
&stack.obligation.predicate, snapshot);
|
||||
let impl_substs =
|
||||
self.rematch_impl(impl_def_id, stack.obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref));
|
||||
&skol_map, skol_obligation_trait_ref.trait_ref.clone());
|
||||
let impl_trait_ref =
|
||||
ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
|
||||
let impl_trait_ref =
|
||||
impl_trait_ref.subst(self.tcx(), &impl_substs);
|
||||
let poly_impl_trait_ref =
|
||||
Rc::new(ty::Binder((*impl_trait_ref).clone()));
|
||||
ty::Binder(impl_trait_ref);
|
||||
let origin =
|
||||
infer::RelateOutputImplTypes(stack.obligation.cause.span);
|
||||
self.infcx
|
||||
@ -966,7 +976,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
fn assemble_builtin_bound_candidates<'o>(&mut self,
|
||||
bound: ty::BuiltinBound,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
match self.builtin_bound(bound, stack.obligation) {
|
||||
@ -987,7 +997,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation: &TraitObligation<'tcx>)
|
||||
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
|
||||
{
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
// TODO seems like we ought to skolemize here, oder?
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
|
||||
return match self_ty.sty {
|
||||
ty::ty_infer(ty::IntVar(_)) |
|
||||
ty::ty_infer(ty::FloatVar(_)) |
|
||||
@ -1269,6 +1280,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
nominal(self, bound, def_id, types)
|
||||
}
|
||||
|
||||
ty::ty_projection(_) |
|
||||
ty::ty_param(_) => {
|
||||
// Note: A type parameter is only considered to meet a
|
||||
// particular bound if there is a where clause telling
|
||||
@ -1360,7 +1372,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn confirm_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidate: Candidate<'tcx>)
|
||||
candidate: SelectionCandidate<'tcx>)
|
||||
-> Result<Selection<'tcx>,SelectionError<'tcx>>
|
||||
{
|
||||
debug!("confirm_candidate({}, {})",
|
||||
@ -1416,7 +1428,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// trait-ref. Repeat that unification now without any
|
||||
// transactional boundary; it should not fail.
|
||||
match self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.predicate.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
param.bound.clone()) {
|
||||
Ok(()) => Ok(param),
|
||||
Err(_) => {
|
||||
@ -1501,9 +1513,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// this time not in a probe.
|
||||
self.infcx.try(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot);
|
||||
let substs = self.rematch_impl(impl_def_id, obligation,
|
||||
snapshot, &skol_map, Rc::new(skol_obligation_trait_ref));
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
let substs =
|
||||
self.rematch_impl(impl_def_id, obligation,
|
||||
snapshot, &skol_map, skol_obligation_trait_ref.trait_ref);
|
||||
debug!("confirm_impl_candidate substs={}", substs);
|
||||
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1, skol_map, snapshot))
|
||||
@ -1574,13 +1587,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
vec![],
|
||||
vec![],
|
||||
self_ty);
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef {
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(substs),
|
||||
}));
|
||||
|
||||
try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.predicate.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
trait_ref));
|
||||
Ok(self_ty)
|
||||
}
|
||||
@ -1615,7 +1628,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
vec![],
|
||||
vec![],
|
||||
obligation.self_ty());
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef {
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(substs),
|
||||
}));
|
||||
@ -1625,7 +1638,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
trait_ref.repr(self.tcx()));
|
||||
|
||||
self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.predicate.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
trait_ref)
|
||||
}
|
||||
|
||||
@ -1656,8 +1669,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// report an error to the user.
|
||||
fn confirm_poly_trait_refs(&mut self,
|
||||
obligation_cause: ObligationCause,
|
||||
obligation_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
expected_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
obligation_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
expected_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
let origin = infer::RelateOutputImplTypes(obligation_cause.span);
|
||||
@ -1770,7 +1783,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// substitution if we find that any of the input types, when
|
||||
// simplified, do not match.
|
||||
|
||||
obligation.predicate.input_types().iter()
|
||||
obligation.predicate.0.input_types().iter()
|
||||
.zip(impl_trait_ref.input_types().iter())
|
||||
.any(|(&obligation_ty, &impl_ty)| {
|
||||
let simplified_obligation_ty =
|
||||
@ -1786,7 +1799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn match_where_clause(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
where_clause_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(),()>
|
||||
{
|
||||
debug!("match_where_clause: obligation={} where_clause_trait_ref={}",
|
||||
@ -1797,7 +1810,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match self.infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
where_clause_trait_ref,
|
||||
obligation.predicate.clone()) {
|
||||
obligation.predicate.to_poly_trait_ref()) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
@ -1879,7 +1892,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation: &'o TraitObligation<'tcx>)
|
||||
-> TraitObligationStack<'o, 'tcx>
|
||||
{
|
||||
let fresh_trait_ref = obligation.predicate.fold_with(&mut self.freshener);
|
||||
let fresh_trait_ref =
|
||||
obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
|
||||
|
||||
TraitObligationStack {
|
||||
obligation: obligation,
|
||||
@ -1932,9 +1946,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
#[allow(unused_comparisons)]
|
||||
fn derived_cause(&self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
variant: fn(Rc<ty::Binder<ty::TraitRef<'tcx>>>,
|
||||
Rc<ObligationCauseCode<'tcx>>)
|
||||
-> ObligationCauseCode<'tcx>)
|
||||
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
|
||||
-> ObligationCause<'tcx>
|
||||
{
|
||||
/*!
|
||||
@ -1951,17 +1963,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// chain. Ideally, we should have a way to configure this either
|
||||
// by using -Z verbose or just a CLI argument.
|
||||
if obligation.recursion_depth >= 0 {
|
||||
let derived_cause = DerivedObligationCause {
|
||||
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
|
||||
parent_code: Rc::new(obligation.cause.code.clone()),
|
||||
};
|
||||
ObligationCause::new(obligation.cause.span,
|
||||
obligation.trait_ref.def_id().node,
|
||||
variant(obligation.trait_ref.clone(),
|
||||
Rc::new(obligation.cause.code.clone())))
|
||||
obligation.cause.body_id,
|
||||
variant(derived_cause))
|
||||
} else {
|
||||
obligation.cause.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ErrorCandidate => format!("ErrorCandidate"),
|
||||
@ -2021,8 +2036,7 @@ impl<'tcx> EvaluationResult<'tcx> {
|
||||
EvaluatedToOk |
|
||||
EvaluatedToAmbig |
|
||||
EvaluatedToErr(Overflow) |
|
||||
EvaluatedToErr(OutputTypeParameterMismatch(..)) |
|
||||
EvaluatedToErr(ProjectionMismatch(..)) => {
|
||||
EvaluatedToErr(OutputTypeParameterMismatch(..)) => {
|
||||
true
|
||||
}
|
||||
EvaluatedToErr(Unimplemented) => {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef};
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
@ -46,19 +46,19 @@ struct StackEntry<'tcx> {
|
||||
|
||||
pub fn elaborate_trait_ref<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)])
|
||||
elaborate_predicates(tcx, vec![trait_ref.as_predicate()])
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_refs: &[Rc<ty::PolyTraitRef<'tcx>>])
|
||||
trait_refs: &[ty::PolyTraitRef<'tcx>])
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
let predicates = trait_refs.iter()
|
||||
.map(|trait_ref| ty::Predicate::Trait((*trait_ref).clone()))
|
||||
.map(|trait_ref| trait_ref.as_predicate())
|
||||
.collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
@ -80,21 +80,28 @@ pub fn elaborate_predicates<'cx, 'tcx>(
|
||||
impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
|
||||
fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let mut predicates =
|
||||
ty::predicates_for_trait_ref(self.tcx, &**trait_ref);
|
||||
ty::predicates_for_trait_ref(self.tcx,
|
||||
&data.to_poly_trait_ref());
|
||||
|
||||
// Only keep those bounds that we haven't already
|
||||
// seen. This is necessary to prevent infinite
|
||||
// recursion in some cases. One common case is when
|
||||
// people define `trait Sized { }` rather than `trait
|
||||
// Sized for Sized? { }`.
|
||||
predicates.retain(|r| self.visited.insert((*r).clone()));
|
||||
predicates.retain(|r| self.visited.insert(r.clone()));
|
||||
|
||||
self.stack.push(StackEntry { position: 0,
|
||||
predicates: predicates });
|
||||
}
|
||||
ty::Predicate::Equate(..) => {
|
||||
// Currently, we do not "elaborate" predicates like
|
||||
// `X == Y`, though conceivably we might. For example,
|
||||
// `&X == &Y` implies that `X == Y`.
|
||||
}
|
||||
ty::Predicate::Projection(..) => {
|
||||
// Nothing to elaborate in a projection predicate.
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
@ -173,7 +180,7 @@ pub struct Supertraits<'cx, 'tcx:'cx> {
|
||||
}
|
||||
|
||||
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_ref(tcx, trait_ref);
|
||||
@ -181,26 +188,24 @@ pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
bounds: &[Rc<ty::PolyTraitRef<'tcx>>])
|
||||
bounds: &[ty::PolyTraitRef<'tcx>])
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_refs(tcx, bounds);
|
||||
Supertraits { elaborator: elaborator }
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator<Rc<ty::PolyTraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<Rc<ty::PolyTraitRef<'tcx>>> {
|
||||
impl<'cx, 'tcx> Iterator<ty::PolyTraitRef<'tcx>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
loop {
|
||||
match self.elaborator.next() {
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
Some(ty::Predicate::Trait(trait_ref)) => {
|
||||
return Some(trait_ref);
|
||||
Some(ty::Predicate::Trait(data)) => {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
Some(ty::Predicate::Equate(..)) |
|
||||
Some(ty::Predicate::RegionOutlives(..)) |
|
||||
Some(ty::Predicate::TypeOutlives(..)) => {
|
||||
Some(_) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,18 +270,18 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn poly_trait_ref_for_builtin_bound<'tcx>(
|
||||
pub fn trait_ref_for_builtin_bound<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
param_ty: Ty<'tcx>)
|
||||
-> Result<Rc<ty::PolyTraitRef<'tcx>>, ErrorReported>
|
||||
-> Result<Rc<ty::TraitRef<'tcx>>, ErrorReported>
|
||||
{
|
||||
match tcx.lang_items.from_builtin_kind(builtin_bound) {
|
||||
Ok(def_id) => {
|
||||
Ok(Rc::new(ty::Binder(ty::TraitRef {
|
||||
Ok(Rc::new(ty::TraitRef {
|
||||
def_id: def_id,
|
||||
substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty))
|
||||
})))
|
||||
}))
|
||||
}
|
||||
Err(e) => {
|
||||
tcx.sess.err(e.as_slice());
|
||||
@ -293,11 +298,11 @@ pub fn predicate_for_builtin_bound<'tcx>(
|
||||
param_ty: Ty<'tcx>)
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
{
|
||||
let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
Ok(Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
predicate: ty::Predicate::Trait(trait_ref),
|
||||
predicate: trait_ref.as_predicate(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -306,7 +311,7 @@ pub fn predicate_for_builtin_bound<'tcx>(
|
||||
/// true, where `d` is the def-id of the trait/supertrait. If any is found, return `Some(p)` where
|
||||
/// `p` is the path to that trait/supertrait. Else `None`.
|
||||
pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>,
|
||||
caller_bound: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
caller_bound: ty::PolyTraitRef<'tcx>,
|
||||
mut test: F)
|
||||
-> Option<VtableParamData<'tcx>>
|
||||
where F: FnMut(ast::DefId) -> bool,
|
||||
@ -390,12 +395,6 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
|
||||
a.repr(tcx),
|
||||
b.repr(tcx),
|
||||
c.repr(tcx)),
|
||||
|
||||
super::ProjectionMismatch(ref a, ref b, ref c) =>
|
||||
format!("PrjectionMismatch({},{},{})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx),
|
||||
c.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,6 +411,7 @@ impl<'tcx> Repr<'tcx> for super::FulfillmentErrorCode<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
super::CodeSelectionError(ref o) => o.repr(tcx),
|
||||
super::CodeProjectionError(ref o) => o.repr(tcx),
|
||||
super::CodeAmbiguity => format!("Ambiguity")
|
||||
}
|
||||
}
|
||||
@ -421,6 +421,7 @@ impl<'tcx> fmt::Show for super::FulfillmentErrorCode<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
super::CodeSelectionError(ref e) => write!(f, "{}", e),
|
||||
super::CodeProjectionError(ref e) => write!(f, "{}", e),
|
||||
super::CodeAmbiguity => write!(f, "Ambiguity")
|
||||
}
|
||||
}
|
||||
@ -431,3 +432,4 @@ impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> {
|
||||
ty::type_err_to_str(tcx, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ pub enum vtable_origin<'tcx> {
|
||||
|
||||
// For every explicit cast into an object type, maps from the cast
|
||||
// expr to the associated trait ref.
|
||||
pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::PolyTraitRef<'tcx>>>>;
|
||||
pub type ObjectCastMap<'tcx> = RefCell<NodeMap<ty::PolyTraitRef<'tcx>>>;
|
||||
|
||||
/// A restriction that certain types must be the same size. The use of
|
||||
/// `transmute` gives rise to these restrictions. These generally
|
||||
@ -843,6 +843,7 @@ bitflags! {
|
||||
const HAS_RE_LATE_BOUND = 0b10000,
|
||||
const HAS_REGIONS = 0b100000,
|
||||
const HAS_TY_ERR = 0b1000000,
|
||||
const HAS_PROJECTION = 0b10000000,
|
||||
const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
|
||||
}
|
||||
}
|
||||
@ -989,6 +990,9 @@ pub fn type_has_ty_infer(ty: Ty) -> bool {
|
||||
pub fn type_needs_infer(ty: Ty) -> bool {
|
||||
ty.flags.intersects(HAS_TY_INFER | HAS_RE_INFER)
|
||||
}
|
||||
pub fn type_has_projection(ty: Ty) -> bool {
|
||||
ty.flags.intersects(HAS_PROJECTION)
|
||||
}
|
||||
|
||||
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
|
||||
ty.flags.intersects(HAS_RE_LATE_BOUND)
|
||||
@ -1354,7 +1358,9 @@ pub enum sty<'tcx> {
|
||||
|
||||
ty_tup(Vec<Ty<'tcx>>),
|
||||
|
||||
ty_projection(Box<TyProjection<'tcx>>),
|
||||
ty_param(ParamTy), // type parameter
|
||||
|
||||
ty_open(Ty<'tcx>), // A deref'ed fat pointer, i.e., a dynamically sized value
|
||||
// and its size. Only ever used in trans. It is not necessary
|
||||
// earlier since we don't need to distinguish a DST with its
|
||||
@ -1370,22 +1376,30 @@ pub enum sty<'tcx> {
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct TyTrait<'tcx> {
|
||||
// Principal trait reference.
|
||||
pub principal: PolyTraitRef<'tcx>,
|
||||
pub principal: ty::Binder<TraitRef<'tcx>>,
|
||||
pub bounds: ExistentialBounds
|
||||
}
|
||||
|
||||
impl<'tcx> TyTrait<'tcx> {
|
||||
pub fn principal_def_id(&self) -> ast::DefId {
|
||||
self.principal.0.def_id
|
||||
}
|
||||
|
||||
/// Object types don't have a self-type specified. Therefore, when
|
||||
/// we convert the principal trait-ref into a normal trait-ref,
|
||||
/// you must give *some* self-type. A common choice is `mk_err()`
|
||||
/// or some skolemized type.
|
||||
pub fn principal_trait_ref_with_self_ty(&self,
|
||||
tcx: &ctxt<'tcx>, self_ty: Ty<'tcx>)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
tcx: &ctxt<'tcx>,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
Rc::new(ty::Binder(ty::TraitRef {
|
||||
def_id: self.principal.def_id(),
|
||||
substs: tcx.mk_substs(self.principal.substs().with_self_ty(self_ty)),
|
||||
// otherwise the escaping regions would be captured by the binder
|
||||
assert!(!self_ty.has_escaping_regions());
|
||||
|
||||
ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: self.principal.0.def_id,
|
||||
substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -1411,7 +1425,7 @@ pub struct TraitRef<'tcx> {
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
}
|
||||
|
||||
pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
|
||||
pub type PolyTraitRef<'tcx> = Binder<Rc<TraitRef<'tcx>>>;
|
||||
|
||||
impl<'tcx> PolyTraitRef<'tcx> {
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
@ -1429,6 +1443,17 @@ impl<'tcx> PolyTraitRef<'tcx> {
|
||||
pub fn input_types(&self) -> &[Ty<'tcx>] {
|
||||
self.0.input_types()
|
||||
}
|
||||
|
||||
pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> {
|
||||
// Note that we preserve binding levels
|
||||
Binder(TraitPredicate { trait_ref: self.0.clone() })
|
||||
}
|
||||
|
||||
pub fn remove_rc(&self) -> ty::Binder<ty::TraitRef<'tcx>> {
|
||||
// Annoyingly, we can't easily put a `Rc` into a `sty` structure,
|
||||
// and hence we have to remove the rc to put this into a `TyTrait`.
|
||||
ty::Binder((*self.0).clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Binder is a binder for higher-ranked lifetimes. It is part of the
|
||||
@ -1501,7 +1526,8 @@ pub enum type_err<'tcx> {
|
||||
pub struct ParamBounds<'tcx> {
|
||||
pub region_bounds: Vec<ty::Region>,
|
||||
pub builtin_bounds: BuiltinBounds,
|
||||
pub trait_bounds: Vec<Rc<PolyTraitRef<'tcx>>>
|
||||
pub trait_bounds: Vec<PolyTraitRef<'tcx>>,
|
||||
pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
|
||||
}
|
||||
|
||||
/// Bounds suitable for an existentially quantified type parameter
|
||||
@ -1672,7 +1698,6 @@ pub struct TypeParameterDef<'tcx> {
|
||||
pub def_id: ast::DefId,
|
||||
pub space: subst::ParamSpace,
|
||||
pub index: u32,
|
||||
pub associated_with: Option<ast::DefId>,
|
||||
pub bounds: ParamBounds<'tcx>,
|
||||
pub default: Option<Ty<'tcx>>,
|
||||
}
|
||||
@ -1731,7 +1756,7 @@ pub enum Predicate<'tcx> {
|
||||
/// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
|
||||
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
||||
/// would be the parameters in the `TypeSpace`.
|
||||
Trait(Rc<PolyTraitRef<'tcx>>),
|
||||
Trait(PolyTraitPredicate<'tcx>),
|
||||
|
||||
/// where `T1 == T2`.
|
||||
Equate(PolyEquatePredicate<'tcx>),
|
||||
@ -1741,6 +1766,35 @@ pub enum Predicate<'tcx> {
|
||||
|
||||
/// where T : 'a
|
||||
TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
|
||||
|
||||
///
|
||||
Projection(PolyProjectionPredicate<'tcx>),
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct TraitPredicate<'tcx> {
|
||||
pub trait_ref: Rc<TraitRef<'tcx>>
|
||||
}
|
||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> TraitPredicate<'tcx> {
|
||||
pub fn def_id(&self) -> ast::DefId {
|
||||
self.trait_ref.def_id
|
||||
}
|
||||
|
||||
pub fn input_types(&self) -> &[Ty<'tcx>] {
|
||||
self.trait_ref.substs.types.as_slice()
|
||||
}
|
||||
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.trait_ref.self_ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
pub fn def_id(&self) -> ast::DefId {
|
||||
self.0.def_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
@ -1753,13 +1807,90 @@ pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
|
||||
pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>;
|
||||
pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>;
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||
///
|
||||
/// 1. `T : TraitRef<..., Item=Type>`
|
||||
/// 2. `<T as TraitRef<...>>::Item == Type` (NYI)
|
||||
///
|
||||
/// In particular, form #1 is "desugared" to the combination of a
|
||||
/// normal trait predicate (`T : TraitRef<...>`) and one of these
|
||||
/// predicates. Form #2 is a broader form in that it also permits
|
||||
/// equality between arbitrary types. Processing an instance of Form
|
||||
/// #2 eventually yields one of these `ProjectionPredicate`
|
||||
/// instances to normalize the LHS.
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct ProjectionPredicate<'tcx> {
|
||||
pub projection_ty: ProjectionTy<'tcx>,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct ProjectionTy<'tcx> {
|
||||
pub trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
pub item_name: ast::Name,
|
||||
}
|
||||
|
||||
// Annoying: a version of `ProjectionTy` that avoids the `Rc`, because
|
||||
// it is difficult to place an `Rc` in the `sty` struct. Eventually
|
||||
// these two types ought to be unified.
|
||||
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
|
||||
pub struct TyProjection<'tcx> {
|
||||
pub trait_ref: ty::TraitRef<'tcx>,
|
||||
pub item_name: ast::Name,
|
||||
}
|
||||
|
||||
pub trait ToPolyTraitRef<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToPolyTraitRef<'tcx> for Rc<TraitRef<'tcx>> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
|
||||
assert!(!self.has_escaping_regions());
|
||||
ty::Binder(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
|
||||
// We are just preserving the binder levels here
|
||||
ty::Binder(self.0.trait_ref.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> {
|
||||
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
|
||||
// Note: unlike with TraitRef::to_poly_trait_ref(),
|
||||
// self.0.trait_ref is permitted to have escaping regions.
|
||||
// This is because here `self` has a `Binder` and so does our
|
||||
// return value, so we are preserving the number of binding
|
||||
// levels.
|
||||
ty::Binder(self.0.projection_ty.trait_ref.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsPredicate<'tcx> {
|
||||
fn as_predicate(&self) -> Predicate<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> AsPredicate<'tcx> for Rc<PolyTraitRef<'tcx>> {
|
||||
impl<'tcx> AsPredicate<'tcx> for Rc<TraitRef<'tcx>> {
|
||||
fn as_predicate(&self) -> Predicate<'tcx> {
|
||||
Predicate::Trait(self.clone())
|
||||
// we're about to add a binder, so let's check that we don't
|
||||
// accidentally capture anything, or else that might be some
|
||||
// weird debruijn accounting.
|
||||
assert!(!self.has_escaping_regions());
|
||||
|
||||
ty::Predicate::Trait(ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: self.clone()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AsPredicate<'tcx> for PolyTraitRef<'tcx> {
|
||||
fn as_predicate(&self) -> Predicate<'tcx> {
|
||||
ty::Predicate::Trait(self.to_poly_trait_predicate())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1781,6 +1912,12 @@ impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
||||
fn as_predicate(&self) -> Predicate<'tcx> {
|
||||
Predicate::Projection(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Predicate<'tcx> {
|
||||
pub fn has_escaping_regions(&self) -> bool {
|
||||
match *self {
|
||||
@ -1788,14 +1925,16 @@ impl<'tcx> Predicate<'tcx> {
|
||||
Predicate::Equate(ref p) => p.has_escaping_regions(),
|
||||
Predicate::RegionOutlives(ref p) => p.has_escaping_regions(),
|
||||
Predicate::TypeOutlives(ref p) => p.has_escaping_regions(),
|
||||
Predicate::Projection(ref p) => p.has_escaping_regions(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_trait(&self) -> Option<Rc<PolyTraitRef<'tcx>>> {
|
||||
pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
|
||||
match *self {
|
||||
Predicate::Trait(ref t) => {
|
||||
Some(t.clone())
|
||||
Some(t.to_poly_trait_ref())
|
||||
}
|
||||
Predicate::Projection(..) |
|
||||
Predicate::Equate(..) |
|
||||
Predicate::RegionOutlives(..) |
|
||||
Predicate::TypeOutlives(..) => {
|
||||
@ -2032,7 +2171,12 @@ pub struct TraitDef<'tcx> {
|
||||
|
||||
/// The "supertrait" bounds.
|
||||
pub bounds: ParamBounds<'tcx>,
|
||||
|
||||
pub trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
|
||||
/// A list of the associated types defined in this trait. Useful
|
||||
/// for resolving `X::Foo` type markers.
|
||||
pub associated_type_names: Vec<ast::Name>,
|
||||
}
|
||||
|
||||
/// Records the substitutions used to translate the polytype for an
|
||||
@ -2330,9 +2474,14 @@ impl FlagComputation {
|
||||
self.add_substs(substs);
|
||||
}
|
||||
|
||||
&ty_projection(ref data) => {
|
||||
self.add_flags(HAS_PROJECTION);
|
||||
self.add_substs(&data.trait_ref.substs);
|
||||
}
|
||||
|
||||
&ty_trait(box TyTrait { ref principal, ref bounds }) => {
|
||||
let mut computation = FlagComputation::new();
|
||||
computation.add_substs(principal.substs());
|
||||
computation.add_substs(&principal.0.substs);
|
||||
self.add_bound_computation(&computation);
|
||||
|
||||
self.add_bounds(bounds);
|
||||
@ -2540,9 +2689,8 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>,
|
||||
principal: ty::PolyTraitRef<'tcx>,
|
||||
principal: ty::Binder<ty::TraitRef<'tcx>>,
|
||||
bounds: ExistentialBounds)
|
||||
-> Ty<'tcx> {
|
||||
// take a copy of substs so that we own the vectors inside
|
||||
@ -2553,6 +2701,15 @@ pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>,
|
||||
mk_t(cx, ty_trait(inner))
|
||||
}
|
||||
|
||||
pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx> {
|
||||
// take a copy of substs so that we own the vectors inside
|
||||
let inner = box TyProjection { trait_ref: trait_ref, item_name: item_name };
|
||||
mk_t(cx, ty_projection(inner))
|
||||
}
|
||||
|
||||
pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId,
|
||||
substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
|
||||
// take a copy of substs so that we own the vectors inside
|
||||
@ -2615,7 +2772,12 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) {
|
||||
maybe_walk_ty(tm.ty, f);
|
||||
}
|
||||
ty_trait(box TyTrait { ref principal, .. }) => {
|
||||
for subty in principal.substs().types.iter() {
|
||||
for subty in principal.0.substs.types.iter() {
|
||||
maybe_walk_ty(*subty, |x| f(x));
|
||||
}
|
||||
}
|
||||
ty_projection(box TyProjection { ref trait_ref, .. }) => {
|
||||
for subty in trait_ref.substs.types.iter() {
|
||||
maybe_walk_ty(*subty, |x| f(x));
|
||||
}
|
||||
}
|
||||
@ -2693,6 +2855,7 @@ impl<'tcx> ParamBounds<'tcx> {
|
||||
builtin_bounds: empty_builtin_bounds(),
|
||||
trait_bounds: Vec::new(),
|
||||
region_bounds: Vec::new(),
|
||||
projection_bounds: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3191,6 +3354,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
||||
apply_lang_items(cx, did, res)
|
||||
}
|
||||
|
||||
ty_projection(..) |
|
||||
ty_param(_) => {
|
||||
TC::All
|
||||
}
|
||||
@ -3372,6 +3536,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
|
||||
ty_infer(_) |
|
||||
ty_err |
|
||||
ty_param(_) |
|
||||
ty_projection(_) |
|
||||
ty_vec(_, None) => {
|
||||
false
|
||||
}
|
||||
@ -4448,7 +4613,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
|
||||
ty_bare_fn(None, _) => "fn pointer".to_string(),
|
||||
ty_closure(_) => "fn".to_string(),
|
||||
ty_trait(ref inner) => {
|
||||
format!("trait {}", item_path_str(cx, inner.principal.def_id()))
|
||||
format!("trait {}", item_path_str(cx, inner.principal_def_id()))
|
||||
}
|
||||
ty_struct(id, _) => {
|
||||
format!("struct {}", item_path_str(cx, id))
|
||||
@ -4460,6 +4625,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
|
||||
ty_infer(FloatVar(_)) => "floating-point variable".to_string(),
|
||||
ty_infer(FreshTy(_)) => "skolemized type".to_string(),
|
||||
ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(),
|
||||
ty_projection(_) => "associated type".to_string(),
|
||||
ty_param(ref p) => {
|
||||
if p.space == subst::SelfSpace {
|
||||
"Self".to_string()
|
||||
@ -4871,7 +5037,7 @@ pub fn try_add_builtin_trait(
|
||||
pub fn ty_to_def_id(ty: Ty) -> Option<ast::DefId> {
|
||||
match ty.sty {
|
||||
ty_trait(ref tt) =>
|
||||
Some(tt.principal.def_id()),
|
||||
Some(tt.principal_def_id()),
|
||||
ty_struct(id, _) |
|
||||
ty_enum(id, _) |
|
||||
ty_unboxed_closure(id, _, _) =>
|
||||
@ -5128,7 +5294,12 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
|
||||
}
|
||||
|
||||
/// Given a reference to a trait, returns the "superbounds" declared
|
||||
/// on the trait, with appropriate substitutions applied.
|
||||
/// on the trait, with appropriate substitutions applied. Basically,
|
||||
/// this applies a filter to the where clauses on the trait, returning
|
||||
/// those that have the form:
|
||||
///
|
||||
/// Self : SuperTrait<...>
|
||||
/// Self : 'region
|
||||
pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
trait_ref: &PolyTraitRef<'tcx>)
|
||||
-> Vec<ty::Predicate<'tcx>>
|
||||
@ -5205,13 +5376,7 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
let trait_bounds: Vec<_> =
|
||||
trait_def.bounds.trait_bounds
|
||||
.iter()
|
||||
.map(|bound_trait_ref| {
|
||||
let substs = tcx.mk_substs(bound_trait_ref.substs().subst(tcx, trait_ref.substs()));
|
||||
ty::Binder(
|
||||
ty::TraitRef::new(bound_trait_ref.def_id(),
|
||||
substs))
|
||||
})
|
||||
.map(|bound_trait_ref| Rc::new(bound_trait_ref))
|
||||
.map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs())))
|
||||
.collect();
|
||||
|
||||
debug!("bounds_for_trait_ref: trait_bounds={}",
|
||||
@ -5228,6 +5393,11 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
|
||||
trait_bounds: trait_bounds,
|
||||
region_bounds: region_bounds,
|
||||
builtin_bounds: builtin_bounds,
|
||||
|
||||
// FIXME(#19451) -- if a trait has a bound like `trait Foo :
|
||||
// Bar<T=X>`, we should probably be returning that, but this
|
||||
// code here will just ignore it.
|
||||
projection_bounds: Vec::new(),
|
||||
};
|
||||
|
||||
predicates(tcx, trait_ref.self_ty(), &bounds)
|
||||
@ -5242,7 +5412,7 @@ pub fn predicates<'tcx>(
|
||||
let mut vec = Vec::new();
|
||||
|
||||
for builtin_bound in bounds.builtin_bounds.iter() {
|
||||
match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
|
||||
match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
|
||||
Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); }
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
@ -5259,6 +5429,10 @@ pub fn predicates<'tcx>(
|
||||
vec.push(bound_trait_ref.as_predicate());
|
||||
}
|
||||
|
||||
for projection in bounds.projection_bounds.iter() {
|
||||
vec.push(projection.as_predicate());
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
@ -5594,10 +5768,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
|
||||
// relation on the supertraits from each bounded trait's constraint
|
||||
// list.
|
||||
pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
|
||||
bounds: &[Rc<PolyTraitRef<'tcx>>],
|
||||
bounds: &[PolyTraitRef<'tcx>],
|
||||
mut f: F)
|
||||
-> bool where
|
||||
F: FnMut(Rc<PolyTraitRef<'tcx>>) -> bool,
|
||||
F: FnMut(PolyTraitRef<'tcx>) -> bool,
|
||||
{
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
if !f(bound_trait_ref) {
|
||||
@ -5607,10 +5781,11 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
||||
opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures
|
||||
others: BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
pub fn object_region_bounds<'tcx>(
|
||||
tcx: &ctxt<'tcx>,
|
||||
opt_principal: Option<&Binder<TraitRef<'tcx>>>, // None for closures
|
||||
others: BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
@ -5618,14 +5793,17 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
||||
let open_ty = ty::mk_infer(tcx, FreshTy(0));
|
||||
|
||||
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
||||
let substs = principal.substs().with_self_ty(open_ty);
|
||||
vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), tcx.mk_substs(substs)))))
|
||||
// Note that we preserve the overall binding levels here.
|
||||
assert!(!open_ty.has_escaping_regions());
|
||||
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
|
||||
vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))))
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: opt_trait_ref,
|
||||
projection_bounds: Vec::new(), // not relevant to computing region bounds
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
|
||||
@ -5656,6 +5834,7 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
||||
traits::elaborate_predicates(tcx, predicates)
|
||||
.filter_map(|predicate| {
|
||||
match predicate {
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
@ -6007,12 +6186,12 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
|
||||
|
||||
return false;
|
||||
}
|
||||
ty_trait(box TyTrait { ref principal, bounds }) => {
|
||||
ty_trait(ref data) => {
|
||||
byte!(17);
|
||||
did(state, principal.def_id());
|
||||
hash!(bounds);
|
||||
did(state, data.principal_def_id());
|
||||
hash!(data.bounds);
|
||||
|
||||
let principal = anonymize_late_bound_regions(tcx, principal);
|
||||
let principal = anonymize_late_bound_regions(tcx, &data.principal);
|
||||
for subty in principal.substs.types.iter() {
|
||||
helper(tcx, *subty, svh, state);
|
||||
}
|
||||
@ -6040,6 +6219,11 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
|
||||
did(state, d);
|
||||
region(state, *r);
|
||||
}
|
||||
ty_projection(ref data) => {
|
||||
byte!(25);
|
||||
did(state, data.trait_ref.def_id);
|
||||
hash!(token::get_name(data.item_name));
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
@ -6156,7 +6340,10 @@ pub fn construct_parameter_environment<'tcx>(
|
||||
|
||||
for predicate in bounds.predicates.iter() {
|
||||
match *predicate {
|
||||
Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => {
|
||||
Predicate::Projection(..) |
|
||||
Predicate::Trait(..) |
|
||||
Predicate::Equate(..) |
|
||||
Predicate::TypeOutlives(..) => {
|
||||
// No region bounds here
|
||||
}
|
||||
Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
|
||||
@ -6283,7 +6470,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
accumulator.push(*region)
|
||||
}
|
||||
ty_trait(ref t) => {
|
||||
accumulator.push_all(t.principal.substs().regions().as_slice());
|
||||
accumulator.push_all(t.principal.0.substs.regions().as_slice());
|
||||
}
|
||||
ty_enum(_, substs) |
|
||||
ty_struct(_, substs) => {
|
||||
@ -6310,6 +6497,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
ty_ptr(_) |
|
||||
ty_bare_fn(..) |
|
||||
ty_tup(_) |
|
||||
ty_projection(_) |
|
||||
ty_param(_) |
|
||||
ty_infer(_) |
|
||||
ty_open(_) |
|
||||
@ -6400,6 +6588,15 @@ pub fn count_late_bound_regions<'tcx, T>(
|
||||
skol_map.len()
|
||||
}
|
||||
|
||||
pub fn binds_late_bound_regions<'tcx, T>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
value: &Binder<T>)
|
||||
-> bool
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx>
|
||||
{
|
||||
count_late_bound_regions(tcx, value) > 0
|
||||
}
|
||||
|
||||
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
|
||||
/// method lookup and a few other places where precise region relationships are not required.
|
||||
pub fn erase_late_bound_regions<'tcx, T>(
|
||||
@ -6540,9 +6737,10 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
Predicate::Trait(ref a) => a.repr(tcx),
|
||||
Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)),
|
||||
Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)),
|
||||
Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)),
|
||||
Predicate::Equate(ref pair) => pair.repr(tcx),
|
||||
Predicate::RegionOutlives(ref pair) => pair.repr(tcx),
|
||||
Predicate::TypeOutlives(ref pair) => pair.repr(tcx),
|
||||
Predicate::Projection(ref pair) => pair.repr(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6638,6 +6836,11 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO -- all of these types basically walk various structures to
|
||||
// test whether types/regions are reachable with various
|
||||
// properties. It should be possible to express them in terms of one
|
||||
// common "walker" trait or something.
|
||||
|
||||
pub trait RegionEscape {
|
||||
fn has_escaping_regions(&self) -> bool {
|
||||
self.has_regions_escaping_depth(0)
|
||||
@ -6677,8 +6880,193 @@ impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
|
||||
self.trait_ref.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
|
||||
self.projection_ty.has_regions_escaping_depth(depth) ||
|
||||
self.ty.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
|
||||
self.trait_ref.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("ProjectionPredicate({}, {})",
|
||||
self.projection_ty.repr(tcx),
|
||||
self.ty.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::TyProjection<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("TyProjection({}, {})",
|
||||
self.trait_ref.repr(tcx),
|
||||
self.item_name.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasProjectionTypes {
|
||||
fn has_projection_types(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for Ty<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
ty::type_has_projection(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::TraitRef<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.substs.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for subst::Substs<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.types.iter().any(|t| t.has_projection_types())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T> HasProjectionTypes for Option<T>
|
||||
where T : HasProjectionTypes
|
||||
{
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.iter().any(|t| t.has_projection_types())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T> HasProjectionTypes for Rc<T>
|
||||
where T : HasProjectionTypes
|
||||
{
|
||||
fn has_projection_types(&self) -> bool {
|
||||
(**self).has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T> HasProjectionTypes for Box<T>
|
||||
where T : HasProjectionTypes
|
||||
{
|
||||
fn has_projection_types(&self) -> bool {
|
||||
(**self).has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> HasProjectionTypes for ty::Binder<T>
|
||||
where T : HasProjectionTypes
|
||||
{
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.0.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::FnOutput<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
match *self {
|
||||
ty::FnConverging(t) => t.has_projection_types(),
|
||||
ty::FnDiverging => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::FnSig<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.inputs.iter().any(|t| t.has_projection_types()) ||
|
||||
self.output.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasProjectionTypes for ty::BareFnTy<'tcx> {
|
||||
fn has_projection_types(&self) -> bool {
|
||||
self.sig.has_projection_types()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReferencesError {
|
||||
fn references_error(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T:ReferencesError> ReferencesError for ty::Binder<T> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.0.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:ReferencesError> ReferencesError for Rc<T> {
|
||||
fn references_error(&self) -> bool {
|
||||
(&*self).references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::TraitPredicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.trait_ref.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::ProjectionPredicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.projection_ty.trait_ref.references_error() || self.ty.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::TraitRef<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
self.input_types().iter().any(|t| t.references_error())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::Ty<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
ty::type_is_error(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::Predicate<'tcx> {
|
||||
fn references_error(&self) -> bool {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref data) => data.references_error(),
|
||||
ty::Predicate::Equate(ref data) => data.references_error(),
|
||||
ty::Predicate::RegionOutlives(ref data) => data.references_error(),
|
||||
ty::Predicate::TypeOutlives(ref data) => data.references_error(),
|
||||
ty::Predicate::Projection(ref data) => data.references_error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A,B> ReferencesError for ty::OutlivesPredicate<A,B>
|
||||
where A : ReferencesError, B : ReferencesError
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
self.0.references_error() || self.1.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ReferencesError for ty::EquatePredicate<'tcx>
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
self.0.references_error() || self.1.references_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReferencesError for ty::Region
|
||||
{
|
||||
fn references_error(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -170,6 +170,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
|
||||
let content: T = (**self).fold_with(folder);
|
||||
box content
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
|
||||
self.iter().map(|t| t.fold_with(folder)).collect()
|
||||
@ -354,6 +361,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParamBounds<'tcx> {
|
||||
region_bounds: self.region_bounds.fold_with(folder),
|
||||
builtin_bounds: self.builtin_bounds.fold_with(folder),
|
||||
trait_bounds: self.trait_bounds.fold_with(folder),
|
||||
projection_bounds: self.projection_bounds.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -365,7 +373,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
|
||||
def_id: self.def_id,
|
||||
space: self.space,
|
||||
index: self.index,
|
||||
associated_with: self.associated_with,
|
||||
bounds: self.bounds.fold_with(folder),
|
||||
default: self.default.fold_with(folder),
|
||||
}
|
||||
@ -405,6 +412,35 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
||||
ty::Predicate::RegionOutlives(binder.fold_with(folder)),
|
||||
ty::Predicate::TypeOutlives(ref binder) =>
|
||||
ty::Predicate::TypeOutlives(binder.fold_with(folder)),
|
||||
ty::Predicate::Projection(ref binder) =>
|
||||
ty::Predicate::Projection(binder.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: self.projection_ty.fold_with(folder),
|
||||
ty: self.ty.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
|
||||
ty::ProjectionTy {
|
||||
trait_ref: self.trait_ref.fold_with(folder),
|
||||
item_name: self.item_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::TyProjection<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TyProjection<'tcx> {
|
||||
ty::TyProjection {
|
||||
trait_ref: self.trait_ref.fold_with(folder),
|
||||
item_name: self.item_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -495,6 +531,14 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
|
||||
ty::TraitPredicate {
|
||||
trait_ref: self.trait_ref.fold_with(folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
|
||||
where T : TypeFoldable<'tcx>,
|
||||
U : TypeFoldable<'tcx>,
|
||||
@ -544,7 +588,7 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn))
|
||||
}
|
||||
ty::ty_closure(ref f) => {
|
||||
ty::ty_closure(box f.fold_with(this))
|
||||
ty::ty_closure(f.fold_with(this))
|
||||
}
|
||||
ty::ty_rptr(r, ref tm) => {
|
||||
let r = r.fold_with(this);
|
||||
@ -559,6 +603,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
let s = substs.fold_with(this);
|
||||
ty::ty_unboxed_closure(did, this.tcx().mk_region(r), this.tcx().mk_substs(s))
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
ty::ty_projection(data.fold_with(this))
|
||||
}
|
||||
ty::ty_bool | ty::ty_char | ty::ty_str |
|
||||
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
|
||||
ty::ty_err | ty::ty_infer(_) |
|
||||
|
@ -448,6 +448,12 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
|
||||
bound_sep,
|
||||
bound_str)
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
format!("<{} as {}>::{}",
|
||||
data.trait_ref.self_ty().user_string(cx),
|
||||
data.trait_ref.user_string(cx),
|
||||
data.item_name.user_string(cx))
|
||||
}
|
||||
ty_str => "str".to_string(),
|
||||
ty_unboxed_closure(ref did, _, substs) => {
|
||||
let unboxed_closures = cx.unboxed_closures.borrow();
|
||||
@ -1408,17 +1414,55 @@ impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("TraitPredicate({})",
|
||||
self.trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("{} : {}",
|
||||
self.trait_ref.self_ty().user_string(tcx),
|
||||
self.trait_ref.user_string(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("{} == {}",
|
||||
self.projection_ty.user_string(tcx),
|
||||
self.ty.user_string(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("<{} as {}>::{}",
|
||||
self.trait_ref.self_ty().repr(tcx),
|
||||
self.trait_ref.repr(tcx),
|
||||
self.item_name.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("<{} as {}>::{}",
|
||||
self.trait_ref.self_ty().user_string(tcx),
|
||||
self.trait_ref.user_string(tcx),
|
||||
self.item_name.user_string(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
format!("{} : {}",
|
||||
trait_ref.self_ty().user_string(tcx),
|
||||
trait_ref.user_string(tcx))
|
||||
}
|
||||
ty::Predicate::Trait(ref data) => data.user_string(tcx),
|
||||
ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx),
|
||||
ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx),
|
||||
ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx),
|
||||
ty::Predicate::Projection(ref predicate) => predicate.user_string(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +281,8 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId)
|
||||
|
||||
pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
|
||||
let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);
|
||||
|
||||
let (inputs, output, abi, env) = match fn_ty.sty {
|
||||
ty::ty_bare_fn(_, ref f) => {
|
||||
(f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None)
|
||||
@ -1453,7 +1455,8 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
|
||||
let uses_outptr = match output_type {
|
||||
ty::FnConverging(output_type) => {
|
||||
let substd_output_type = output_type.subst(ccx.tcx(), param_substs);
|
||||
let substd_output_type =
|
||||
monomorphize::apply_param_substs(ccx.tcx(), param_substs, &output_type);
|
||||
type_of::return_uses_outptr(ccx, substd_output_type)
|
||||
}
|
||||
ty::FnDiverging => false
|
||||
@ -1512,7 +1515,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
|
||||
if let ty::FnConverging(output_type) = output {
|
||||
// This shouldn't need to recompute the return type,
|
||||
// as new_fn_ctxt did it already.
|
||||
let substd_output_type = output_type.subst(fcx.ccx.tcx(), fcx.param_substs);
|
||||
let substd_output_type = fcx.monomorphize(&output_type);
|
||||
if !return_type_is_void(fcx.ccx, substd_output_type) {
|
||||
// If the function returns nil/bot, there is no real return
|
||||
// value, so do not set `llretslotptr`.
|
||||
@ -1732,7 +1735,7 @@ pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
|
||||
|
||||
// This shouldn't need to recompute the return type,
|
||||
// as new_fn_ctxt did it already.
|
||||
let substd_retty = retty.subst(fcx.ccx.tcx(), fcx.param_substs);
|
||||
let substd_retty = fcx.monomorphize(&retty);
|
||||
build_return_block(fcx, ret_cx, substd_retty);
|
||||
|
||||
debuginfo::clear_source_location(fcx);
|
||||
@ -2074,7 +2077,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
|
||||
param_substs: &Substs<'tcx>,
|
||||
llfndecl: ValueRef) {
|
||||
let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
|
||||
let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs);
|
||||
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
|
||||
|
||||
let result_ty = match ctor_ty.sty {
|
||||
ty::ty_bare_fn(_, ref bft) => bft.sig.0.output,
|
||||
@ -2764,6 +2767,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
||||
}
|
||||
|
||||
let item = ccx.tcx().map.get(id);
|
||||
debug!("get_item_val: id={} item={}", id, item);
|
||||
let val = match item {
|
||||
ast_map::NodeItem(i) => {
|
||||
let ty = ty::node_id_to_type(ccx.tcx(), i.id);
|
||||
|
@ -516,6 +516,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
|
||||
// Type scheme of the function item (may have type params)
|
||||
let fn_type_scheme = ty::lookup_item_type(tcx, def_id);
|
||||
let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty);
|
||||
|
||||
// Find the actual function pointer.
|
||||
let mut val = {
|
||||
@ -524,7 +525,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
get_item_val(ccx, def_id.node)
|
||||
} else {
|
||||
// External reference.
|
||||
trans_external_path(ccx, def_id, fn_type_scheme.ty)
|
||||
trans_external_path(ccx, def_id, fn_type)
|
||||
}
|
||||
};
|
||||
|
||||
@ -551,7 +552,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
// This can occur on either a crate-local or crate-external
|
||||
// reference. It also occurs when testing libcore and in some
|
||||
// other weird situations. Annoying.
|
||||
let llty = type_of::type_of_fn_from_ty(ccx, fn_type_scheme.ty);
|
||||
let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
|
||||
let llptrty = llty.ptr_to();
|
||||
if val_ty(val) != llptrty {
|
||||
debug!("trans_fn_ref_with_vtables(): casting pointer!");
|
||||
|
@ -24,20 +24,20 @@ use middle::infer;
|
||||
use middle::lang_items::LangItem;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{mod, Subst, Substs};
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::cleanup;
|
||||
use trans::datum;
|
||||
use trans::debuginfo;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use util::ppaux::Repr;
|
||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
|
||||
@ -45,7 +45,6 @@ use arena::TypedArena;
|
||||
use libc::{c_uint, c_char};
|
||||
use std::c_str::ToCStr;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::vec::Vec;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::ast;
|
||||
@ -137,7 +136,7 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<
|
||||
|
||||
ty::ty_enum(did, substs) =>
|
||||
ty::enum_variants(tcx, did).iter().any(|v|
|
||||
v.args.iter().any(|aty| {
|
||||
v.args.iter().any(|&aty| {
|
||||
let t = aty.subst(tcx, substs);
|
||||
type_needs_unwind_cleanup_(tcx, t, tycache)
|
||||
})
|
||||
@ -465,6 +464,14 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn monomorphize<T>(&self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
monomorphize::apply_param_substs(self.ccx.tcx(),
|
||||
self.param_substs,
|
||||
value)
|
||||
}
|
||||
}
|
||||
|
||||
// Basic block context. We create a block context for each basic block
|
||||
@ -557,6 +564,14 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
|
||||
pub fn to_str(&self) -> String {
|
||||
format!("[block {:p}]", self)
|
||||
}
|
||||
|
||||
pub fn monomorphize<T>(&self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
monomorphize::apply_param_substs(self.tcx(),
|
||||
self.fcx.param_substs,
|
||||
value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
|
||||
@ -859,7 +874,7 @@ pub fn is_null(val: ValueRef) -> bool {
|
||||
}
|
||||
|
||||
pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
t.subst(bcx.tcx(), bcx.fcx.param_substs)
|
||||
bcx.fcx.monomorphize(&t)
|
||||
}
|
||||
|
||||
pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> {
|
||||
@ -881,7 +896,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) ->
|
||||
/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
|
||||
pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
span: Span,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> traits::Vtable<'tcx, ()>
|
||||
{
|
||||
let tcx = ccx.tcx();
|
||||
@ -911,7 +926,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.clone());
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(selection)) => selection,
|
||||
Ok(None) => {
|
||||
@ -991,7 +1006,8 @@ pub enum ExprOrMethodCall {
|
||||
|
||||
pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
node: ExprOrMethodCall)
|
||||
-> subst::Substs<'tcx> {
|
||||
-> subst::Substs<'tcx>
|
||||
{
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
let substs = match node {
|
||||
@ -1012,7 +1028,7 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
|
||||
let substs = substs.erase_regions();
|
||||
substs.subst(tcx, bcx.fcx.param_substs)
|
||||
bcx.monomorphize(&substs)
|
||||
}
|
||||
|
||||
pub fn langcall(bcx: Block,
|
||||
|
@ -100,7 +100,7 @@ pub struct LocalCrateContext<'tcx> {
|
||||
monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>,
|
||||
monomorphizing: RefCell<DefIdMap<uint>>,
|
||||
/// Cache generated vtables
|
||||
vtables: RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>), ValueRef>>,
|
||||
vtables: RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>), ValueRef>>,
|
||||
/// Cache of constant strings,
|
||||
const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>,
|
||||
|
||||
@ -151,7 +151,7 @@ pub struct LocalCrateContext<'tcx> {
|
||||
/// contexts around the same size.
|
||||
n_llvm_insns: Cell<uint>,
|
||||
|
||||
trait_cache: RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>,
|
||||
trait_cache: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
|
||||
traits::Vtable<'tcx, ()>>>,
|
||||
}
|
||||
|
||||
@ -607,7 +607,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
&self.local.monomorphizing
|
||||
}
|
||||
|
||||
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>),
|
||||
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>),
|
||||
ValueRef>> {
|
||||
&self.local.vtables
|
||||
}
|
||||
@ -705,7 +705,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1);
|
||||
}
|
||||
|
||||
pub fn trait_cache(&self) -> &RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>,
|
||||
pub fn trait_cache(&self) -> &RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
|
||||
traits::Vtable<'tcx, ()>>> {
|
||||
&self.local.trait_cache
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ use middle::subst::{mod, Subst, Substs};
|
||||
use trans::{mod, adt, machine, type_of};
|
||||
use trans::common::*;
|
||||
use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::pat_util;
|
||||
@ -426,8 +427,8 @@ impl<'tcx> TypeMap<'tcx> {
|
||||
|
||||
from_def_id_and_substs(self,
|
||||
cx,
|
||||
trait_data.principal.def_id(),
|
||||
trait_data.principal.substs(),
|
||||
trait_data.principal_def_id(),
|
||||
&trait_data.principal.0.substs,
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
@ -1438,7 +1439,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
|
||||
|
||||
let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
|
||||
let return_type = return_type.subst(cx.tcx(), param_substs);
|
||||
let return_type = monomorphize::apply_param_substs(cx.tcx(),
|
||||
param_substs,
|
||||
&return_type);
|
||||
signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP));
|
||||
}
|
||||
}
|
||||
@ -1447,7 +1450,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
for arg in fn_decl.inputs.iter() {
|
||||
assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
|
||||
let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id);
|
||||
let arg_type = arg_type.subst(cx.tcx(), param_substs);
|
||||
let arg_type = monomorphize::apply_param_substs(cx.tcx(),
|
||||
param_substs,
|
||||
&arg_type);
|
||||
signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP));
|
||||
}
|
||||
|
||||
@ -1459,8 +1464,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
param_substs: &Substs<'tcx>,
|
||||
file_metadata: DIFile,
|
||||
name_to_append_suffix_to: &mut String)
|
||||
-> DIArray {
|
||||
-> DIArray
|
||||
{
|
||||
let self_type = param_substs.self_ty();
|
||||
let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type);
|
||||
|
||||
// Only true for static default methods:
|
||||
let has_self_type = self_type.is_some();
|
||||
@ -2878,7 +2885,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
// But it does not describe the trait's methods.
|
||||
|
||||
let def_id = match trait_type.sty {
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id(),
|
||||
ty::ty_trait(ref data) => data.principal_def_id(),
|
||||
_ => {
|
||||
let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type);
|
||||
cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
|
||||
@ -3811,8 +3818,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
output.push(']');
|
||||
},
|
||||
ty::ty_trait(ref trait_data) => {
|
||||
push_item_name(cx, trait_data.principal.def_id(), false, output);
|
||||
push_type_params(cx, trait_data.principal.substs(), output);
|
||||
push_item_name(cx, trait_data.principal_def_id(), false, output);
|
||||
push_type_params(cx, &trait_data.principal.0.substs, output);
|
||||
},
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
if unsafety == ast::Unsafety::Unsafe {
|
||||
@ -3920,9 +3927,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
ty::ty_unboxed_closure(..) => {
|
||||
output.push_str("closure");
|
||||
}
|
||||
ty::ty_err |
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_open(_) |
|
||||
ty::ty_projection(..) |
|
||||
ty::ty_param(_) => {
|
||||
cx.sess().bug(format!("debuginfo: Trying to create type name for \
|
||||
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]);
|
||||
|
@ -39,7 +39,7 @@ use back::abi;
|
||||
use llvm::{mod, ValueRef};
|
||||
use middle::def;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{mod, Subst, Substs};
|
||||
use middle::subst::{mod, Substs};
|
||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
@ -319,11 +319,13 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
bcx.ty_to_string(unadjusted_ty))[])
|
||||
},
|
||||
&ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
|
||||
let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions();
|
||||
// Note that we preserve binding levels here:
|
||||
let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
|
||||
let substs = tcx.tcx().mk_substs(substs);
|
||||
let trait_ref =
|
||||
Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(),
|
||||
substs: bcx.tcx().mk_substs(substs) }));
|
||||
let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs);
|
||||
ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
|
||||
substs: substs }));
|
||||
let trait_ref = bcx.monomorphize(&trait_ref);
|
||||
let box_ty = mk_ty(unadjusted_ty);
|
||||
PointerCast(bcx,
|
||||
meth::get_vtable(bcx, box_ty, trait_ref),
|
||||
@ -1204,7 +1206,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
.get(&expr.id)
|
||||
.map(|t| (*t).clone())
|
||||
.unwrap();
|
||||
let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs);
|
||||
let trait_ref = bcx.monomorphize(&trait_ref);
|
||||
let datum = unpack_datum!(bcx, trans(bcx, &**val));
|
||||
meth::trans_trait_cast(bcx, datum, expr.id,
|
||||
trait_ref, dest)
|
||||
|
@ -19,11 +19,12 @@ use trans::build::*;
|
||||
use trans::cabi;
|
||||
use trans::common::*;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of::*;
|
||||
use trans::type_of;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{Substs};
|
||||
use std::cmp;
|
||||
use libc::c_uint;
|
||||
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
|
||||
@ -525,7 +526,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let _icx = push_ctxt("foreign::build_foreign_fn");
|
||||
|
||||
let fnty = ty::node_id_to_type(ccx.tcx(), id);
|
||||
let mty = fnty.subst(ccx.tcx(), param_substs);
|
||||
let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
|
||||
let tys = foreign_types_for_fn_ty(ccx, mty);
|
||||
|
||||
unsafe { // unsafe because we call LLVM operations
|
||||
@ -543,10 +544,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
attrs: &[ast::Attribute],
|
||||
id: ast::NodeId,
|
||||
hash: Option<&str>)
|
||||
-> ValueRef {
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
|
||||
let tcx = ccx.tcx();
|
||||
let t = ty::node_id_to_type(tcx, id).subst(ccx.tcx(), param_substs);
|
||||
let t = ty::node_id_to_type(tcx, id);
|
||||
let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
|
||||
|
||||
let ps = ccx.tcx().map.with_path(id, |path| {
|
||||
let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
|
||||
|
@ -13,7 +13,7 @@ use back::abi;
|
||||
use llvm;
|
||||
use llvm::ValueRef;
|
||||
use metadata::csearch;
|
||||
use middle::subst::{Subst,Substs};
|
||||
use middle::subst::{Substs};
|
||||
use middle::subst::VecPerParamSpace;
|
||||
use middle::subst;
|
||||
use middle::traits;
|
||||
@ -132,8 +132,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
ref trait_ref,
|
||||
method_num
|
||||
}) => {
|
||||
let trait_ref =
|
||||
Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs)));
|
||||
let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
|
||||
let span = bcx.tcx().map.span(method_call.expr_id);
|
||||
debug!("method_call={} trait_ref={}",
|
||||
method_call,
|
||||
@ -142,8 +141,11 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
span,
|
||||
trait_ref.clone());
|
||||
debug!("origin = {}", origin.repr(bcx.tcx()));
|
||||
trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(),
|
||||
method_num, origin)
|
||||
trans_monomorphized_callee(bcx,
|
||||
method_call,
|
||||
trait_ref.def_id(),
|
||||
method_num,
|
||||
origin)
|
||||
}
|
||||
|
||||
ty::MethodTraitObject(ref mt) => {
|
||||
@ -238,9 +240,10 @@ pub fn trans_static_method_callee(bcx: Block,
|
||||
rcvr_self,
|
||||
rcvr_assoc,
|
||||
Vec::new()));
|
||||
let trait_substs = bcx.tcx().mk_substs(trait_substs);
|
||||
debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id,
|
||||
substs: bcx.tcx().mk_substs(trait_substs) }));
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
|
||||
substs: trait_substs }));
|
||||
let vtbl = fulfill_obligation(bcx.ccx(),
|
||||
DUMMY_SP,
|
||||
trait_ref);
|
||||
@ -515,7 +518,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
/// This will hopefully change now that DST is underway.
|
||||
pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
box_ty: Ty<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
debug!("get_vtable(box_ty={}, trait_ref={})",
|
||||
@ -671,7 +674,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
datum: Datum<'tcx, Expr>,
|
||||
id: ast::NodeId,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
dest: expr::Dest)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let mut bcx = bcx;
|
||||
|
@ -12,15 +12,18 @@ use back::link::exported_name;
|
||||
use session;
|
||||
use llvm::ValueRef;
|
||||
use llvm;
|
||||
use middle::infer;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty_fold::{mod, TypeFolder, TypeFoldable};
|
||||
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
|
||||
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
|
||||
use trans::base::{trans_fn, decl_internal_rust_fn};
|
||||
use trans::base;
|
||||
use trans::common::*;
|
||||
use trans::foreign;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::abi;
|
||||
@ -29,6 +32,7 @@ use syntax::ast_map;
|
||||
use syntax::ast_util::{local_def, PostExpansionMethod};
|
||||
use syntax::attr;
|
||||
use std::hash::{sip, Hash};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_id: ast::DefId,
|
||||
@ -92,7 +96,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
|
||||
|
||||
let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts);
|
||||
debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
|
||||
|
||||
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
|
||||
debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));
|
||||
|
||||
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
|
||||
|
||||
@ -282,3 +291,84 @@ pub struct MonoId<'tcx> {
|
||||
pub def: ast::DefId,
|
||||
pub params: subst::VecPerParamSpace<Ty<'tcx>>
|
||||
}
|
||||
|
||||
/// Monomorphizes a type from the AST by first applying the in-scope
|
||||
/// substitutions and then normalizing any associated types.
|
||||
pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
|
||||
param_substs: &Substs<'tcx>,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
assert!(param_substs.regions.is_erased());
|
||||
|
||||
let substituted = value.subst(tcx, param_substs);
|
||||
normalize_associated_type(tcx, &substituted)
|
||||
}
|
||||
|
||||
/// Removes associated types, if any. Since this during
|
||||
/// monomorphization, we know that only concrete types are involved,
|
||||
/// and hence we can be sure that all associated types will be
|
||||
/// completely normalized away.
|
||||
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
debug!("normalize_associated_type(t={})", t.repr(tcx));
|
||||
|
||||
if !t.has_projection_types() {
|
||||
return t.clone();
|
||||
}
|
||||
|
||||
// TODO cache
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let mut normalizer = AssociatedTypeNormalizer { selcx: &mut selcx };
|
||||
let result = t.fold_with(&mut normalizer);
|
||||
|
||||
debug!("normalize_associated_type: t={} result={}",
|
||||
t.repr(tcx),
|
||||
result.repr(tcx));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
selcx: &'a mut traits::SelectionContext<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.selcx.tcx() }
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) => {
|
||||
debug!("ty_projection({})", data.repr(self.tcx()));
|
||||
|
||||
let tcx = self.selcx.tcx();
|
||||
let substs = data.trait_ref.substs.clone().erase_regions();
|
||||
assert!(substs.types.iter().all(|&t| (!ty::type_has_params(t) &&
|
||||
!ty::type_has_self(t))));
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(data.trait_ref.def_id, substs));
|
||||
let projection_ty = ty::ProjectionTy { trait_ref: trait_ref.clone(),
|
||||
item_name: data.item_name };
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
projection_ty);
|
||||
match traits::project_type(self.selcx, &obligation) {
|
||||
Ok(ty) => ty,
|
||||
Err(errors) => {
|
||||
tcx.sess.bug(
|
||||
format!("Encountered error(s) `{}` selecting `{}` during trans",
|
||||
errors.repr(tcx),
|
||||
trait_ref.repr(tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
||||
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
|
||||
}
|
||||
|
||||
ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
|
||||
ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
|
||||
cx.sess().bug(format!("fictitious type {} in sizing_type_of()",
|
||||
ppaux::ty_to_string(cx.tcx(), t))[])
|
||||
}
|
||||
@ -414,6 +414,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
||||
},
|
||||
|
||||
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
|
||||
ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
|
||||
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
|
||||
ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
|
||||
};
|
||||
|
@ -51,7 +51,7 @@ use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGION
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::resolve_lifetime as rl;
|
||||
use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{VecPerParamSpace};
|
||||
use middle::ty::{mod, RegionEscape, Ty};
|
||||
use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope,
|
||||
@ -84,25 +84,45 @@ pub trait AstConv<'tcx> {
|
||||
/// What type should we use when a type is omitted?
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
|
||||
|
||||
/// Returns true if associated types from the given trait and type are
|
||||
/// allowed to be used here and false otherwise.
|
||||
fn associated_types_of_trait_are_valid(&self,
|
||||
ty: Ty<'tcx>,
|
||||
trait_id: ast::DefId)
|
||||
-> bool;
|
||||
/// Projecting an associated type from a (potentially)
|
||||
/// higher-ranked trait reference is more complicated, because of
|
||||
/// the possibility of late-bound regions appearing in the
|
||||
/// associated type binding. This is not legal in function
|
||||
/// signatures for that reason. In a function body, we can always
|
||||
/// handle it because we can use inference variables to remove the
|
||||
/// late-bound regions.
|
||||
fn projected_ty_from_poly_trait_ref(&self,
|
||||
span: Span,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) {
|
||||
self.tcx().sess.span_err(
|
||||
span,
|
||||
"cannot extract an associated type from a higher-ranked trait bound \
|
||||
in this context");
|
||||
self.tcx().types.err
|
||||
} else {
|
||||
// no late-bound regions, we can just ignore the binder
|
||||
self.projected_ty(span, poly_trait_ref.0.clone(), item_name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the concrete type bound to the given associated type (indicated
|
||||
/// by associated_type_id) in the current context. For example,
|
||||
/// in `trait Foo { type A; }` looking up `A` will give a type variable;
|
||||
/// in `impl Foo for ... { type A = int; ... }` looking up `A` will give `int`.
|
||||
fn associated_type_binding(&self,
|
||||
span: Span,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
// DefId for the declaration of the trait
|
||||
// in which the associated type is declared.
|
||||
trait_id: ast::DefId,
|
||||
associated_type_id: ast::DefId)
|
||||
-> Option<Ty<'tcx>>;
|
||||
/// Project an associated type from a non-higher-ranked trait reference.
|
||||
/// This is fairly straightforward and can be accommodated in any context.
|
||||
fn projected_ty(&self,
|
||||
span: Span,
|
||||
_trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
_item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
self.tcx().sess.span_err(
|
||||
span,
|
||||
"associated types are not accepted in this context");
|
||||
|
||||
self.tcx().types.err
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
|
||||
@ -255,6 +275,8 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
|
||||
}
|
||||
};
|
||||
|
||||
prohibit_projections(this.tcx(), assoc_bindings.as_slice());
|
||||
|
||||
create_substs_for_ast_path(this,
|
||||
rscope,
|
||||
path.span,
|
||||
@ -262,21 +284,19 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
|
||||
decl_generics,
|
||||
None,
|
||||
types,
|
||||
regions,
|
||||
assoc_bindings)
|
||||
regions)
|
||||
}
|
||||
|
||||
fn create_substs_for_ast_path<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
decl_def_id: ast::DefId,
|
||||
_decl_def_id: ast::DefId,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
types: Vec<Ty<'tcx>>,
|
||||
regions: Vec<ty::Region>,
|
||||
assoc_bindings: Vec<(ast::Ident, Ty<'tcx>)>)
|
||||
-> Substs<'tcx>
|
||||
regions: Vec<ty::Region>)
|
||||
-> Substs<'tcx>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
@ -382,52 +402,21 @@ fn create_substs_for_ast_path<'tcx,AC,RS>(
|
||||
}
|
||||
}
|
||||
|
||||
for formal_assoc in decl_generics.types.get_slice(AssocSpace).iter() {
|
||||
let mut found = false;
|
||||
for &(ident, ty) in assoc_bindings.iter() {
|
||||
if formal_assoc.name.ident() == ident {
|
||||
substs.types.push(AssocSpace, ty);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
match this.associated_type_binding(span,
|
||||
self_ty,
|
||||
decl_def_id,
|
||||
formal_assoc.def_id) {
|
||||
Some(ty) => {
|
||||
substs.types.push(AssocSpace, ty);
|
||||
}
|
||||
None => {
|
||||
substs.types.push(AssocSpace, ty::mk_err());
|
||||
span_err!(this.tcx().sess, span, E0171,
|
||||
"missing type for associated type `{}`",
|
||||
token::get_ident(formal_assoc.name.ident()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &(ident, _) in assoc_bindings.iter() {
|
||||
let mut formal_idents = decl_generics.types.get_slice(AssocSpace)
|
||||
.iter().map(|t| t.name.ident());
|
||||
if !formal_idents.any(|i| i == ident) {
|
||||
span_err!(this.tcx().sess, span, E0177,
|
||||
"associated type `{}` does not exist",
|
||||
token::get_ident(ident));
|
||||
}
|
||||
}
|
||||
|
||||
return substs;
|
||||
}
|
||||
|
||||
struct ConvertedBinding<'tcx> {
|
||||
item_name: ast::Name,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
data: &ast::AngleBracketedParameterData)
|
||||
-> (Vec<ty::Region>,
|
||||
Vec<Ty<'tcx>>,
|
||||
Vec<(ast::Ident, Ty<'tcx>)>)
|
||||
Vec<ConvertedBinding<'tcx>>)
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let regions: Vec<_> =
|
||||
@ -442,7 +431,9 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
|
||||
|
||||
let assoc_bindings: Vec<_> =
|
||||
data.bindings.iter()
|
||||
.map(|b| (b.ident, ast_ty_to_ty(this, rscope, &*b.ty)))
|
||||
.map(|b| ConvertedBinding { item_name: b.ident.name,
|
||||
ty: ast_ty_to_ty(this, rscope, &*b.ty),
|
||||
span: b.span })
|
||||
.collect();
|
||||
|
||||
(regions, types, assoc_bindings)
|
||||
@ -534,38 +525,47 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::PolyTraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let mut projections = Vec::new();
|
||||
|
||||
let trait_ref =
|
||||
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq);
|
||||
let trait_ref = (*trait_ref).clone();
|
||||
Rc::new(ty::Binder(trait_ref)) // Ugh.
|
||||
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
|
||||
self_ty, Some(&mut projections));
|
||||
|
||||
for projection in projections.into_iter() {
|
||||
poly_projections.push(ty::Binder(projection));
|
||||
}
|
||||
|
||||
ty::Binder(trait_ref)
|
||||
}
|
||||
|
||||
/// Instantiates the path for the given trait reference, assuming that it's
|
||||
/// bound to a valid trait type. Returns the def_id for the defining trait.
|
||||
/// Fails if the type is a type other than a trait type.
|
||||
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::TraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>,
|
||||
RS: RegionScope
|
||||
///
|
||||
/// 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,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::TraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) {
|
||||
def::DefTrait(trait_def_id) => {
|
||||
let trait_ref = Rc::new(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
&ast_trait_ref.path,
|
||||
allow_eq));
|
||||
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
|
||||
trait_ref.clone());
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
&ast_trait_ref.path,
|
||||
projections);
|
||||
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone());
|
||||
trait_ref
|
||||
}
|
||||
_ => {
|
||||
@ -576,20 +576,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(PartialEq,Show)]
|
||||
pub enum AllowEqConstraints {
|
||||
Allow,
|
||||
DontAllow
|
||||
}
|
||||
|
||||
fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
||||
fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
path: &ast::Path,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> ty::TraitRef<'tcx>
|
||||
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
debug!("ast_path_to_trait_ref {}", path);
|
||||
@ -624,11 +618,6 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
||||
}
|
||||
};
|
||||
|
||||
if allow_eq == AllowEqConstraints::DontAllow && assoc_bindings.len() > 0 {
|
||||
span_err!(this.tcx().sess, path.span, E0173,
|
||||
"equality constraints are not allowed in this position");
|
||||
}
|
||||
|
||||
let substs = create_substs_for_ast_path(this,
|
||||
&shifted_rscope,
|
||||
path.span,
|
||||
@ -636,10 +625,69 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
types,
|
||||
regions,
|
||||
assoc_bindings);
|
||||
regions);
|
||||
let substs = this.tcx().mk_substs(substs);
|
||||
|
||||
ty::TraitRef::new(trait_def_id, 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.as_slice());
|
||||
}
|
||||
Some(ref mut v) => {
|
||||
for binding in assoc_bindings.iter() {
|
||||
match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
|
||||
Ok(pp) => { v.push(pp); }
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait_ref
|
||||
}
|
||||
|
||||
pub fn ast_type_binding_to_projection_predicate<'tcx,AC>(
|
||||
this: &AC,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
binding: &ConvertedBinding<'tcx>)
|
||||
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
|
||||
where AC : AstConv<'tcx>
|
||||
{
|
||||
// Given something like `U : SomeTrait<T=X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait : SuperTrait<int> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B : SubTrait<T=foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// FIXME(#19541): supertrait upcasting not actually impl'd :)
|
||||
|
||||
if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
|
||||
this.tcx().sess.span_err(
|
||||
binding.span,
|
||||
format!("no associated type `{}` defined in `{}`",
|
||||
token::get_name(binding.item_name),
|
||||
trait_ref.user_string(this.tcx())).as_slice());
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
Ok(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
item_name: binding.item_name,
|
||||
},
|
||||
ty: binding.ty,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
@ -784,12 +832,14 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
ast::TyPath(ref path, id) => {
|
||||
match this.tcx().def_map.borrow().get(&id) {
|
||||
Some(&def::DefTrait(trait_def_id)) => {
|
||||
return Ok(ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
AllowEqConstraints::Allow)));
|
||||
// TODO do something with this
|
||||
let mut projections = Vec::new();
|
||||
Ok(ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projections))))
|
||||
}
|
||||
_ => {
|
||||
span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait");
|
||||
@ -831,7 +881,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::Binder<ty::TraitRef<'tcx>>,
|
||||
bounds: &[ast::TyParamBound])
|
||||
-> Ty<'tcx>
|
||||
where AC : AstConv<'tcx>, RS : RegionScope
|
||||
@ -849,6 +899,68 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
||||
result
|
||||
}
|
||||
|
||||
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
ast_ty: &ast::Ty,
|
||||
provenance: def::TyParamProvenance,
|
||||
assoc_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let ty_param_def_id = provenance.def_id();
|
||||
let mut suitable_bounds: Vec<_>;
|
||||
let ty_param_name: ast::Name;
|
||||
{ // contain scope of refcell:
|
||||
let ty_param_defs = tcx.ty_param_defs.borrow();
|
||||
let ty_param_def = &ty_param_defs[ty_param_def_id.node];
|
||||
ty_param_name = ty_param_def.name;
|
||||
|
||||
// FIXME(#19541): we should consider associated types in
|
||||
// super-traits. Probably by elaborating the bounds.
|
||||
|
||||
suitable_bounds =
|
||||
ty_param_def.bounds.trait_bounds // TODO trait_bounds, no good
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
|
||||
.collect();
|
||||
}
|
||||
|
||||
if suitable_bounds.len() == 0 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("associated type `{}` not found for type parameter `{}`",
|
||||
token::get_name(assoc_name),
|
||||
token::get_name(ty_param_name)).as_slice());
|
||||
return this.tcx().types.err;
|
||||
}
|
||||
|
||||
if suitable_bounds.len() > 1 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("ambiguous associated type `{}` in bounds of `{}`",
|
||||
token::get_name(assoc_name),
|
||||
token::get_name(ty_param_name)).as_slice());
|
||||
|
||||
for suitable_bound in suitable_bounds.iter() {
|
||||
span_note!(this.tcx().sess, ast_ty.span,
|
||||
"associated type `{}` could derive from `{}`",
|
||||
token::get_name(ty_param_name),
|
||||
suitable_bound.user_string(this.tcx()));
|
||||
}
|
||||
}
|
||||
|
||||
let suitable_bound = suitable_bounds.pop().unwrap().clone();
|
||||
return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
|
||||
}
|
||||
|
||||
fn trait_defines_associated_type_named(this: &AstConv,
|
||||
trait_def_id: ast::DefId,
|
||||
assoc_name: ast::Name)
|
||||
-> bool
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||
trait_def.associated_type_names.contains(&assoc_name)
|
||||
}
|
||||
|
||||
fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
ast_ty: &ast::Ty, // the TyQPath
|
||||
@ -867,33 +979,13 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
|
||||
rscope,
|
||||
&*qpath.trait_ref,
|
||||
Some(self_type),
|
||||
AllowEqConstraints::DontAllow);
|
||||
None);
|
||||
|
||||
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
|
||||
|
||||
if let Some(ty) = find_assoc_ty(this, &*trait_ref, qpath.item_name) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
this.tcx().sess.span_bug(ast_ty.span,
|
||||
"this associated type didn't get added \
|
||||
as a parameter for some reason")
|
||||
}
|
||||
|
||||
fn find_assoc_ty<'tcx, AC>(this: &AC,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
type_name: ast::Ident)
|
||||
-> Option<Ty<'tcx>>
|
||||
where AC: AstConv<'tcx> {
|
||||
let trait_def = this.get_trait_def(trait_ref.def_id);
|
||||
|
||||
for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
|
||||
if ty_param_def.name == type_name.name {
|
||||
return Some(trait_ref.substs.type_for_def(ty_param_def));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
return this.projected_ty(ast_ty.span,
|
||||
trait_ref,
|
||||
qpath.item_name.name); // TODO change qpath to use name
|
||||
}
|
||||
|
||||
// Parses the programmer's textual representation of a type into our
|
||||
@ -928,6 +1020,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
ast::TyObjectSum(ref ty, ref bounds) => {
|
||||
match ast_ty_to_trait_ref(this, rscope, &**ty, bounds[]) {
|
||||
Ok(trait_ref) => {
|
||||
let trait_ref = trait_ref.remove_rc();
|
||||
trait_ref_to_object_type(this, rscope, ast_ty.span,
|
||||
trait_ref, bounds[])
|
||||
}
|
||||
@ -1000,13 +1093,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
def::DefTrait(trait_def_id) => {
|
||||
// N.B. this case overlaps somewhat with
|
||||
// TyObjectSum, see that fn for details
|
||||
let result = ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
AllowEqConstraints::Allow));
|
||||
trait_ref_to_object_type(this, rscope, path.span, result, &[])
|
||||
let mut projections = Vec::new(); // TODO
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projections));
|
||||
let trait_ref = (*trait_ref).clone();
|
||||
let trait_ref = ty::Binder(trait_ref);
|
||||
trait_ref_to_object_type(this, rscope, path.span, trait_ref, &[])
|
||||
}
|
||||
def::DefTy(did, _) | def::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
@ -1048,44 +1144,9 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
.get())[]);
|
||||
this.tcx().types.err
|
||||
}
|
||||
def::DefAssociatedPath(typ, assoc_ident) => {
|
||||
// FIXME(#19541): in both branches we should consider
|
||||
// associated types in super-traits.
|
||||
let (assoc_tys, tp_name): (Vec<_>, _) = match typ {
|
||||
def::TyParamProvenance::FromParam(did) |
|
||||
def::TyParamProvenance::FromSelf(did) => {
|
||||
let ty_param_defs = tcx.ty_param_defs.borrow();
|
||||
let tp_def = &(*ty_param_defs)[did.node];
|
||||
let assoc_tys = tp_def.bounds.trait_bounds.iter()
|
||||
.filter_map(|b| find_assoc_ty(this, &b.0, assoc_ident))
|
||||
.collect();
|
||||
(assoc_tys, token::get_name(tp_def.name).to_string())
|
||||
}
|
||||
};
|
||||
|
||||
if assoc_tys.len() == 0 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("associated type `{}` not \
|
||||
found for type parameter `{}`",
|
||||
token::get_ident(assoc_ident),
|
||||
tp_name).as_slice());
|
||||
return ty::mk_err()
|
||||
}
|
||||
|
||||
if assoc_tys.len() > 1 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("ambiguous associated type \
|
||||
`{}` in bounds of `{}`",
|
||||
token::get_ident(assoc_ident),
|
||||
tp_name).as_slice());
|
||||
}
|
||||
|
||||
let mut result_ty = assoc_tys[0];
|
||||
if let Some(substs) = this.get_free_substs() {
|
||||
result_ty = result_ty.subst(tcx, substs);
|
||||
}
|
||||
|
||||
result_ty
|
||||
def::DefAssociatedPath(provenance, assoc_ident) => {
|
||||
// TODO update DefAssociatedPath to use name
|
||||
associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
@ -1440,7 +1501,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: Option<&ty::Binder<ty::TraitRef<'tcx>>>, // None for boxed closures
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds
|
||||
{
|
||||
@ -1461,13 +1522,15 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
||||
{
|
||||
let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);
|
||||
|
||||
let mut projections = Vec::new();
|
||||
let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
|
||||
Some(trait_bound) => {
|
||||
Some(instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
AllowEqConstraints::Allow))
|
||||
let ptr = instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projections);
|
||||
Some(ptr.remove_rc())
|
||||
}
|
||||
None => {
|
||||
this.tcx().sess.span_err(
|
||||
@ -1477,11 +1540,13 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
||||
}
|
||||
};
|
||||
|
||||
// TODO use projections somewhere
|
||||
|
||||
let bounds =
|
||||
conv_existential_bounds_from_partitioned_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
main_trait_bound.as_ref().map(|tr| &**tr),
|
||||
main_trait_bound.as_ref(),
|
||||
partitioned_bounds);
|
||||
|
||||
match main_trait_bound {
|
||||
@ -1494,7 +1559,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: Option<&ty::Binder<ty::TraitRef<'tcx>>>, // None for boxed closures
|
||||
partitioned_bounds: PartitionedBounds)
|
||||
-> ty::ExistentialBounds
|
||||
where AC: AstConv<'tcx>, RS:RegionScope
|
||||
@ -1532,7 +1597,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
||||
fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>,
|
||||
principal_trait_ref: Option<&ty::Binder<ty::TraitRef<'tcx>>>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> Option<ty::Region>
|
||||
{
|
||||
@ -1592,7 +1657,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures
|
||||
principal_trait_ref: Option<&ty::Binder<ty::TraitRef<'tcx>>>, // None for closures
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
{
|
||||
@ -1660,6 +1725,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
if ty::try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
// TODO Copy<T>?
|
||||
continue; // success
|
||||
}
|
||||
}
|
||||
@ -1683,3 +1749,13 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
||||
region_bounds: region_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
bindings: &[ConvertedBinding<'tcx>])
|
||||
{
|
||||
for binding in bindings.iter().take(1) {
|
||||
tcx.sess.span_err(
|
||||
binding.span,
|
||||
"associated type bindings are not allowed here");
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use middle::def;
|
||||
use middle::infer;
|
||||
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{Substs};
|
||||
use middle::ty::{mod, Ty};
|
||||
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
|
||||
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
|
||||
@ -410,17 +410,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
||||
demand::eqtype(fcx, pat.span, expected, pat_ty);
|
||||
|
||||
let real_path_ty = fcx.node_ty(pat.id);
|
||||
let (arg_tys, kind_name) = match real_path_ty.sty {
|
||||
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
|
||||
ty::ty_enum(enum_def_id, expected_substs)
|
||||
if def == def::DefVariant(enum_def_id, def.def_id(), false) => {
|
||||
if def == def::DefVariant(enum_def_id, def.def_id(), false) =>
|
||||
{
|
||||
let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id());
|
||||
(variant.args.iter().map(|t| t.subst(tcx, expected_substs)).collect::<Vec<_>>(),
|
||||
"variant")
|
||||
(variant.args.iter()
|
||||
.map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t))
|
||||
.collect(),
|
||||
"variant")
|
||||
}
|
||||
ty::ty_struct(struct_def_id, expected_substs) => {
|
||||
let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs);
|
||||
(struct_fields.iter().map(|field| field.mt.ty).collect::<Vec<_>>(),
|
||||
"struct")
|
||||
(struct_fields.iter()
|
||||
.map(|field| fcx.instantiate_type_scheme(pat.span,
|
||||
expected_substs,
|
||||
&field.mt.ty))
|
||||
.collect(),
|
||||
"struct")
|
||||
}
|
||||
_ => {
|
||||
let name = pprust::path_to_string(path);
|
||||
|
73
src/librustc_typeck/check/assoc.rs
Normal file
73
src/librustc_typeck/check/assoc.rs
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
let value = infcx.resolve_type_vars_if_possible(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
return value.clone();
|
||||
}
|
||||
|
||||
let mut normalizer = AssociatedTypeNormalizer { span: span,
|
||||
body_id: body_id,
|
||||
infcx: infcx,
|
||||
fulfillment_cx: fulfillment_cx };
|
||||
value.fold_with(&mut normalizer)
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) => {
|
||||
let cause =
|
||||
ObligationCause::new(
|
||||
self.span,
|
||||
self.body_id,
|
||||
ObligationCauseCode::MiscObligation);
|
||||
let trait_ref = Rc::new(data.trait_ref.clone());
|
||||
self.fulfillment_cx
|
||||
.normalize_associated_type(self.infcx,
|
||||
trait_ref,
|
||||
data.item_name,
|
||||
cause)
|
||||
}
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ use super::{check_fn, Expectation, FnCtxt};
|
||||
use astconv;
|
||||
use middle::infer;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, ToPolyTraitRef, Ty};
|
||||
use rscope::RegionScope;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
@ -168,7 +168,8 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
|
||||
{
|
||||
match expected_ty.sty {
|
||||
ty::ty_trait(ref object_type) => {
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
|
||||
let trait_ref = object_type.principal_trait_ref_with_self_ty(fcx.tcx().types.err);
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
|
||||
@ -227,23 +228,21 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
|
||||
{
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
|
||||
match self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &**trait_ref) {
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
use super::probe;
|
||||
|
||||
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
|
||||
use middle::subst::{mod, Subst};
|
||||
use middle::subst::{mod};
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin,
|
||||
@ -227,14 +227,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
let upcast_poly_trait_ref =
|
||||
this.upcast(original_poly_trait_ref.clone(), trait_def_id);
|
||||
let upcast_trait_ref =
|
||||
this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref);
|
||||
this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
|
||||
debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
|
||||
original_poly_trait_ref.repr(this.tcx()),
|
||||
upcast_trait_ref.repr(this.tcx()),
|
||||
trait_def_id.repr(this.tcx()));
|
||||
let substs = upcast_trait_ref.substs.clone();
|
||||
let origin = MethodTraitObject(MethodObject {
|
||||
trait_ref: Rc::new(upcast_trait_ref),
|
||||
trait_ref: upcast_trait_ref,
|
||||
object_trait_id: trait_def_id,
|
||||
method_num: method_num,
|
||||
real_index: real_index,
|
||||
@ -254,9 +254,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
// parameters from the trait ([$A,$B]), not those from
|
||||
// the impl ([$A,$B,$C]) not the receiver type ([$C]).
|
||||
let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
|
||||
let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id)
|
||||
.unwrap()
|
||||
.subst(self.tcx(), &impl_polytype.substs);
|
||||
let impl_trait_ref =
|
||||
self.fcx.instantiate_type_scheme(
|
||||
self.span,
|
||||
&impl_polytype.substs,
|
||||
&ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap());
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
|
||||
method_num: method_num });
|
||||
(impl_trait_ref.substs.clone(), origin)
|
||||
@ -284,9 +286,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
probe::WhereClausePick(ref poly_trait_ref, method_num) => {
|
||||
// Where clauses can have bound regions in them. We need to instantiate
|
||||
// those to convert from a poly-trait-ref to a trait-ref.
|
||||
let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref);
|
||||
let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref);
|
||||
let substs = trait_ref.substs.clone();
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref),
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
|
||||
method_num: method_num });
|
||||
(substs, origin)
|
||||
}
|
||||
@ -425,9 +427,13 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
// Substitute the type/early-bound-regions into the method
|
||||
// signature. In addition, the method signature may bind
|
||||
// late-bound regions, so instantiate those.
|
||||
let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs);
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
|
||||
let method_sig = self.fcx.instantiate_type_scheme(self.span,
|
||||
&all_substs,
|
||||
&pick.method_ty.fty.sig);
|
||||
debug!("late-bound lifetimes from method substituted, method_sig={}",
|
||||
method_sig.repr(self.tcx()));
|
||||
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
|
||||
debug!("late-bound lifetimes from method instantiated, method_sig={}",
|
||||
method_sig.repr(self.tcx()));
|
||||
|
||||
@ -626,9 +632,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
}
|
||||
|
||||
fn upcast(&mut self,
|
||||
source_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
source_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
target_trait_def_id: ast::DefId)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) {
|
||||
if super_trait_ref.def_id() == target_trait_def_id {
|
||||
|
@ -16,7 +16,6 @@ use check::{impl_self_ty};
|
||||
use check::vtable;
|
||||
use check::vtable::select_new_fcx_obligations;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::*;
|
||||
use middle::ty;
|
||||
@ -167,7 +166,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)));
|
||||
|
||||
// Construct an obligation
|
||||
let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone()));
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = traits::Obligation::misc(span,
|
||||
fcx.body_id,
|
||||
poly_trait_ref.as_predicate());
|
||||
@ -193,11 +192,12 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
|
||||
// Substitute the trait parameters into the method type and
|
||||
// instantiate late-bound regions to get the actual method type.
|
||||
let ref bare_fn_ty = method_ty.fty;
|
||||
let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs);
|
||||
let bare_fn_ty = fcx.instantiate_type_scheme(span,
|
||||
&trait_ref.substs,
|
||||
&method_ty.fty);
|
||||
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
|
||||
infer::FnCall,
|
||||
&fn_sig).0;
|
||||
&bare_fn_ty.sig).0;
|
||||
let transformed_self_ty = fn_sig.inputs[0];
|
||||
let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy {
|
||||
sig: ty::Binder(fn_sig),
|
||||
|
@ -18,7 +18,7 @@ use middle::fast_reject;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, ToPolyTraitRef};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::infer;
|
||||
use middle::infer::InferCtxt;
|
||||
@ -61,7 +61,7 @@ enum CandidateKind<'tcx> {
|
||||
ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
|
||||
subst::Substs<'tcx>, MethodIndex),
|
||||
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClauseCandidate(Rc<ty::PolyTraitRef<'tcx>>, MethodIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
}
|
||||
|
||||
pub struct Pick<'tcx> {
|
||||
@ -76,7 +76,7 @@ pub enum PickKind<'tcx> {
|
||||
ObjectPick(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint),
|
||||
ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex),
|
||||
TraitPick(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClausePick(/* Trait */ Rc<ty::PolyTraitRef<'tcx>>, MethodIndex),
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
}
|
||||
|
||||
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
|
||||
@ -235,7 +235,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
match self_ty.sty {
|
||||
ty::ty_trait(box ref data) => {
|
||||
self.assemble_inherent_candidates_from_object(self_ty, data);
|
||||
self.assemble_inherent_impl_candidates_for_type(data.principal.def_id());
|
||||
self.assemble_inherent_impl_candidates_for_type(data.principal_def_id());
|
||||
}
|
||||
ty::ty_enum(did, _) |
|
||||
ty::ty_struct(did, _) |
|
||||
@ -308,7 +308,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
|
||||
self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| {
|
||||
let vtable_index =
|
||||
get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num);
|
||||
get_method_index(tcx, &new_trait_ref, trait_ref.clone(), method_num);
|
||||
|
||||
let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs());
|
||||
|
||||
@ -330,13 +330,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
match trait_ref.self_ty().sty {
|
||||
ty::ty_param(ref p) if *p == param_ty => Some(trait_ref.clone()),
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
match trait_predicate.0.trait_ref.self_ty().sty {
|
||||
ty::ty_param(ref p) if *p == param_ty => {
|
||||
Some(trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
None
|
||||
@ -381,10 +384,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
// create the candidates.
|
||||
fn elaborate_bounds(
|
||||
&mut self,
|
||||
bounds: &[Rc<ty::PolyTraitRef<'tcx>>],
|
||||
bounds: &[ty::PolyTraitRef<'tcx>],
|
||||
num_includes_types: bool,
|
||||
mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>,
|
||||
tr: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
tr: ty::PolyTraitRef<'tcx>,
|
||||
m: Rc<ty::Method<'tcx>>,
|
||||
method_num: uint|)
|
||||
{
|
||||
@ -996,7 +999,7 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
// to a trait and its supertraits.
|
||||
fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
subtrait: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
subtrait: ty::PolyTraitRef<'tcx>,
|
||||
n_method: uint) -> uint {
|
||||
// We need to figure the "real index" of the method in a
|
||||
// listing of all the methods of an object. We do this by
|
||||
|
@ -93,10 +93,10 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||
use middle::traits;
|
||||
use middle::ty::{FnSig, VariantInfo, TypeScheme};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use rscope::RegionScope;
|
||||
use session::Session;
|
||||
use {CrateCtxt, lookup_def_ccx, no_params, require_same_types};
|
||||
@ -120,6 +120,7 @@ use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::visit::{mod, Visitor};
|
||||
|
||||
mod assoc;
|
||||
pub mod _match;
|
||||
pub mod vtable;
|
||||
pub mod writeback;
|
||||
@ -348,6 +349,17 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, body_id: ast::NodeId, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
|
||||
{
|
||||
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
|
||||
assoc::normalize_associated_types_in(&self.infcx,
|
||||
&mut *fulfillment_cx, span,
|
||||
body_id,
|
||||
value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Used by check_const and check_enum_variants
|
||||
@ -414,15 +426,18 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
id: ast::NodeId,
|
||||
fty: Ty<'tcx>,
|
||||
raw_fty: Ty<'tcx>,
|
||||
param_env: ty::ParameterEnvironment<'tcx>) {
|
||||
// Compute the fty from point of view of inside fn
|
||||
// (replace any type-scheme with a type)
|
||||
let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
|
||||
|
||||
match fty.sty {
|
||||
match raw_fty.sty {
|
||||
ty::ty_bare_fn(_, ref fn_ty) => {
|
||||
let inh = Inherited::new(ccx.tcx, param_env);
|
||||
|
||||
// Compute the fty from point of view of inside fn
|
||||
// (replace any type-scheme with a type, and normalize
|
||||
// associated types appearing in the fn signature).
|
||||
let fn_ty = fn_ty.subst(ccx.tcx, &inh.param_env.free_substs);
|
||||
let fn_ty = inh.normalize_associated_types_in(body.span, body.id, &fn_ty);
|
||||
|
||||
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig,
|
||||
decl, id, body, &inh);
|
||||
|
||||
@ -532,7 +547,8 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
|
||||
fn_id: ast::NodeId,
|
||||
body: &ast::Block,
|
||||
inherited: &'a Inherited<'a, 'tcx>)
|
||||
-> FnCtxt<'a, 'tcx> {
|
||||
-> FnCtxt<'a, 'tcx>
|
||||
{
|
||||
let tcx = ccx.tcx;
|
||||
let err_count_on_creation = tcx.sess.err_count();
|
||||
|
||||
@ -771,9 +787,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
// corresponding method definition in the trait.
|
||||
let opt_trait_method_ty =
|
||||
trait_items.iter()
|
||||
.find(|ti| {
|
||||
ti.name() == impl_item_ty.name()
|
||||
});
|
||||
.find(|ti| ti.name() == impl_item_ty.name());
|
||||
match opt_trait_method_ty {
|
||||
Some(trait_method_ty) => {
|
||||
match (trait_method_ty, &impl_item_ty) {
|
||||
@ -917,6 +931,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_trait_ref.repr(tcx));
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||
|
||||
let trait_to_impl_substs = &impl_trait_ref.substs;
|
||||
|
||||
@ -1034,21 +1049,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
// this kind of equivalency just fine.
|
||||
|
||||
// Create mapping from impl to skolemized.
|
||||
let skol_tps =
|
||||
impl_m.generics.types.map(
|
||||
|d| ty::mk_param_from_def(tcx, d));
|
||||
let skol_regions =
|
||||
impl_m.generics.regions.map(
|
||||
|l| ty::free_region_from_def(impl_m_body_id, l));
|
||||
let impl_to_skol_substs =
|
||||
subst::Substs::new(skol_tps.clone(), skol_regions.clone());
|
||||
let impl_param_env = ty::construct_parameter_environment(tcx, &impl_m.generics, impl_m_body_id);
|
||||
let impl_to_skol_substs = &impl_param_env.free_substs;
|
||||
|
||||
// Create mapping from trait to skolemized.
|
||||
let trait_to_skol_substs =
|
||||
trait_to_impl_substs
|
||||
.subst(tcx, &impl_to_skol_substs)
|
||||
.with_method(skol_tps.get_slice(subst::FnSpace).to_vec(),
|
||||
skol_regions.get_slice(subst::FnSpace).to_vec());
|
||||
.subst(tcx, impl_to_skol_substs)
|
||||
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
|
||||
impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
|
||||
|
||||
// Check region bounds.
|
||||
if !check_region_bounds_on_impl_method(tcx,
|
||||
@ -1057,7 +1066,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
&trait_m.generics,
|
||||
&impl_m.generics,
|
||||
&trait_to_skol_substs,
|
||||
&impl_to_skol_substs) {
|
||||
impl_to_skol_substs) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1120,7 +1129,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
for impl_trait_bound in impl_param_bounds.trait_bounds.iter() {
|
||||
debug!("compare_impl_method(): impl-trait-bound subst");
|
||||
let impl_trait_bound =
|
||||
impl_trait_bound.subst(tcx, &impl_to_skol_substs);
|
||||
impl_trait_bound.subst(tcx, impl_to_skol_substs);
|
||||
|
||||
// There may be late-bound regions from the impl in the
|
||||
// impl's bound, so "liberate" those. Note that the
|
||||
@ -1134,7 +1143,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
debug!("compare_impl_method(): trait-bound subst");
|
||||
let trait_bound =
|
||||
trait_bound.subst(tcx, &trait_to_skol_substs);
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
infer::mk_sub_poly_trait_refs(&infcx,
|
||||
true,
|
||||
infer::Misc(impl_m_span),
|
||||
@ -1155,9 +1163,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
|
||||
// Compute skolemized form of impl and trait method tys.
|
||||
let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
|
||||
let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
|
||||
let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
|
||||
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
|
||||
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
|
||||
let trait_fty =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&mut fulfillment_cx,
|
||||
impl_m_span,
|
||||
impl_m_body_id,
|
||||
&trait_fty);
|
||||
|
||||
// Check the impl method type IM is a subtype of the trait method
|
||||
// type TM. To see why this makes sense, think of a vtable. The
|
||||
@ -1183,6 +1197,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
// Run the fulfillment context to completion to accommodate any
|
||||
// associated type normalizations that may have occurred.
|
||||
match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env, tcx) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, &errors);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, resolve all regions. This catches wily misuses of lifetime
|
||||
// parameters.
|
||||
infcx.resolve_regions_and_report_errors(impl_m_body_id);
|
||||
@ -1526,19 +1549,28 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
self.infcx().next_ty_var()
|
||||
}
|
||||
|
||||
fn associated_types_of_trait_are_valid(&self, _: Ty, _: ast::DefId)
|
||||
-> bool {
|
||||
false
|
||||
fn projected_ty_from_poly_trait_ref(&self,
|
||||
span: Span,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let (trait_ref, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span,
|
||||
infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name),
|
||||
&poly_trait_ref);
|
||||
|
||||
self.normalize_associated_type(span, trait_ref, item_name)
|
||||
}
|
||||
|
||||
fn associated_type_binding(&self,
|
||||
span: Span,
|
||||
_: Option<Ty<'tcx>>,
|
||||
_: ast::DefId,
|
||||
_: ast::DefId)
|
||||
-> Option<Ty<'tcx>> {
|
||||
self.tcx().sess.span_err(span, "unsupported associated type binding");
|
||||
Some(ty::mk_err())
|
||||
fn projected_ty(&self,
|
||||
span: Span,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
self.normalize_associated_type(span, trait_ref, item_name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1560,22 +1592,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn err_count_since_creation(&self) -> uint {
|
||||
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
|
||||
Some(self.next_region_var(infer::MiscVariable(span)))
|
||||
}
|
||||
|
||||
fn anon_regions(&self, span: Span, count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>> {
|
||||
Ok(Vec::from_fn(count, |_| {
|
||||
self.next_region_var(infer::MiscVariable(span))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn tag(&self) -> String {
|
||||
format!("{}", self as *const FnCtxt)
|
||||
}
|
||||
@ -1609,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
pub fn write_object_cast(&self,
|
||||
key: ast::NodeId,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>) {
|
||||
trait_ref: ty::PolyTraitRef<'tcx>) {
|
||||
debug!("write_object_cast key={} trait_ref={}",
|
||||
key, trait_ref.repr(self.tcx()));
|
||||
self.inh.object_cast_map.borrow_mut().insert(key, trait_ref);
|
||||
@ -1660,6 +1677,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.inh.adjustments.borrow_mut().insert(node_id, adj);
|
||||
}
|
||||
|
||||
/// Basically whenever we are converting from a type scheme into
|
||||
/// the fn body space, we always want to normalize associated
|
||||
/// types as well. This function combines the two.
|
||||
fn instantiate_type_scheme<T>(&self,
|
||||
span: Span,
|
||||
substs: &Substs<'tcx>,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
|
||||
{
|
||||
let value = value.subst(self.tcx(), substs);
|
||||
let result = self.normalize_associated_types_in(span, &value);
|
||||
debug!("instantiate_type_scheme(value={}, substs={}) = {}",
|
||||
value.repr(self.tcx()),
|
||||
substs.repr(self.tcx()),
|
||||
result.repr(self.tcx()));
|
||||
result
|
||||
}
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
|
||||
{
|
||||
self.inh.normalize_associated_types_in(span, self.body_id, value)
|
||||
}
|
||||
|
||||
fn normalize_associated_type(&self,
|
||||
span: Span,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let cause = traits::ObligationCause::new(span,
|
||||
self.body_id,
|
||||
traits::ObligationCauseCode::MiscObligation);
|
||||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.normalize_associated_type(self.infcx(),
|
||||
trait_ref,
|
||||
item_name,
|
||||
cause)
|
||||
}
|
||||
|
||||
fn register_adjustment_obligations(&self,
|
||||
span: Span,
|
||||
adj: &ty::AutoAdjustment<'tcx>) {
|
||||
@ -1754,7 +1813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
traits::ItemObligation(def_id)),
|
||||
&bounds);
|
||||
let monotype =
|
||||
type_scheme.ty.subst(self.tcx(), &substs);
|
||||
self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
|
||||
|
||||
TypeAndSubsts {
|
||||
ty: monotype,
|
||||
@ -2017,7 +2076,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Copy, Show,PartialEq,Eq)]
|
||||
//impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> {
|
||||
// fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
|
||||
// Some(self.next_region_var(infer::MiscVariable(span)))
|
||||
// }
|
||||
//
|
||||
// fn anon_regions(&self, span: Span, count: uint)
|
||||
// -> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>> {
|
||||
// Ok(Vec::from_fn(count, |_| {
|
||||
// self.next_region_var(infer::MiscVariable(span))
|
||||
// }))
|
||||
// }
|
||||
//}
|
||||
|
||||
#[deriving(Copy, Show, PartialEq, Eq)]
|
||||
pub enum LvaluePreference {
|
||||
PreferMutLvalue,
|
||||
NoPreference
|
||||
@ -2879,7 +2951,7 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
let rps = fcx.inh.infcx.region_vars_for_defs(span, rps);
|
||||
let tps = fcx.inh.infcx.next_ty_vars(n_tps);
|
||||
let substs = subst::Substs::new_type(tps, rps);
|
||||
let substd_ty = raw_ty.subst(tcx, &substs);
|
||||
let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty);
|
||||
|
||||
TypeAndSubsts { substs: substs, ty: substd_ty }
|
||||
}
|
||||
@ -5219,9 +5291,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
||||
// Substitute the values for the type parameters into the type of
|
||||
// the referenced item.
|
||||
let ty_substituted = ty_late_bound.subst(fcx.tcx(), &substs);
|
||||
|
||||
debug!("ty_substituted: ty_substituted={}", ty_substituted.repr(fcx.tcx()));
|
||||
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound);
|
||||
|
||||
fcx.write_ty(node_id, ty_substituted);
|
||||
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
|
||||
|
@ -121,6 +121,15 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
self.push_param_constraint_from_top(p);
|
||||
}
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
// `<T as TraitRef<..>>::Name`
|
||||
|
||||
// TODO What region constraints are necessary here, if any??
|
||||
|
||||
// this seems like a minimal requirement:
|
||||
self.accumulate_from_ty(data.trait_ref.self_ty());
|
||||
}
|
||||
|
||||
ty::ty_tup(ref tuptys) => {
|
||||
for &tupty in tuptys.iter() {
|
||||
self.accumulate_from_ty(tupty);
|
||||
|
@ -13,7 +13,7 @@ use middle::subst::{FnSpace};
|
||||
use middle::traits;
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::report_fulfillment_errors;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef};
|
||||
use middle::infer;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
@ -136,7 +136,7 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
let object_trait_ref =
|
||||
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
|
||||
for tr in traits::supertraits(tcx, object_trait_ref) {
|
||||
check_object_safety_inner(tcx, &*tr, span);
|
||||
check_object_safety_inner(tcx, &tr, span);
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,7 +231,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
object_trait: &ty::TyTrait<'tcx>,
|
||||
referent_ty: Ty<'tcx>)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
// We can only make objects from sized types.
|
||||
fcx.register_builtin_bound(
|
||||
@ -258,7 +258,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty)),
|
||||
ty::Predicate::Trait(object_trait_ref.clone()));
|
||||
object_trait_ref.as_predicate());
|
||||
fcx.register_predicate(object_obligation);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
@ -314,3 +314,4 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
|
||||
use CrateCtxt;
|
||||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
@ -148,7 +147,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
region::CodeExtent::from_node_id(item.id),
|
||||
Some(&mut this.cache));
|
||||
let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
|
||||
let item_ty = type_scheme.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let item_ty = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&type_scheme.ty);
|
||||
bounds_checker.check_traits_in_ty(item_ty);
|
||||
});
|
||||
}
|
||||
@ -168,7 +169,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
// that is, with all type parameters converted from bound
|
||||
// to free.
|
||||
let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
|
||||
let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let self_ty = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&self_ty);
|
||||
|
||||
bounds_checker.check_traits_in_ty(self_ty);
|
||||
|
||||
@ -178,7 +181,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
None => { return; }
|
||||
Some(t) => { t }
|
||||
};
|
||||
let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let trait_ref = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&trait_ref);
|
||||
|
||||
// There are special rules that apply to drop.
|
||||
if
|
||||
@ -209,7 +214,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
||||
// trait reference. Instead, this is done at the impl site.
|
||||
// Arguably this is wrong and we should treat the trait-reference
|
||||
// the same way as we treat the self-type.
|
||||
bounds_checker.check_trait_ref(&trait_ref);
|
||||
bounds_checker.check_trait_ref(&*trait_ref);
|
||||
|
||||
let cause =
|
||||
traits::ObligationCause::new(
|
||||
@ -344,7 +349,8 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
||||
//
|
||||
// (I believe we should do the same for traits, but
|
||||
// that will require an RFC. -nmatsakis)
|
||||
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = type_scheme
|
||||
.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = filter_to_trait_obligations(bounds);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
@ -397,7 +403,9 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
|
||||
let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let field_ty = fcx.instantiate_type_scheme(field.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&field_ty);
|
||||
AdtField { ty: field_ty, span: field.span }
|
||||
})
|
||||
.collect();
|
||||
@ -416,7 +424,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
AdtVariant {
|
||||
fields: args.iter().enumerate().map(|(index, arg)| {
|
||||
let arg_ty = arg_tys[index];
|
||||
let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let arg_ty =
|
||||
fcx.instantiate_type_scheme(variant.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&arg_ty);
|
||||
AdtField {
|
||||
ty: arg_ty,
|
||||
span: arg.ty.span
|
||||
@ -443,7 +454,8 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
|
||||
let mut result = ty::GenericBounds::empty();
|
||||
for (space, _, predicate) in bounds.predicates.iter_enumerated() {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(..) => {
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Projection(..) => {
|
||||
result.predicates.push(space, predicate.clone())
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
|
@ -27,6 +27,7 @@ use middle::ty::{ty_param, TypeScheme, ty_ptr};
|
||||
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
|
||||
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open};
|
||||
use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
|
||||
use middle::ty::{ty_projection};
|
||||
use middle::ty;
|
||||
use CrateCtxt;
|
||||
use middle::infer::combine::Combine;
|
||||
@ -64,13 +65,13 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
ty_trait(ref t) => {
|
||||
Some(t.principal.def_id())
|
||||
Some(t.principal_def_id())
|
||||
}
|
||||
|
||||
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
|
||||
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
|
||||
ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
|
||||
ty_ptr(_) | ty_rptr(_, _) => {
|
||||
ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,8 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
ty::ty_struct(def_id, _) => {
|
||||
self.check_def_id(item.span, def_id);
|
||||
}
|
||||
ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => {
|
||||
self.check_def_id(item.span, principal.def_id());
|
||||
ty::ty_trait(ref data) => {
|
||||
self.check_def_id(item.span, data.principal_def_id());
|
||||
}
|
||||
_ => {
|
||||
span_err!(self.tcx.sess, item.span, E0118,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -770,33 +770,38 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id());
|
||||
ty::ty_projection(ref data) => {
|
||||
let trait_ref = &data.trait_ref;
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
|
||||
let generics = &trait_def.generics;
|
||||
self.add_constraints_from_substs(
|
||||
trait_ref.def_id,
|
||||
generics.types.as_slice(),
|
||||
generics.regions.as_slice(),
|
||||
&trait_ref.substs,
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_trait(ref data) => {
|
||||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx().types.err);
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id());
|
||||
let generics = &trait_def.generics;
|
||||
|
||||
// Traits DO have a Self type parameter, but it is
|
||||
// erased from object types.
|
||||
assert!(!generics.types.is_empty_in(subst::SelfSpace) &&
|
||||
principal.substs().types.is_empty_in(subst::SelfSpace));
|
||||
|
||||
// Traits never declare region parameters in the self
|
||||
// space.
|
||||
// space nor anything in the fn space.
|
||||
assert!(generics.regions.is_empty_in(subst::SelfSpace));
|
||||
|
||||
// Traits never declare type/region parameters in the
|
||||
// fn space.
|
||||
assert!(generics.types.is_empty_in(subst::FnSpace));
|
||||
assert!(generics.regions.is_empty_in(subst::FnSpace));
|
||||
|
||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(bounds.region_bound, contra);
|
||||
self.add_constraints_from_region(data.bounds.region_bound, contra);
|
||||
|
||||
self.add_constraints_from_substs(
|
||||
principal.def_id(),
|
||||
trait_ref.def_id(),
|
||||
generics.types.get_slice(subst::TypeSpace),
|
||||
generics.regions.get_slice(subst::TypeSpace),
|
||||
principal.substs(),
|
||||
trait_ref.substs(),
|
||||
variance);
|
||||
}
|
||||
|
||||
|
@ -1466,6 +1466,18 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
||||
}
|
||||
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
let trait_ref = match data.trait_ref.clean(cx) {
|
||||
TyParamBound::TraitBound(t) => t,
|
||||
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
|
||||
};
|
||||
Type::QPath {
|
||||
name: data.item_name.clean(cx),
|
||||
self_type: box data.trait_ref.self_ty().clean(cx),
|
||||
trait_: box trait_ref,
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_param(ref p) => {
|
||||
if p.space == subst::SelfSpace {
|
||||
Self(p.def_id)
|
||||
|
25
src/test/compile-fail/associated-types-for-unimpl-trait.rs
Normal file
25
src/test/compile-fail/associated-types-for-unimpl-trait.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Get {
|
||||
type Value;
|
||||
fn get(&self) -> <Self as Get>::Value;
|
||||
}
|
||||
|
||||
trait Other {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
//~^ ERROR the trait `Get` is not implemented for the type `Self`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -15,9 +15,6 @@ trait Get {
|
||||
fn get(&self) -> <Self as Get>::Value;
|
||||
}
|
||||
|
||||
fn get(x: int) -> <int as Get>::Value {}
|
||||
//~^ ERROR unsupported
|
||||
|
||||
struct Struct {
|
||||
x: int,
|
||||
}
|
||||
|
26
src/test/run-pass/associated-types-basic.rs
Normal file
26
src/test/run-pass/associated-types-basic.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Foo {
|
||||
type T;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
type T = int;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: <i32 as Foo>::T = 22;
|
||||
let y: int = 44;
|
||||
assert_eq!(x * 2, y);
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test equality constraints on associated types in a where clause.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
struct Bar;
|
||||
|
||||
impl Foo for int {
|
||||
type A = uint;
|
||||
fn boo(&self) -> uint { 42 }
|
||||
}
|
||||
|
||||
impl Foo for char {
|
||||
type A = Bar;
|
||||
fn boo(&self) -> Bar { Bar }
|
||||
}
|
||||
|
||||
fn foo_bar<I: Foo<A=Bar>>(x: I) -> Bar {
|
||||
x.boo()
|
||||
}
|
||||
|
||||
fn foo_uint<I: Foo<A=uint>>(x: I) -> uint {
|
||||
x.boo()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = 42i;
|
||||
foo_uint(a);
|
||||
|
||||
let a = 'a';
|
||||
foo_bar(a);
|
||||
}
|
42
src/test/run-pass/associated-types-constant-type.rs
Normal file
42
src/test/run-pass/associated-types-constant-type.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait SignedUnsigned {
|
||||
type Opposite;
|
||||
fn convert(self) -> Self::Opposite;
|
||||
}
|
||||
|
||||
impl SignedUnsigned for int {
|
||||
type Opposite = uint;
|
||||
|
||||
fn convert(self) -> uint {
|
||||
self as uint
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedUnsigned for uint {
|
||||
type Opposite = int;
|
||||
|
||||
fn convert(self) -> int {
|
||||
self as int
|
||||
}
|
||||
}
|
||||
|
||||
fn get(x: int) -> <int as SignedUnsigned>::Opposite {
|
||||
x.convert()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = get(22);
|
||||
assert_eq!(22u, x);
|
||||
}
|
||||
|
34
src/test/run-pass/associated-types-eq-obj.rs
Normal file
34
src/test/run-pass/associated-types-eq-obj.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test equality constraints on associated types inside of an object type
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for char {
|
||||
type A = Bar;
|
||||
fn boo(&self) -> Bar { Bar }
|
||||
}
|
||||
|
||||
fn baz(x: &Foo<A=Bar>) -> Bar {
|
||||
x.boo()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = 'a';
|
||||
baz(&a);
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test equality constraints on associated types.
|
||||
// Test equality constraints on associated types in a where clause.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
@ -17,16 +17,19 @@ pub trait Foo {
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
struct Bar;
|
||||
|
||||
impl Foo for int {
|
||||
type A = uint;
|
||||
fn boo(&self) -> uint { 42 }
|
||||
}
|
||||
|
||||
impl Foo for Bar {
|
||||
type A = int;
|
||||
fn boo(&self) -> int { 43 }
|
||||
}
|
||||
|
||||
impl Foo for char {
|
||||
type A = Bar;
|
||||
fn boo(&self) -> Bar { Bar }
|
||||
@ -35,12 +38,10 @@ impl Foo for char {
|
||||
fn foo1<I: Foo<A=Bar>>(x: I) -> Bar {
|
||||
x.boo()
|
||||
}
|
||||
|
||||
fn foo2<I: Foo>(x: I) -> <I as Foo>::A {
|
||||
x.boo()
|
||||
}
|
||||
fn baz(x: &Foo<A=Bar>) -> Bar {
|
||||
x.boo()
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = 42i;
|
||||
@ -51,5 +52,5 @@ pub fn main() {
|
||||
|
||||
let a = 'a';
|
||||
foo1(a);
|
||||
baz(&a);
|
||||
assert!(foo2(a) == Bar);
|
||||
}
|
Loading…
Reference in New Issue
Block a user