Skip to content

Commit 103f145

Browse files
committed
rollup merge of #21702: nikomatsakis/issue-21636
Check and extract bindings from trait definitions. Fixes #21636. r? @nick29581
2 parents 16120e9 + 093926e commit 103f145

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
@@ -430,6 +430,11 @@ fn project_type<'cx,'tcx>(
430430
&obligation_trait_ref,
431431
&mut candidates);
432432

433+
assemble_candidates_from_trait_def(selcx,
434+
obligation,
435+
&obligation_trait_ref,
436+
&mut candidates);
437+
433438
if let Err(e) = assemble_candidates_from_impls(selcx,
434439
obligation,
435440
&obligation_trait_ref,
@@ -474,6 +479,41 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
474479
candidate_set, env_predicates);
475480
}
476481

482+
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
483+
/// that the definition of `Foo` has some clues:
484+
///
485+
/// ```rust
486+
/// trait Foo {
487+
/// type FooT : Bar<BarT=i32>
488+
/// }
489+
/// ```
490+
///
491+
/// Here, for example, we could conclude that the result is `i32`.
492+
fn assemble_candidates_from_trait_def<'cx,'tcx>(
493+
selcx: &mut SelectionContext<'cx,'tcx>,
494+
obligation: &ProjectionTyObligation<'tcx>,
495+
obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
496+
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
497+
{
498+
// Check whether the self-type is itself a projection.
499+
let trait_ref = match obligation_trait_ref.self_ty().sty {
500+
ty::ty_projection(ref data) => data.trait_ref.clone(),
501+
ty::ty_infer(ty::TyVar(_)) => {
502+
// If the self-type is an inference variable, then it MAY wind up
503+
// being a projected type, so induce an ambiguity.
504+
candidate_set.ambiguous = true;
505+
return;
506+
}
507+
_ => { return; }
508+
};
509+
510+
// If so, extract what we know from the trait and try to come up with a good answer.
511+
let trait_def = ty::lookup_trait_def(selcx.tcx(), trait_ref.def_id);
512+
let bounds = trait_def.generics.to_bounds(selcx.tcx(), trait_ref.substs);
513+
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
514+
candidate_set, bounds.predicates.into_vec());
515+
}
516+
477517
fn assemble_candidates_from_predicates<'cx,'tcx>(
478518
selcx: &mut SelectionContext<'cx,'tcx>,
479519
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)