Skip to content

Commit 279de38

Browse files
committed
Support methods invoked on projection types based on the bounds found in the trait.
1 parent fcc2323 commit 279de38

File tree

7 files changed

+185
-16
lines changed

7 files changed

+185
-16
lines changed

src/librustc/middle/infer/combine.rs

+10
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,16 @@ impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
427427
}
428428
}
429429

430+
impl<'tcx> Combineable<'tcx> for Ty<'tcx> {
431+
fn combine<C:Combine<'tcx>>(combiner: &C,
432+
a: &Ty<'tcx>,
433+
b: &Ty<'tcx>)
434+
-> cres<'tcx, Ty<'tcx>>
435+
{
436+
combiner.tys(*a, *b)
437+
}
438+
}
439+
430440
impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
431441
fn combine<C:Combine<'tcx>>(combiner: &C,
432442
a: &ty::ProjectionPredicate<'tcx>,

src/librustc/middle/infer/mod.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use util::ppaux::{ty_to_string};
3939
use util::ppaux::{Repr, UserString};
4040

4141
use self::coercion::Coerce;
42-
use self::combine::{Combine, CombineFields};
42+
use self::combine::{Combine, Combineable, CombineFields};
4343
use self::region_inference::{RegionVarBindings, RegionSnapshot};
4444
use self::equate::Equate;
4545
use self::sub::Sub;
@@ -360,17 +360,9 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
360360
})
361361
}
362362

363-
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
364-
a: Ty<'tcx>, b: Ty<'tcx>)
365-
-> ures<'tcx> {
366-
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
367-
cx.probe(|_| {
368-
let trace = TypeTrace {
369-
origin: Misc(codemap::DUMMY_SP),
370-
values: Types(expected_found(true, a, b))
371-
};
372-
cx.equate(true, trace).tys(a, b)
373-
}).to_ures()
363+
pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx>
364+
{
365+
cx.can_equate(&a, &b)
374366
}
375367

376368
pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
@@ -1072,6 +1064,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10721064

10731065
self.region_vars.verify_generic_bound(origin, kind, a, bs);
10741066
}
1067+
1068+
pub fn can_equate<T>(&self, a: &T, b: &T) -> ures<'tcx>
1069+
where T : Combineable<'tcx> + Repr<'tcx>
1070+
{
1071+
debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
1072+
self.probe(|_| {
1073+
// Gin up a dummy trace, since this won't be committed
1074+
// anyhow. We should make this typetrace stuff more
1075+
// generic so we don't have to do anything quite this
1076+
// terrible.
1077+
let e = self.tcx.types.err;
1078+
let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP),
1079+
values: Types(expected_found(true, e, e)) };
1080+
let eq = self.equate(true, trace);
1081+
Combineable::combine(&eq, a, b)
1082+
}).to_ures()
1083+
}
10751084
}
10761085

10771086
impl<'tcx> TypeTrace<'tcx> {

src/librustc/middle/subst.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ impl<T> VecPerParamSpace<T> {
394394
self.content.as_slice()
395395
}
396396

397-
pub fn to_vec(self) -> Vec<T> {
397+
pub fn into_vec(self) -> Vec<T> {
398398
self.content
399399
}
400400

src/librustc/middle/traits/project.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ fn confirm_candidate<'cx,'tcx>(
641641
}
642642

643643
match impl_ty {
644-
Some(ty) => (ty, impl_vtable.nested.to_vec()),
644+
Some(ty) => (ty, impl_vtable.nested.into_vec()),
645645
None => {
646646
// This means that the impl is missing a
647647
// definition for the associated type. This error

src/librustc/middle/traits/select.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
835835
bounds.repr(self.tcx()));
836836

837837
let matching_bound =
838-
util::elaborate_predicates(self.tcx(), bounds.predicates.to_vec())
838+
util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec())
839839
.filter_to_traits()
840840
.find(
841841
|bound| self.infcx.probe(

src/librustc_typeck/check/method/probe.rs

+73-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum CandidateKind<'tcx> {
6262
subst::Substs<'tcx>, MethodIndex),
6363
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
6464
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
65+
ProjectionCandidate(ast::DefId, MethodIndex),
6566
}
6667

6768
pub struct Pick<'tcx> {
@@ -479,6 +480,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
479480
method.clone(),
480481
matching_index);
481482

483+
self.assemble_projection_candidates(trait_def_id,
484+
method.clone(),
485+
matching_index);
486+
482487
self.assemble_where_clause_candidates(trait_def_id,
483488
method,
484489
matching_index);
@@ -608,6 +613,64 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
608613
}
609614
}
610615

