Implement associated type projection and normalization.

This commit is contained in:
Niko Matsakis 2014-12-17 14:16:28 -05:00
parent f95bb55a1c
commit 4404592f36
61 changed files with 2478 additions and 1516 deletions

View File

@ -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;

View File

@ -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,
}
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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))
})),

View File

@ -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)

View File

@ -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)))
};

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -45,7 +45,9 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
let param_env = ty::empty_parameter_environment();
let mut selcx = SelectionContext::intercrate(infcx, &param_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 => {

View File

@ -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);
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -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()
}
}

View 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))
}
}
}

View File

@ -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) => {

View File

@ -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)
}
}

View File

@ -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, &param_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
}
}

View File

@ -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(_) |

View File

@ -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),
}
}
}

View File

@ -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);

View File

@ -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!");

View File

@ -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, &param_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,

View File

@ -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
}

View File

@ -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))[]);

View File

@ -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)

View File

@ -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));

View File

@ -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;

View File

@ -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, &param_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)
}
}
}
}

View File

@ -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"),
};

View File

@ -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");
}
}

View File

@ -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);

View 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)
}
}
}
}

View File

@ -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(..) => {
}
_ => { }
}
}

View File

@ -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 {

View File

@ -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),

View File

@ -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

View File

@ -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, &param_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 });

View File

@ -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);

View File

@ -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); }
}
}

View File

@ -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(..) |

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

@ -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)

View 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() {
}

View File

@ -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,
}

View 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);
}

View File

@ -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);
}

View 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);
}

View 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);
}

View File

@ -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);
}