]> git.lizzy.rs Git - rust.git/commitdiff
Make impl-trait-ref associated types work in methods
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Sat, 13 Jun 2015 23:27:18 +0000 (02:27 +0300)
committerAriel Ben-Yehuda <arielb1@mail.tau.ac.il>
Mon, 15 Jun 2015 15:27:35 +0000 (18:27 +0300)
src/librustc/middle/traits/project.rs
src/librustc_typeck/check/method/probe.rs
src/test/run-pass/associated-types-method.rs [new file with mode: 0644]
src/test/run-pass/issue-25679.rs

index 1631a33588ce2020455a389c78b193bb0a71c84b..4ef8f380e82487516018998dc3b46f17215946fa 100644 (file)
@@ -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
index 88c77e88b9bf2e1ecec7a5e377ae33e41af3faf9..915aadd722b2ce89ee4d86ac16c046354da98ffe 100644 (file)
@@ -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<traits::PredicateObligation<'tcx>>),
     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<traits::PredicateObligation<'tcx>>),
     ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
     WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
     ProjectionCandidate(ast::DefId, ItemIndex),
@@ -398,24 +400,24 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) {
         }
 
         let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
+        let impl_ty = impl_ty.subst(self.tcx(), &impl_substs);
 
-        // We can't use instantiate_type_scheme here as it will pollute
-        // the fcx's fulfillment context if this probe is rolled back.
+        // Determine the receiver type that the method itself expects.
+        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: impl_ty, .. } =
-            traits::normalize(selcx, cause, &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 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 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
                                    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 @@ fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
             // 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 @@ fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
                     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 @@ fn to_unadjusted_pick(&self) -> Pick<'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 @@ fn to_unadjusted_pick(&self) -> Pick<'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 @@ fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
             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 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
 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 (file)
index 0000000..b57687a
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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>(D, R);
+
+trait Tr {
+    fn present(&self) {}
+}
+
+impl<D: Device> Tr for Foo<D, D::Resources> {
+    fn present(&self) {}
+}
+
+struct Res;
+struct Dev;
+impl Device for Dev {
+    type Resources = Res;
+}
+
+fn main() {
+    let foo = Foo(Dev, Res);
+    foo.present();
+}
index 28e07158feebbf1a5ee00c495b29c9103c5d1f83..0ba7feece6061cde69696051489d75c703efec66 100644 (file)
@@ -13,7 +13,7 @@ trait Device {
 }
 struct Foo<D, R>(D, R);
 
-impl<D: Device, S> Foo<D, S> {
+impl<D: Device> Foo<D, D::Resources> {
     fn present(&self) {}
 }