diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 1631a33588c..4ef8f380e82 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -389,15 +389,19 @@ fn opt_normalize_projection_type<'a,'b,'tcx>( } } Ok(ProjectedTy::NoProgress(projected_ty)) => { + debug!("normalize_projection_type: projected_ty={} no progress", + projected_ty.repr(selcx.tcx())); Some(Normalized { value: projected_ty, obligations: vec!() }) } Err(ProjectionTyError::TooManyCandidates) => { + debug!("normalize_projection_type: too many candidates"); None } Err(ProjectionTyError::TraitSelectionError(_)) => { + debug!("normalize_projection_type: ERROR"); // if we got an error processing the `T as Trait` part, // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 88c77e88b9b..915aadd722b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -59,10 +59,12 @@ struct Candidate<'tcx> { } enum CandidateKind<'tcx> { - InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), + InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>, + /* Normalize obligations */ Vec>), ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize), ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>, - subst::Substs<'tcx>, ItemIndex), + subst::Substs<'tcx>, ItemIndex, + /* Normalize obligations */ Vec>), ClosureCandidate(/* Trait */ ast::DefId, ItemIndex), WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex), ProjectionCandidate(ast::DefId, ItemIndex), @@ -398,24 +400,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - - // We can't use instantiate_type_scheme here as it will pollute - // the fcx's fulfillment context if this probe is rolled back. - let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); - let traits::Normalized { value: impl_ty, .. } = - traits::normalize(selcx, cause, &impl_ty.subst(self.tcx(), &impl_substs)); + let impl_ty = impl_ty.subst(self.tcx(), &impl_substs); // Determine the receiver type that the method itself expects. - let xform_self_ty = - self.xform_self_ty(&item, impl_ty, &impl_substs); - debug!("assemble_inherent_impl_probe: self ty = {:?}", + let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs); + + // We can't use normalize_associated_types_in as it will pollute the + // fcx's fulfillment context after this probe is over. + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", xform_self_ty.repr(self.tcx())); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: InherentImplCandidate(impl_def_id, impl_substs) + kind: InherentImplCandidate(impl_def_id, impl_substs, obligations) }); } @@ -661,12 +663,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { impl_trait_ref.self_ty(), impl_trait_ref.substs); + // Normalize the receiver. We can't use normalize_associated_types_in + // as it will pollute the fcx's fulfillment context after this probe + // is over. + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx())); self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index) + kind: ExtensionImplCandidate(impl_def_id, + impl_trait_ref, + impl_substs, + item_index, + obligations) }); }); } @@ -1034,8 +1048,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(impl_def_id, ref substs) | - ExtensionImplCandidate(impl_def_id, _, ref substs, _) => { + InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) | + ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => { let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx); let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); @@ -1054,8 +1068,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("impl_obligations={}", obligations.repr(self.tcx())); // Evaluate those obligations to see if they might possibly hold. - obligations.iter().all(|o| selcx.evaluate_obligation(o)) && - norm_obligations.iter().all(|o| selcx.evaluate_obligation(o)) + obligations.iter() + .chain(norm_obligations.iter()).chain(ref_obligations.iter()) + .all(|o| selcx.evaluate_obligation(o)) + } ProjectionCandidate(..) | @@ -1289,13 +1305,13 @@ impl<'tcx> Candidate<'tcx> { Pick { item: self.item.clone(), kind: match self.kind { - InherentImplCandidate(def_id, _) => { + InherentImplCandidate(def_id, _, _) => { InherentImplPick(def_id) } ObjectCandidate(def_id, item_num, real_index) => { ObjectPick(def_id, item_num, real_index) } - ExtensionImplCandidate(def_id, _, _, index) => { + ExtensionImplCandidate(def_id, _, _, index, _) => { ExtensionImplPick(def_id, index) } ClosureCandidate(trait_def_id, index) => { @@ -1323,9 +1339,9 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(def_id, _) => ImplSource(def_id), + InherentImplCandidate(def_id, _, _) => ImplSource(def_id), ObjectCandidate(def_id, _, _) => TraitSource(def_id), - ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), + ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id), ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id), @@ -1343,7 +1359,7 @@ impl<'tcx> Candidate<'tcx> { ClosureCandidate(trait_def_id, item_num) => { Some((trait_def_id, item_num)) } - ExtensionImplCandidate(_, ref trait_ref, _, item_num) => { + ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => { Some((trait_ref.def_id, item_num)) } WhereClauseCandidate(ref trait_ref, item_num) => { @@ -1367,13 +1383,14 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> { impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { - InherentImplCandidate(ref a, ref b) => - format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)), + InherentImplCandidate(ref a, ref b, ref c) => + format!("InherentImplCandidate({},{},{})", a.repr(tcx), b.repr(tcx), + c.repr(tcx)), ObjectCandidate(a, b, c) => format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c), - ExtensionImplCandidate(ref a, ref b, ref c, ref d) => - format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx), - c.repr(tcx), d), + ExtensionImplCandidate(ref a, ref b, ref c, ref d, ref e) => + format!("ExtensionImplCandidate({},{},{},{},{})", a.repr(tcx), b.repr(tcx), + c.repr(tcx), d, e.repr(tcx)), ClosureCandidate(ref a, ref b) => format!("ClosureCandidate({},{})", a.repr(tcx), b), WhereClauseCandidate(ref a, ref b) => diff --git a/src/test/run-pass/associated-types-method.rs b/src/test/run-pass/associated-types-method.rs new file mode 100644 index 00000000000..b57687a49fa --- /dev/null +++ b/src/test/run-pass/associated-types-method.rs @@ -0,0 +1,36 @@ +// 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 methods whose impl-trait-ref contains associated types +// are supported. + +trait Device { + type Resources; +} +struct Foo(D, R); + +trait Tr { + fn present(&self) {} +} + +impl Tr for Foo { + fn present(&self) {} +} + +struct Res; +struct Dev; +impl Device for Dev { + type Resources = Res; +} + +fn main() { + let foo = Foo(Dev, Res); + foo.present(); +} diff --git a/src/test/run-pass/issue-25679.rs b/src/test/run-pass/issue-25679.rs index 28e07158fee..0ba7feece60 100644 --- a/src/test/run-pass/issue-25679.rs +++ b/src/test/run-pass/issue-25679.rs @@ -13,7 +13,7 @@ trait Device { } struct Foo(D, R); -impl Foo { +impl Foo { fn present(&self) {} }