diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 98a826355a73a..b1dc033b567bb 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -22,7 +22,7 @@ use super::TupleArgumentsFlag; use super::write_call; use middle::infer; -use middle::ty::{mod, Ty}; +use middle::ty::{self, Ty}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index beb51590b4159..115711ae92b29 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -442,7 +442,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: ast::DefId) { - debug!("assemble_extension_candidates_for_trait: trait_def_id={}", + debug!("assemble_extension_candidates_for_trait(trait_def_id={})", trait_def_id.repr(self.tcx())); // Check whether `trait_def_id` defines a method with suitable name: @@ -471,8 +471,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { matching_index); self.assemble_unboxed_closure_candidates(trait_def_id, - method, + method.clone(), matching_index); + + self.assemble_where_clause_candidates(trait_def_id, + method, + matching_index); } fn assemble_extension_candidates_for_trait_impls(&mut self, @@ -599,6 +603,35 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } } + fn assemble_where_clause_candidates(&mut self, + trait_def_id: ast::DefId, + method_ty: Rc>, + method_index: uint) + { + debug!("assemble_where_clause_candidates(trait_def_id={})", + trait_def_id.repr(self.tcx())); + + // Check whether there are any where-clauses pertaining to this trait. + let caller_predicates = + self.fcx.inh.param_env.caller_bounds.predicates.as_slice().to_vec(); + for bound in traits::elaborate_predicates(self.tcx(), caller_predicates) + .filter_map(|p| p.to_opt_poly_trait_ref()) + .filter(|b| b.def_id() == trait_def_id) + { + let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs()); + + debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}", + bound.repr(self.tcx()), + xform_self_ty.repr(self.tcx())); + + self.extension_candidates.push(Candidate { + xform_self_ty: xform_self_ty, + method_ty: method_ty.clone(), + kind: WhereClauseCandidate(bound, method_index) + }); + } + } + /////////////////////////////////////////////////////////////////////////// // THE ACTUAL SEARCH @@ -774,26 +807,26 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { match probe.kind { InherentImplCandidate(impl_def_id, ref substs) | ExtensionImplCandidate(impl_def_id, _, ref substs, _) => { + let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx); + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + // Check whether the impl imposes obligations we have to worry about. let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let impl_bounds = impl_generics.to_bounds(self.tcx(), substs); - // FIXME(#20378) assoc type normalization here? - - // Erase any late-bound regions bound in the impl - // which appear in the bounds. - let impl_bounds = self.erase_late_bound_regions(&ty::Binder(impl_bounds)); + let traits::Normalized { value: impl_bounds, + obligations: norm_obligations } = + traits::normalize(selcx, cause.clone(), &impl_bounds); // Convert the bounds into obligations. let obligations = - traits::predicates_for_generics( - self.tcx(), - traits::ObligationCause::misc(self.span, self.fcx.body_id), - &impl_bounds); + traits::predicates_for_generics(self.tcx(), + cause.clone(), + &impl_bounds); debug!("impl_obligations={}", obligations.repr(self.tcx())); // Evaluate those obligations to see if they might possibly hold. - let mut selcx = traits::SelectionContext::new(self.infcx(), self.fcx); - obligations.all(|o| selcx.evaluate_obligation(o)) + obligations.all(|o| selcx.evaluate_obligation(o)) && + norm_obligations.iter().all(|o| selcx.evaluate_obligation(o)) } ObjectCandidate(..) | diff --git a/src/test/run-pass/method-normalize-bounds-issue-20604.rs b/src/test/run-pass/method-normalize-bounds-issue-20604.rs new file mode 100644 index 0000000000000..73489948da5de --- /dev/null +++ b/src/test/run-pass/method-normalize-bounds-issue-20604.rs @@ -0,0 +1,65 @@ +// 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 that we handle projection types which wind up important for +// resolving methods. This test was reduced from a larger example; the +// call to `foo()` at the end was failing to resolve because the +// winnowing stage of method resolution failed to handle an associated +// type projection. + +#![feature(associated_types)] + +trait Hasher { + type Output; + fn finish(&self) -> Self::Output; +} + +trait Hash { + fn hash(&self, h: &mut H); +} + +trait HashState { + type Wut: Hasher; + fn hasher(&self) -> Self::Wut; +} + +struct SipHasher; +impl Hasher for SipHasher { + type Output = u64; + fn finish(&self) -> u64 { 4 } +} + +impl Hash for int { + fn hash(&self, h: &mut SipHasher) {} +} + +struct SipState; +impl HashState for SipState { + type Wut = SipHasher; + fn hasher(&self) -> SipHasher { SipHasher } +} + +struct Map { + s: S, +} + +impl Map + where S: HashState, + ::Wut: Hasher, +{ + fn foo(&self, k: K) where K: Hash< ::Wut> {} +} + +fn foo>(map: &Map) { + map.foo(22); +} + +fn main() {} + diff --git a/src/test/run-pass/method-where-clause.rs b/src/test/run-pass/method-where-clause.rs new file mode 100644 index 0000000000000..4361c22f55a8a --- /dev/null +++ b/src/test/run-pass/method-where-clause.rs @@ -0,0 +1,42 @@ +// Copyright 2014 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 that we can use method notation to call methods based on a +// where clause type, and not only type parameters. + +trait Foo { + fn foo(&self) -> int; +} + +impl Foo for Option +{ + fn foo(&self) -> int { + self.unwrap_or(22) + } +} + +impl Foo for Option +{ + fn foo(&self) -> int { + self.unwrap_or(22) as int + } +} + +fn check(x: Option) -> (int, int) + where Option : Foo +{ + let y: Option = None; + (x.foo(), y.foo()) +} + +fn main() { + assert_eq!(check(Some(23u)), (23i, 22i)); + assert_eq!(check(Some(23i)), (23i, 22i)); +}