From e58f1bdc03b775e6d42f23f0cd181b47241bce41 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 21:17:59 -0500 Subject: [PATCH] Normalize predicates during method winnowing. Fixes #20604. Fixes #20378. --- src/librustc_typeck/check/method/probe.rs | 22 +++---- .../method-normalize-bounds-issue-20604.rs | 65 +++++++++++++++++++ 2 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/test/run-pass/method-normalize-bounds-issue-20604.rs diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 94e535cf2ef..115711ae92b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -807,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 00000000000..73489948da5 --- /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() {} +