Teach project
to project associated types out of object types.
This commit is contained in:
parent
5b53b11ad9
commit
de806bc057
@ -19,7 +19,7 @@ use super::VtableImplData;
|
||||
|
||||
use middle::infer;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, ToPolyTraitRef, Ty};
|
||||
use middle::ty::{mod, AsPredicate, ToPolyTraitRef, Ty};
|
||||
use std::fmt;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
@ -46,7 +46,7 @@ pub enum ProjectionError<'tcx> {
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MismatchedProjectionTypes<'tcx> {
|
||||
pub err: ty::type_err<'tcx> // TODO expected/actual/etc
|
||||
pub err: ty::type_err<'tcx>
|
||||
}
|
||||
|
||||
pub type ProjectionResult<'tcx, T> = Result<T, ProjectionError<'tcx>>;
|
||||
@ -123,9 +123,20 @@ pub fn project_type<'cx,'tcx>(
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
let () = try!(assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates));
|
||||
let () = assemble_candidates_from_object_type(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
if candidates.vec.is_empty() {
|
||||
// TODO This `if` is not necessarily wrong, but it needs an
|
||||
// explanation, and it should probably be accompanied by a
|
||||
// similar rule in `select.rs`. Currently it's *needed*
|
||||
// because the impl-trait-for-trait branch has not landed.
|
||||
|
||||
let () = try!(assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates));
|
||||
}
|
||||
|
||||
debug!("{} candidates, ambiguous={}",
|
||||
candidates.vec.len(),
|
||||
@ -155,9 +166,21 @@ fn assemble_candidates_from_param_env<'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();
|
||||
assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates);
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_predicates<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
env_predicates: Vec<ty::Predicate<'tcx>>)
|
||||
{
|
||||
debug!("assemble_candidates_from_predicates(obligation={}, env_predicates={})",
|
||||
obligation.repr(selcx.tcx()),
|
||||
env_predicates.repr(selcx.tcx()));
|
||||
let infcx = selcx.infcx();
|
||||
for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
|
||||
match predicate {
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
@ -183,6 +206,26 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_object_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
let trait_ref = infcx.resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
|
||||
debug!("assemble_candidates_from_object_type(trait_ref={})",
|
||||
trait_ref.repr(infcx.tcx));
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let data = match self_ty.sty {
|
||||
ty::ty_trait(ref data) => data,
|
||||
_ => { return; }
|
||||
};
|
||||
let env_predicates = data.projection_bounds_with_self_ty(self_ty).iter()
|
||||
.map(|p| p.as_predicate())
|
||||
.collect();
|
||||
assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates)
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
|
@ -1401,6 +1401,31 @@ impl<'tcx> TyTrait<'tcx> {
|
||||
substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn projection_bounds_with_self_ty(&self, self_ty: Ty<'tcx>)
|
||||
-> Vec<ty::PolyProjectionPredicate<'tcx>>
|
||||
{
|
||||
// otherwise the escaping regions would be captured by the binders
|
||||
assert!(!self_ty.has_escaping_regions());
|
||||
|
||||
self.bounds.projection_bounds.iter()
|
||||
.map(|in_poly_projection_predicate| {
|
||||
let in_projection_ty = &in_poly_projection_predicate.0.projection_ty;
|
||||
let trait_ref =
|
||||
Rc::new(ty::TraitRef::new(
|
||||
in_projection_ty.trait_ref.def_id,
|
||||
in_projection_ty.trait_ref.substs.with_self_ty(self_ty)));
|
||||
let projection_ty = ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
item_name: in_projection_ty.item_name
|
||||
};
|
||||
ty::Binder(ty::ProjectionPredicate {
|
||||
projection_ty: projection_ty,
|
||||
ty: in_poly_projection_predicate.0.ty
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// A complete reference to a trait. These take numerous guises in syntax,
|
||||
|
@ -13,12 +13,12 @@ use middle::subst::{FnSpace, SelfSpace};
|
||||
use middle::traits;
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::report_fulfillment_errors;
|
||||
use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef};
|
||||
use middle::ty::{mod, Ty, AsPredicate};
|
||||
use middle::infer;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{Repr, ty_to_string};
|
||||
use util::nodemap::FnvHashSet;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
cast_expr: &ast::Expr,
|
||||
@ -133,10 +133,33 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait: &ty::TyTrait<'tcx>,
|
||||
span: Span)
|
||||
{
|
||||
// Also check that the type `object_trait` specifies all
|
||||
// associated types for all supertraits.
|
||||
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = FnvHashSet::new();
|
||||
|
||||
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) {
|
||||
for tr in traits::supertraits(tcx, object_trait_ref.clone()) {
|
||||
check_object_safety_inner(tcx, &tr, span);
|
||||
|
||||
let trait_def = ty::lookup_trait_def(tcx, object_trait_ref.def_id());
|
||||
for &associated_type_name in trait_def.associated_type_names.iter() {
|
||||
associated_types.insert((object_trait_ref.def_id(), associated_type_name));
|
||||
}
|
||||
}
|
||||
|
||||
for projection_bound in object_trait.bounds.projection_bounds.iter() {
|
||||
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
|
||||
projection_bound.0.projection_ty.item_name);
|
||||
associated_types.remove(&pair);
|
||||
}
|
||||
|
||||
for (trait_def_id, name) in associated_types.into_iter() {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
|
||||
name.user_string(tcx),
|
||||
ty::item_path_str(tcx, trait_def_id)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +224,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
Some(format!(
|
||||
"cannot call a method (`{}`) whose type contains \
|
||||
a self-type (`{}`) through a trait object",
|
||||
method_name, ty_to_string(tcx, ty)))
|
||||
method_name, ty.user_string(tcx)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -343,15 +366,15 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
referent_ty.repr(fcx.tcx()),
|
||||
object_trait_ty.repr(fcx.tcx()));
|
||||
|
||||
let cause = ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty));
|
||||
|
||||
// Create the obligation for casting from T to Trait.
|
||||
let object_trait_ref =
|
||||
object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
|
||||
let object_obligation =
|
||||
Obligation::new(
|
||||
ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty)),
|
||||
object_trait_ref.as_predicate());
|
||||
Obligation::new(cause.clone(), object_trait_ref.as_predicate());
|
||||
fcx.register_predicate(object_obligation);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
@ -362,7 +385,15 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
builtin_bound,
|
||||
ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty)));
|
||||
cause.clone());
|
||||
}
|
||||
|
||||
// Finally, create obligations for the projection predicates.
|
||||
let projection_bounds = object_trait.projection_bounds_with_self_ty(referent_ty);
|
||||
for projection_bound in projection_bounds.iter() {
|
||||
let projection_obligation =
|
||||
Obligation::new(cause.clone(), projection_bound.as_predicate());
|
||||
fcx.register_predicate(projection_obligation);
|
||||
}
|
||||
|
||||
object_trait_ref
|
||||
|
Loading…
Reference in New Issue
Block a user