]> git.lizzy.rs Git - rust.git/commitdiff
Make supertrait references work in object types too.
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 5 Jan 2015 11:08:03 +0000 (06:08 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 5 Jan 2015 12:11:48 +0000 (07:11 -0500)
src/librustc_typeck/astconv.rs
src/test/run-pass/associated-type-doubleendediterator-object.rs [new file with mode: 0644]

index e216338b1e3a6f5f3e85cc22f6103b5b601a6e26..c616f4feaff02fa9946f7d4e05d539f4c56752bb 100644 (file)
@@ -627,7 +627,8 @@ fn ast_path_to_trait_ref<'a,'tcx>(
         }
         Some(ref mut v) => {
             for binding in assoc_bindings.iter() {
-                match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
+                match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
+                                                               self_ty, binding) {
                     Ok(pp) => { v.push(pp); }
                     Err(ErrorReported) => { }
                 }
@@ -640,10 +641,13 @@ fn ast_path_to_trait_ref<'a,'tcx>(
 
 fn ast_type_binding_to_projection_predicate<'tcx>(
     this: &AstConv<'tcx>,
-    trait_ref: Rc<ty::TraitRef<'tcx>>,
+    mut trait_ref: Rc<ty::TraitRef<'tcx>>,
+    self_ty: Option<Ty<'tcx>>,
     binding: &ConvertedBinding<'tcx>)
     -> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
 {
+    let tcx = this.tcx();
+
     // Given something like `U : SomeTrait<T=X>`, we want to produce a
     // predicate like `<U as SomeTrait>::T = X`. This is somewhat
     // subtle in the event that `T` is defined in a supertrait of
@@ -671,39 +675,67 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
         });
     }
 
-    // Otherwise, we have to walk through the supertraits to find those that do.
-    let mut candidates: Vec<_> =
-        traits::supertraits(this.tcx(), trait_ref.to_poly_trait_ref())
+    // Otherwise, we have to walk through the supertraits to find
+    // those that do.  This is complicated by the fact that, for an
+    // object type, the `Self` type is not present in the
+    // substitutions (after all, it's being constructed right now),
+    // but the `supertraits` iterator really wants one. To handle
+    // this, we currently insert a dummy type and then remove it
+    // later. Yuck.
+
+    let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+    if self_ty.is_none() { // if converting for an object type
+        let mut dummy_substs = trait_ref.substs.clone();
+        assert!(dummy_substs.self_ty().is_none());
+        dummy_substs.types.push(SelfSpace, dummy_self_ty);
+        trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
+                                              tcx.mk_substs(dummy_substs)));
+    }
+
+    let mut candidates: Vec<ty::PolyTraitRef> =
+        traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
         .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name))
         .collect();
 
+    // If converting for an object type, then remove the dummy-ty from `Self` now.
+    // Yuckety yuck.
+    if self_ty.is_none() {
+        for candidate in candidates.iter_mut() {
+            let mut dummy_substs = candidate.0.substs.clone();
+            assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
+            dummy_substs.types.pop(SelfSpace);
+            *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(),
+                                                              tcx.mk_substs(dummy_substs))));
+        }
+    }
+
     if candidates.len() > 1 {
-        this.tcx().sess.span_err(
+        tcx.sess.span_err(
             binding.span,
             format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`",
                     token::get_name(binding.item_name),
-                    candidates.user_string(this.tcx())).as_slice());
+                    candidates.user_string(tcx)).as_slice());
         return Err(ErrorReported);
     }
 
     let candidate = match candidates.pop() {
         Some(c) => c,
         None => {
-            this.tcx().sess.span_err(
+            tcx.sess.span_err(
                 binding.span,
                 format!("no associated type `{}` defined in `{}`",
                         token::get_name(binding.item_name),
-                        trait_ref.user_string(this.tcx())).as_slice());
+                        trait_ref.user_string(tcx)).as_slice());
             return Err(ErrorReported);
         }
     };
 
-    if ty::binds_late_bound_regions(this.tcx(), &candidate) {
-        this.tcx().sess.span_err(
+    if ty::binds_late_bound_regions(tcx, &candidate) {
+        tcx.sess.span_err(
             binding.span,
             format!("associated type `{}` defined in higher-ranked supertrait `{}`",
                     token::get_name(binding.item_name),
-                    candidate.user_string(this.tcx())).as_slice());
+                    candidate.user_string(tcx)).as_slice());
         return Err(ErrorReported);
     }
 
diff --git a/src/test/run-pass/associated-type-doubleendediterator-object.rs b/src/test/run-pass/associated-type-doubleendediterator-object.rs
new file mode 100644 (file)
index 0000000..429027c
--- /dev/null
@@ -0,0 +1,27 @@
+// 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 <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.
+
+fn pairwise_sub(mut t: Box<DoubleEndedIterator<Item=int>>) -> int {
+    let mut result = 0;
+    loop {
+        let front = t.next();
+        let back = t.next_back();
+        match (front, back) {
+            (Some(f), Some(b)) => { result += b - f; }
+            _ => { return result; }
+        }
+    }
+}
+
+fn main() {
+    let v = vec!(1, 2, 3, 4, 5, 6);
+    let r = pairwise_sub(box v.into_iter());
+    assert_eq!(r, 9);
+}