rollup merge of #20665: nikomatsakis/assoc-types-method-dispatch-projection
Conflicts: src/librustc/middle/ty.rs
This commit is contained in:
commit
51357e04be
@ -427,6 +427,16 @@ fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for Ty<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &Ty<'tcx>,
|
||||
b: &Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
{
|
||||
combiner.tys(*a, *b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &ty::ProjectionPredicate<'tcx>,
|
||||
|
@ -39,7 +39,7 @@
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
use self::coercion::Coerce;
|
||||
use self::combine::{Combine, CombineFields};
|
||||
use self::combine::{Combine, Combineable, CombineFields};
|
||||
use self::region_inference::{RegionVarBindings, RegionSnapshot};
|
||||
use self::equate::Equate;
|
||||
use self::sub::Sub;
|
||||
@ -360,17 +360,9 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
-> ures<'tcx> {
|
||||
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
|
||||
cx.probe(|_| {
|
||||
let trace = TypeTrace {
|
||||
origin: Misc(codemap::DUMMY_SP),
|
||||
values: Types(expected_found(true, a, b))
|
||||
};
|
||||
cx.equate(true, trace).tys(a, b)
|
||||
}).to_ures()
|
||||
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx>
|
||||
{
|
||||
cx.can_equate(&a, &b)
|
||||
}
|
||||
|
||||
pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||
@ -1072,6 +1064,23 @@ pub fn verify_generic_bound(&self,
|
||||
|
||||
self.region_vars.verify_generic_bound(origin, kind, a, bs);
|
||||
}
|
||||
|
||||
pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
|
||||
where T : Combineable<'tcx> + Repr<'tcx>
|
||||
{
|
||||
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
|
||||
self.probe(|_| {
|
||||
// Gin up a dummy trace, since this won't be committed
|
||||
// anyhow. We should make this typetrace stuff more
|
||||
// generic so we don't have to do anything quite this
|
||||
// terrible.
|
||||
let e = self.tcx.types.err;
|
||||
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
|
||||
values: Types(expected_found(true, e, e)) };
|
||||
let eq = self.equate(true, trace);
|
||||
Combineable::combine(&eq, a, b)
|
||||
}).to_ures()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeTrace<'tcx> {
|
||||
|
@ -394,7 +394,7 @@ pub fn as_slice(&self) -> &[T] {
|
||||
self.content.as_slice()
|
||||
}
|
||||
|
||||
pub fn to_vec(self) -> Vec<T> {
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
self.content
|
||||
}
|
||||
|
||||
|
@ -649,7 +649,7 @@ fn confirm_candidate<'cx,'tcx>(
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => (ty, impl_vtable.nested.to_vec()),
|
||||
Some(ty) => (ty, impl_vtable.nested.into_vec()),
|
||||
None => {
|
||||
// This means that the impl is missing a
|
||||
// definition for the associated type. This error
|
||||
|
@ -835,7 +835,7 @@ fn match_projection_obligation_against_bounds_from_trait(
|
||||
bounds.repr(self.tcx()));
|
||||
|
||||
let matching_bound =
|
||||
util::elaborate_predicates(self.tcx(), bounds.predicates.to_vec())
|
||||
util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec())
|
||||
.filter_to_traits()
|
||||
.find(
|
||||
|bound| self.infcx.probe(
|
||||
|
@ -1498,10 +1498,12 @@ pub fn def_id(&self) -> ast::DefId {
|
||||
}
|
||||
|
||||
pub fn substs(&self) -> &'tcx Substs<'tcx> {
|
||||
// FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
|
||||
self.0.substs
|
||||
}
|
||||
|
||||
pub fn input_types(&self) -> &[Ty<'tcx>] {
|
||||
// FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
|
||||
self.0.input_types()
|
||||
}
|
||||
|
||||
@ -6977,6 +6979,13 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionEscape for Substs<'tcx> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.types.has_regions_escaping_depth(depth) ||
|
||||
self.regions.has_regions_escaping_depth(depth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
|
||||
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
|
||||
self.iter_enumerated().any(|(space, _, t)| {
|
||||
|
@ -18,7 +18,7 @@
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::traits;
|
||||
use middle::ty::{self, Ty, ToPolyTraitRef};
|
||||
use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::infer;
|
||||
use middle::infer::InferCtxt;
|
||||
@ -62,6 +62,7 @@ enum CandidateKind<'tcx> {
|
||||
subst::Substs<'tcx>, MethodIndex),
|
||||
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
ProjectionCandidate(ast::DefId, MethodIndex),
|
||||
}
|
||||
|
||||
pub struct Pick<'tcx> {
|
||||
@ -309,18 +310,20 @@ fn assemble_inherent_candidates_from_object(&mut self,
|
||||
// argument type like `&Trait`.
|
||||
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 new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
|
||||
|
||||
let vtable_index =
|
||||
traits::get_vtable_index_of_object_method(tcx,
|
||||
trait_ref.clone(),
|
||||
new_trait_ref.def_id(),
|
||||
new_trait_ref.def_id,
|
||||
method_num);
|
||||
|
||||
let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs());
|
||||
let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs);
|
||||
|
||||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: m,
|
||||
kind: ObjectCandidate(new_trait_ref.def_id(), method_num, vtable_index)
|
||||
kind: ObjectCandidate(new_trait_ref.def_id, method_num, vtable_index)
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -353,34 +356,37 @@ fn assemble_inherent_candidates_from_param(&mut self,
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| {
|
||||
self.elaborate_bounds(bounds.as_slice(), true, |this, poly_trait_ref, m, method_num| {
|
||||
let trait_ref =
|
||||
this.erase_late_bound_regions(&poly_trait_ref);
|
||||
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&m, trait_ref.substs());
|
||||
this.xform_self_ty(&m, trait_ref.substs);
|
||||
|
||||
debug!("found match: trait_ref={} substs={} m={}",
|
||||
trait_ref.repr(this.tcx()),
|
||||
trait_ref.substs().repr(this.tcx()),
|
||||
trait_ref.substs.repr(this.tcx()),
|
||||
m.repr(this.tcx()));
|
||||
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs().types.get_slice(subst::TypeSpace).len());
|
||||
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs().regions().get_slice(subst::TypeSpace).len());
|
||||
trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs().types.get_slice(subst::SelfSpace).len());
|
||||
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs().regions().get_slice(subst::SelfSpace).len());
|
||||
trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
|
||||
|
||||
// Because this trait derives from a where-clause, it
|
||||
// should not contain any inference variables or other
|
||||
// artifacts. This means it is safe to put into the
|
||||
// `WhereClauseCandidate` and (eventually) into the
|
||||
// `WhereClausePick`.
|
||||
assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t)));
|
||||
assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t)));
|
||||
|
||||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: m,
|
||||
kind: WhereClauseCandidate(trait_ref, method_num)
|
||||
kind: WhereClauseCandidate(poly_trait_ref, method_num)
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -474,6 +480,10 @@ fn assemble_extension_candidates_for_trait(&mut self,
|
||||
method.clone(),
|
||||
matching_index);
|
||||
|
||||
self.assemble_projection_candidates(trait_def_id,
|
||||
method.clone(),
|
||||
matching_index);
|
||||
|
||||
self.assemble_where_clause_candidates(trait_def_id,
|
||||
method,
|
||||
matching_index);
|
||||
@ -603,6 +613,64 @@ fn assemble_unboxed_closure_candidates(&mut self,
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_projection_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method: Rc<ty::Method<'tcx>>,
|
||||
method_index: uint)
|
||||
{
|
||||
debug!("assemble_projection_candidates(\
|
||||
trait_def_id={}, \
|
||||
method={}, \
|
||||
method_index={})",
|
||||
trait_def_id.repr(self.tcx()),
|
||||
method.repr(self.tcx()),
|
||||
method_index);
|
||||
|
||||
for step in self.steps.iter() {
|
||||
debug!("assemble_projection_candidates: step={}",
|
||||
step.repr(self.tcx()));
|
||||
|
||||
let projection_trait_ref = match step.self_ty.sty {
|
||||
ty::ty_projection(ref data) => &data.trait_ref,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
debug!("assemble_projection_candidates: projection_trait_ref={}",
|
||||
projection_trait_ref.repr(self.tcx()));
|
||||
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id);
|
||||
let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs);
|
||||
let predicates = bounds.predicates.into_vec();
|
||||
debug!("assemble_projection_candidates: predicates={}",
|
||||
predicates.repr(self.tcx()));
|
||||
for poly_bound in
|
||||
traits::elaborate_predicates(self.tcx(), predicates)
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id)
|
||||
{
|
||||
let bound = self.erase_late_bound_regions(&poly_bound);
|
||||
|
||||
debug!("assemble_projection_candidates: projection_trait_ref={} bound={}",
|
||||
projection_trait_ref.repr(self.tcx()),
|
||||
bound.repr(self.tcx()));
|
||||
|
||||
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
|
||||
let xform_self_ty = self.xform_self_ty(&method, bound.substs);
|
||||
|
||||
debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
|
||||
bound.repr(self.tcx()),
|
||||
xform_self_ty.repr(self.tcx()));
|
||||
|
||||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method.clone(),
|
||||
kind: ProjectionCandidate(trait_def_id, method_index)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_where_clause_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method_ty: Rc<ty::Method<'tcx>>,
|
||||
@ -611,14 +679,14 @@ fn assemble_where_clause_candidates(&mut self,
|
||||
debug!("assemble_where_clause_candidates(trait_def_id={})",
|
||||
trait_def_id.repr(self.tcx()));
|
||||
|
||||
// Check whether there are any where-clauses pertaining to this trait.
|
||||
let caller_predicates =
|
||||
self.fcx.inh.param_env.caller_bounds.predicates.as_slice().to_vec();
|
||||
for bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id)
|
||||
for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id)
|
||||
{
|
||||
let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs());
|
||||
let bound = self.erase_late_bound_regions(&poly_bound);
|
||||
let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs);
|
||||
|
||||
debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}",
|
||||
bound.repr(self.tcx()),
|
||||
@ -627,7 +695,7 @@ fn assemble_where_clause_candidates(&mut self,
|
||||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method_ty.clone(),
|
||||
kind: WhereClauseCandidate(bound, method_index)
|
||||
kind: WhereClauseCandidate(poly_bound, method_index)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -829,6 +897,7 @@ fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
|
||||
norm_obligations.iter().all(|o| selcx.evaluate_obligation(o))
|
||||
}
|
||||
|
||||
ProjectionCandidate(..) |
|
||||
ObjectCandidate(..) |
|
||||
UnboxedClosureCandidate(..) |
|
||||
WhereClauseCandidate(..) => {
|
||||
@ -920,6 +989,8 @@ fn xform_self_ty(&self,
|
||||
method.fty.sig.0.inputs[0].repr(self.tcx()),
|
||||
substs.repr(self.tcx()));
|
||||
|
||||
assert!(!substs.has_escaping_regions());
|
||||
|
||||
// It is possible for type parameters or early-bound lifetimes
|
||||
// to appear in the signature of `self`. The substitutions we
|
||||
// are given do not include type/lifetime parameters for the
|
||||
@ -949,14 +1020,13 @@ fn xform_self_ty(&self,
|
||||
substs = &placeholder;
|
||||
}
|
||||
|
||||
// Replace early-bound regions and types.
|
||||
let xform_self_ty = method.fty.sig.0.inputs[0].subst(self.tcx(), substs);
|
||||
// Erase any late-bound regions from the method and substitute
|
||||
// in the values from the substitution.
|
||||
let xform_self_ty = method.fty.sig.input(0);
|
||||
let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty);
|
||||
let xform_self_ty = xform_self_ty.subst(self.tcx(), substs);
|
||||
|
||||
// Replace late-bound regions bound in the impl or
|
||||
// where-clause (2 levels of binding) and method (1 level of binding).
|
||||
self.erase_late_bound_regions(
|
||||
&self.erase_late_bound_regions(
|
||||
&ty::Binder(ty::Binder(xform_self_ty))))
|
||||
xform_self_ty
|
||||
}
|
||||
|
||||
fn impl_substs(&self,
|
||||
@ -1065,6 +1135,9 @@ fn to_unadjusted_pick(&self) -> Pick<'tcx> {
|
||||
|
||||
WhereClausePick((*trait_ref).clone(), index)
|
||||
}
|
||||
ProjectionCandidate(def_id, index) => {
|
||||
TraitPick(def_id, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1076,6 +1149,7 @@ fn to_source(&self) -> CandidateSource {
|
||||
ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id),
|
||||
UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
|
||||
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1094,6 +1168,9 @@ fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
|
||||
WhereClauseCandidate(ref trait_ref, method_num) => {
|
||||
Some((trait_ref.def_id(), method_num))
|
||||
}
|
||||
ProjectionCandidate(trait_def_id, method_num) => {
|
||||
Some((trait_def_id, method_num))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1120,6 +1197,8 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("UnboxedClosureCandidate({},{})", a.repr(tcx), b),
|
||||
WhereClauseCandidate(ref a, ref b) =>
|
||||
format!("WhereClauseCandidate({},{})", a.repr(tcx), b),
|
||||
ProjectionCandidate(ref a, ref b) =>
|
||||
format!("ProjectionCandidate({},{})", a.repr(tcx), b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
src/test/run-pass/method-projection.rs
Normal file
78
src/test/run-pass/method-projection.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// 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 that we can use method notation to call methods based on a
|
||||
// projection bound from a trait. Issue #20469.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
trait MakeString {
|
||||
fn make_string(&self) -> String;
|
||||
}
|
||||
|
||||
impl MakeString for int {
|
||||
fn make_string(&self) -> String {
|
||||
format!("{}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MakeString for uint {
|
||||
fn make_string(&self) -> String {
|
||||
format!("{}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
trait Foo {
|
||||
type F: MakeString;
|
||||
|
||||
fn get(&self) -> &Self::F;
|
||||
}
|
||||
|
||||
fn foo<F:Foo>(f: &F) -> String {
|
||||
f.get().make_string()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SomeStruct {
|
||||
field: int,
|
||||
}
|
||||
|
||||
impl Foo for SomeStruct {
|
||||
type F = int;
|
||||
|
||||
fn get(&self) -> &int {
|
||||
&self.field
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SomeOtherStruct {
|
||||
field: uint,
|
||||
}
|
||||
|
||||
impl Foo for SomeOtherStruct {
|
||||
type F = uint;
|
||||
|
||||
fn get(&self) -> &uint {
|
||||
&self.field
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = SomeStruct { field: 22 };
|
||||
assert_eq!(foo(&x), format!("22"));
|
||||
|
||||
let x = SomeOtherStruct { field: 44 };
|
||||
assert_eq!(foo(&x), format!("44"));
|
||||
}
|
Loading…
Reference in New Issue
Block a user