Skip to content

Commit 093926e

Browse files
committed
Check and extract bindings from trait definitions.
Fixes #21636.
1 parent 7774359 commit 093926e

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

src/librustc/middle/traits/project.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,11 @@ fn project_type<'cx,'tcx>(
401401
&obligation_trait_ref,
402402
&mut candidates);
403403

404+
assemble_candidates_from_trait_def(selcx,
405+
obligation,
406+
&obligation_trait_ref,
407+
&mut candidates);
408+
404409
if let Err(e) = assemble_candidates_from_impls(selcx,
405410
obligation,
406411
&obligation_trait_ref,
@@ -446,6 +451,41 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
446451
candidate_set, env_predicates);
447452
}
448453

454+
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
455+
/// that the definition of `Foo` has some clues:
456+
///
457+
/// ```rust
458+
/// trait Foo {
459+
/// type FooT : Bar<BarT=i32>
460+
/// }
461+
/// ```
462+
///
463+
/// Here, for example, we could conclude that the result is `i32`.
464+
fn assemble_candidates_from_trait_def<'cx,'tcx>(
465+
selcx: &mut SelectionContext<'cx,'tcx>,
466+
obligation: &ProjectionTyObligation<'tcx>,
467+
obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
468+
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
469+
{
470+
// Check whether the self-type is itself a projection.
471+
let trait_ref = match obligation_trait_ref.self_ty().sty {
472+
ty::ty_projection(ref data) => data.trait_ref.clone(),
473+
ty::ty_infer(ty::TyVar(_)) => {
474+
// If the self-type is an inference variable, then it MAY wind up
475+
// being a projected type, so induce an ambiguity.
476+
candidate_set.ambiguous = true;
477+
return;
478+
}
479+
_ => { return; }
480+
};
481+
482+
// If so, extract what we know from the trait and try to come up with a good answer.
483+
let trait_def = ty::lookup_trait_def(selcx.tcx(), trait_ref.def_id);
484+
let bounds = trait_def.generics.to_bounds(selcx.tcx(), trait_ref.substs);
485+
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
486+
candidate_set, bounds.predicates.into_vec());
487+
}
488+
449489
fn assemble_candidates_from_predicates<'cx,'tcx>(
450490
selcx: &mut SelectionContext<'cx,'tcx>,
451491
obligation: &ProjectionTyObligation<'tcx>,
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2015 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 a case where the associated type binding (to `bool`, in this
12+
// case) is derived from the trait definition. Issue #21636.
13+
14+
use std::vec;
15+
16+
pub trait BitIter {
17+
type Iter: Iterator<Item=bool>;
18+
fn bit_iter(self) -> <Self as BitIter>::Iter;
19+
}
20+
21+
impl BitIter for Vec<bool> {
22+
type Iter = vec::IntoIter<bool>;
23+
fn bit_iter(self) -> <Self as BitIter>::Iter {
24+
self.into_iter()
25+
}
26+
}
27+
28+
fn count<T>(arg: T) -> usize
29+
where T: BitIter
30+
{
31+
let mut sum = 0;
32+
for i in arg.bit_iter() {
33+
if i {
34+
sum += 1;
35+
}
36+
}
37+
sum
38+
}
39+
40+
fn main() {
41+
let v = vec![true, false, true];
42+
let c = count(v);
43+
assert_eq!(c, 2);
44+
}

0 commit comments

Comments
 (0)