rollup merge of #21702: nikomatsakis/issue-21636

Check and extract bindings from trait definitions.

Fixes #21636.

r? @nick29581
This commit is contained in:
Alex Crichton 2015-01-30 12:02:56 -08:00
commit 103f1459c0
2 changed files with 84 additions and 0 deletions

View File

@ -430,6 +430,11 @@ fn project_type<'cx,'tcx>(
&obligation_trait_ref,
&mut candidates);
assemble_candidates_from_trait_def(selcx,
obligation,
&obligation_trait_ref,
&mut candidates);
if let Err(e) = assemble_candidates_from_impls(selcx,
obligation,
&obligation_trait_ref,
@ -474,6 +479,41 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
candidate_set, env_predicates);
}
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
/// that the definition of `Foo` has some clues:
///
/// ```rust
/// trait Foo {
/// type FooT : Bar<BarT=i32>
/// }
/// ```
///
/// Here, for example, we could conclude that the result is `i32`.
fn assemble_candidates_from_trait_def<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
{
// Check whether the self-type is itself a projection.
let trait_ref = match obligation_trait_ref.self_ty().sty {
ty::ty_projection(ref data) => data.trait_ref.clone(),
ty::ty_infer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
candidate_set.ambiguous = true;
return;
}
_ => { return; }
};
// If so, extract what we know from the trait and try to come up with a good answer.
let trait_def = ty::lookup_trait_def(selcx.tcx(), trait_ref.def_id);
let bounds = trait_def.generics.to_bounds(selcx.tcx(), trait_ref.substs);
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
candidate_set, bounds.predicates.into_vec());
}
fn assemble_candidates_from_predicates<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,

View File

@ -0,0 +1,44 @@
// Copyright 2015 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 a case where the associated type binding (to `bool`, in this
// case) is derived from the trait definition. Issue #21636.
use std::vec;
pub trait BitIter {
type Iter: Iterator<Item=bool>;
fn bit_iter(self) -> <Self as BitIter>::Iter;
}
impl BitIter for Vec<bool> {
type Iter = vec::IntoIter<bool>;
fn bit_iter(self) -> <Self as BitIter>::Iter {
self.into_iter()
}
}
fn count<T>(arg: T) -> usize
where T: BitIter
{
let mut sum = 0;
for i in arg.bit_iter() {
if i {
sum += 1;
}
}
sum
}
fn main() {
let v = vec![true, false, true];
let c = count(v);
assert_eq!(c, 2);
}