From 093926e841df9a715f35d194846ad24134bafd2c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 27 Jan 2015 14:52:54 -0500 Subject: [PATCH] Check and extract bindings from trait definitions. Fixes #21636. --- src/librustc/middle/traits/project.rs | 40 +++++++++++++++++ .../associated-types-binding-in-trait.rs | 44 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/test/run-pass/associated-types-binding-in-trait.rs diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index ffb38091a87..f1513293726 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -401,6 +401,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, @@ -446,6 +451,41 @@ fn assemble_candidates_from_param_env<'cx,'tcx>( candidate_set, env_predicates); } +/// In the case of a nested projection like <::FooT as Bar>::BarT, we may find +/// that the definition of `Foo` has some clues: +/// +/// ```rust +/// trait Foo { +/// type FooT : Bar +/// } +/// ``` +/// +/// 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>, + 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>, diff --git a/src/test/run-pass/associated-types-binding-in-trait.rs b/src/test/run-pass/associated-types-binding-in-trait.rs new file mode 100644 index 00000000000..b47b0109bdf --- /dev/null +++ b/src/test/run-pass/associated-types-binding-in-trait.rs @@ -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 or the MIT license +// , 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; + fn bit_iter(self) -> ::Iter; +} + +impl BitIter for Vec { + type Iter = vec::IntoIter; + fn bit_iter(self) -> ::Iter { + self.into_iter() + } +} + +fn count(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); +}