diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index e37425901c8c8..24cafa7f7253a 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -25,7 +25,7 @@ use hir::def_id::DefId; use infer::{InferCtxt, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; -use traits::{self, Reveal, ObligationCause, Normalized}; +use traits::{self, Reveal, ObligationCause}; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; @@ -148,6 +148,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> bool { + debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id); + if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) { return r; } @@ -177,31 +179,24 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // create a parameter environment corresponding to a (skolemized) instantiation of impl1 - let mut penv = tcx.construct_parameter_environment(DUMMY_SP, - impl1_def_id, - region::DUMMY_CODE_EXTENT); + let penv = tcx.construct_parameter_environment(DUMMY_SP, + impl1_def_id, + region::DUMMY_CODE_EXTENT); let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id) .unwrap() .subst(tcx, &penv.free_substs); - let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| { - // Normalize the trait reference, adding any obligations - // that arise into the impl1 assumptions. - let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { - let selcx = &mut SelectionContext::new(&infcx); - traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref) - }; - penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| { - match tcx.lift_to_global(&o.predicate) { - Some(predicate) => predicate, - None => { - bug!("specializes: obligation `{:?}` has inference types/regions", o); + // Create a infcx, taking the predicates of impl1 as assumptions: + let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|infcx| { + // Normalize the trait reference. The WF rules ought to ensure + // that this always succeeds. + let impl1_trait_ref = + match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) { + Ok(impl1_trait_ref) => impl1_trait_ref, + Err(err) => { + bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); } - } - })); - - // Install the parameter environment, taking the predicates of impl1 as assumptions: - infcx.parameter_environment = penv; + }; // Attempt to prove that impl2 applies, given all of the above. fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() diff --git a/src/test/run-pass/issue-37291/auxiliary/lib.rs b/src/test/run-pass/issue-37291/auxiliary/lib.rs new file mode 100644 index 0000000000000..67cdea807beeb --- /dev/null +++ b/src/test/run-pass/issue-37291/auxiliary/lib.rs @@ -0,0 +1,52 @@ +// Copyright 2016 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. + +#![crate_type = "lib"] + +use std::ops::Mul; + +pub trait A {} +pub trait B { + type AT: A; +} +pub trait C { + type BT: B; +} + +pub struct AV; +impl A for AV {} + +pub struct BV; +impl B for BV { + type AT = AV; +} + +pub struct CV; +impl C for CV { + type BT = BV; +} + +pub struct WrapperB(pub T); +pub struct WrapperC(pub T); + +impl Mul::AT>> for WrapperC + where C1: C +{ + type Output = u8; + fn mul(self, _: WrapperB<::AT>) -> Self::Output { + loop {} + } +} +impl Mul> for WrapperC { + type Output = u8; + fn mul(self, _: WrapperC) -> Self::Output { + loop {} + } +} diff --git a/src/test/run-pass/issue-37291/main.rs b/src/test/run-pass/issue-37291/main.rs new file mode 100644 index 0000000000000..2461f7485f26f --- /dev/null +++ b/src/test/run-pass/issue-37291/main.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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. + +// aux-build:lib.rs + +// Regression test for #37291. The problem was that the starting +// environment for a specialization check was not including the +// where-clauses from the impl when attempting to normalize the impl's +// trait-ref, so things like `::Item` could not resolve, +// since the `C: Foo` trait bound was not included in the environment. + +extern crate lib; + +use lib::{CV, WrapperB, WrapperC}; + +fn main() { + let a = WrapperC(CV); + let b = WrapperC(CV); + if false { + let _ = a * b; + } +}