616+
fn assemble_projection_candidates(&mut self,
617+
trait_def_id: ast::DefId,
618+
method: Rc<ty::Method<'tcx>>,
619+
method_index: uint)
620+
{
621+
debug!("assemble_projection_candidates(\
622+
trait_def_id={}, \
623+
method={}, \
624+
method_index={})",
625+
trait_def_id.repr(self.tcx()),
626+
method.repr(self.tcx()),
627+
method_index);
628+
629+
for step in self.steps.iter() {
630+
debug!("assemble_projection_candidates: step={}",
631+
step.repr(self.tcx()));
632+
633+
let projection_trait_ref = match step.self_ty.sty {
634+
ty::ty_projection(ref data) => &data.trait_ref,
635+
_ => continue,
636+
};
637+
638+
debug!("assemble_projection_candidates: projection_trait_ref={}",
639+
projection_trait_ref.repr(self.tcx()));
640+
641+
let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id);
642+
let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs);
643+
let predicates = bounds.predicates.into_vec();
644+
debug!("assemble_projection_candidates: predicates={}",
645+
predicates.repr(self.tcx()));
646+
for poly_bound in
647+
traits::elaborate_predicates(self.tcx(), predicates)
648+
.filter_map(|p| p.to_opt_poly_trait_ref()) // TODO filter_to_traits()
649+
.filter(|b| b.def_id() == trait_def_id)
650+
{
651+
let bound = self.erase_late_bound_regions(&poly_bound);
652+
653+
debug!("assemble_projection_candidates: projection_trait_ref={} bound={}",
654+
projection_trait_ref.repr(self.tcx()),
655+
bound.repr(self.tcx()));
656+
657+
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
658+
let xform_self_ty = self.xform_self_ty(&method, bound.substs);
659+
660+
debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
661+
bound.repr(self.tcx()),
662+
xform_self_ty.repr(self.tcx()));
663+
664+
self.extension_candidates.push(Candidate {
665+
xform_self_ty: xform_self_ty,
666+
method_ty: method.clone(),
667+
kind: ProjectionCandidate(trait_def_id, method_index)
668+
});
669+
}
670+
}
671+
}
672+
}
673+
611674
fn assemble_where_clause_candidates(&mut self,
612675
trait_def_id: ast::DefId,
613676
method_ty: Rc<ty::Method<'tcx>>,
@@ -616,7 +679,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
616679
debug!("assemble_where_clause_candidates(trait_def_id={})",
617680
trait_def_id.repr(self.tcx()));
618681

619-
// Check whether there are any where-clauses pertaining to this trait.
620682
let caller_predicates =
621683
self.fcx.inh.param_env.caller_bounds.predicates.as_slice().to_vec();
622684
for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
@@ -835,6 +897,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
835897
norm_obligations.iter().all(|o| selcx.evaluate_obligation(o))
836898
}
837899

900+
ProjectionCandidate(..) |
838901
ObjectCandidate(..) |
839902
UnboxedClosureCandidate(..) |
840903
WhereClauseCandidate(..) => {
@@ -1072,6 +1135,9 @@ impl<'tcx> Candidate<'tcx> {
10721135

10731136
WhereClausePick((*trait_ref).clone(), index)
10741137
}
1138+
ProjectionCandidate(def_id, index) => {
1139+
TraitPick(def_id, index)
1140+
}
10751141
}
10761142
}
10771143
}
@@ -1083,6 +1149,7 @@ impl<'tcx> Candidate<'tcx> {
10831149
ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id),
10841150
UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
10851151
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
1152+
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
10861153
}
10871154
}
10881155

@@ -1101,6 +1168,9 @@ impl<'tcx> Candidate<'tcx> {
11011168
WhereClauseCandidate(ref trait_ref, method_num) => {
11021169
Some((trait_ref.def_id(), method_num))
11031170
}
1171+
ProjectionCandidate(trait_def_id, method_num) => {
1172+
Some((trait_def_id, method_num))
1173+
}
11041174
}
11051175
}
11061176
}
@@ -1127,6 +1197,8 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
11271197
format!("UnboxedClosureCandidate({},{})", a.repr(tcx), b),
11281198
WhereClauseCandidate(ref a, ref b) =>
11291199
format!("WhereClauseCandidate({},{})", a.repr(tcx), b),
1200+
ProjectionCandidate(ref a, ref b) =>
1201+
format!("ProjectionCandidate({},{})", a.repr(tcx), b),
11301202
}
11311203
}
11321204
}
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we can use method notation to call methods based on a
12+
// projection bound from a trait. Issue #20469.
13+
14+
///////////////////////////////////////////////////////////////////////////
15+
16+
trait MakeString {
17+
fn make_string(&self) -> String;
18+
}
19+
20+
impl MakeString for int {
21+
fn make_string(&self) -> String {
22+
format!("{}", *self)
23+
}
24+
}
25+
26+
impl MakeString for uint {
27+
fn make_string(&self) -> String {
28+
format!("{}", *self)
29+
}
30+
}
31+
32+
///////////////////////////////////////////////////////////////////////////
33+
34+
trait Foo {
35+
type F: MakeString;
36+
37+
fn get(&self) -> &Self::F;
38+
}
39+
40+
fn foo<F:Foo>(f: &F) -> String {
41+
f.get().make_string()
42+
}
43+
44+
///////////////////////////////////////////////////////////////////////////
45+
46+
struct SomeStruct {
47+
field: int,
48+
}
49+
50+
impl Foo for SomeStruct {
51+
type F = int;
52+
53+
fn get(&self) -> &int {
54+
&self.field
55+
}
56+
}
57+
58+
///////////////////////////////////////////////////////////////////////////
59+
60+
struct SomeOtherStruct {
61+
field: uint,
62+
}
63+
64+
impl Foo for SomeOtherStruct {
65+
type F = uint;
66+
67+
fn get(&self) -> &uint {
68+
&self.field
69+
}
70+
}
71+
72+
fn main() {
73+
let x = SomeStruct { field: 22 };
74+
assert_eq!(foo(&x), format!("22"));
75+
76+
let x = SomeOtherStruct { field: 44 };
77+
assert_eq!(foo(&x), format!("44"));
78+
}

0 commit comments

Comments
 (0)