]> git.lizzy.rs Git - rust.git/commitdiff
Work with assoc types in a super trait.
authorNick Cameron <ncameron@mozilla.com>
Tue, 7 Apr 2015 05:59:10 +0000 (17:59 +1200)
committerNick Cameron <ncameron@mozilla.com>
Tue, 7 Apr 2015 06:03:07 +0000 (18:03 +1200)
And fix a bug with type param visibility though the Self rib.

src/librustc_resolve/lib.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/collect.rs
src/test/compile-fail/self-impl.rs
src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
src/test/run-pass/self-impl.rs

index 002e5cc5e826d0861638cfd80b8adeefffefd45b..f90c7640f8ce70770ee64359177953bfcd04182c 100644 (file)
@@ -1815,12 +1815,12 @@ fn resolve_item(&mut self, item: &Item) {
             ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
                 self.check_if_primitive_type_name(name, item.span);
 
-                self.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| {
-                    // Create a new rib for the trait-wide type parameters.
-                    this.with_type_parameter_rib(HasTypeParameters(generics,
-                                                                   TypeSpace,
-                                                                   NormalRibKind),
-                                                 |this| {
+                // Create a new rib for the trait-wide type parameters.
+                self.with_type_parameter_rib(HasTypeParameters(generics,
+                                                               TypeSpace,
+                                                               ItemRibKind),
+                                             |this| {
+                    this.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| {
                         this.visit_generics(generics);
                         visit::walk_ty_param_bounds_helper(this, bounds);
 
index 1e7e27762f67c73a16af89338830ceb255274893..6617781ce2b0a0f4fb486499e2f1a58f28a615f3 100644 (file)
@@ -871,24 +871,11 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
         }
     }
 
-    if candidates.len() > 1 {
-        span_err!(tcx.sess, binding.span, E0217,
-            "ambiguous associated type: `{}` defined in multiple supertraits `{}`",
-                    token::get_name(binding.item_name),
-                    candidates.user_string(tcx));
-        return Err(ErrorReported);
-    }
-
-    let candidate = match candidates.pop() {
-        Some(c) => c,
-        None => {
-            span_err!(tcx.sess, binding.span, E0218,
-                "no associated type `{}` defined in `{}`",
-                        token::get_name(binding.item_name),
-                        trait_ref.user_string(tcx));
-            return Err(ErrorReported);
-        }
-    };
+    let candidate = try!(one_bound_for_assoc_type(tcx,
+                                                  candidates,
+                                                  &trait_ref.user_string(tcx),
+                                                  &token::get_name(binding.item_name),
+                                                  binding.span));
 
     Ok(ty::Binder(ty::ProjectionPredicate {             // <-------------------------+
         projection_ty: ty::ProjectionTy {               //                           |
@@ -1042,19 +1029,18 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt,
 }
 
 // Search for a bound on a type parameter which includes the associated item
-// given by assoc_name. We assume that ty_path_def is the def for such a type
-// parameter (which might be `Self`). This function will fail if there are no
-// suitable bounds or there is any ambiguity.
+// given by assoc_name. ty_param_node_id is the node id for the type parameter
+// (which might be `Self`, but only if it is the `Self` of a trait, not an
+// impl). This function will fail if there are no suitable bounds or there is
+// any ambiguity.
 fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>,
-                                   ty_path_def: def::Def,
+                                   ty_param_node_id: ast::NodeId,
                                    assoc_name: ast::Name,
                                    span: Span)
                                    -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
 {
     let tcx = this.tcx();
 
-    let ty_param_node_id = ty_path_def.local_node_id();
-
     let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
         Ok(v) => v,
         Err(ErrorReported) => {
@@ -1069,35 +1055,52 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>,
 
     // Check that there is exactly one way to find an associated type with the
     // correct name.
-    let mut suitable_bounds: Vec<_> =
+    let suitable_bounds: Vec<_> =
         traits::transitive_bounds(tcx, &bounds)
         .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
         .collect();
 
-    let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name;
-    if suitable_bounds.len() == 0 {
+    let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name;
+    one_bound_for_assoc_type(tcx,
+                             suitable_bounds,
+                             &token::get_name(ty_param_name),
+                             &token::get_name(assoc_name),
+                             span)
+}
+
+
+// Checks that bounds contains exactly one element and reports appropriate
+// errors otherwise.
+fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                  bounds: Vec<ty::PolyTraitRef<'tcx>>,
+                                  ty_param_name: &str,
+                                  assoc_name: &str,
+                                  span: Span)
+    -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+{
+    if bounds.len() == 0 {
         span_err!(tcx.sess, span, E0220,
-                          "associated type `{}` not found for type parameter `{}`",
-                                  token::get_name(assoc_name),
-                                  token::get_name(ty_param_name));
+                  "associated type `{}` not found for `{}`",
+                  assoc_name,
+                  ty_param_name);
         return Err(ErrorReported);
     }
 
-    if suitable_bounds.len() > 1 {
+    if bounds.len() > 1 {
         span_err!(tcx.sess, span, E0221,
-                          "ambiguous associated type `{}` in bounds of `{}`",
-                                  token::get_name(assoc_name),
-                                  token::get_name(ty_param_name));
+                  "ambiguous associated type `{}` in bounds of `{}`",
+                  assoc_name,
+                  ty_param_name);
 
-        for suitable_bound in &suitable_bounds {
+        for bound in &bounds {
             span_note!(tcx.sess, span,
                        "associated type `{}` could derive from `{}`",
-                       token::get_name(ty_param_name),
-                       suitable_bound.user_string(tcx));
+                       ty_param_name,
+                       bound.user_string(tcx));
         }
     }
 
-    Ok(suitable_bounds.pop().unwrap().clone())
+    Ok(bounds[0].clone())
 }
 
 // Create a type from a a path to an associated type.
@@ -1122,12 +1125,16 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     // Find the type of the associated item, and the trait where the associated
     // item is declared.
-    let (ty, trait_did) = match (&ty.sty, ty_path_def) {
+    let bound = match (&ty.sty, ty_path_def) {
         (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
             // `Self` in an impl of a trait - we have a concrete self type and a
             // trait reference.
             match tcx.map.expect_item(impl_id).node {
                 ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => {
+                    if this.ensure_super_predicates(span, trait_did).is_err() {
+                        return (tcx.types.err, ty_path_def);
+                    }
+
                     let trait_segment = &trait_ref.path.segments.last().unwrap();
                     let trait_ref = ast_path_to_mono_trait_ref(this,
                                                                &ExplicitRscope,
@@ -1137,8 +1144,20 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
                                                                Some(ty),
                                                                trait_segment);
 
-                    let ty = this.projected_ty(span, trait_ref, assoc_name);
-                    (ty, trait_did)
+                    let candidates: Vec<ty::PolyTraitRef> =
+                        traits::supertraits(tcx, ty::Binder(trait_ref.clone()))
+                        .filter(|r| this.trait_defines_associated_type_named(r.def_id(),
+                                                                             assoc_name))
+                        .collect();
+
+                    match one_bound_for_assoc_type(tcx,
+                                                   candidates,
+                                                   "Self",
+                                                   &token::get_name(assoc_name),
+                                                   span) {
+                        Ok(bound) => bound,
+                        Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+                    }
                 }
                 _ => unreachable!()
             }
@@ -1147,17 +1166,13 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => {
             // A type parameter or Self, we need to find the associated item from
             // a bound.
-            let bound = match find_bound_for_assoc_item(this, ty_path_def, assoc_name, span) {
+            let ty_param_node_id = ty_path_def.local_node_id();
+            match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) {
                 Ok(bound) => bound,
                 Err(ErrorReported) => return (tcx.types.err, ty_path_def),
-            };
-            let trait_did = bound.0.def_id;
-            let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
-
-            (ty, trait_did)
+            }
         }
         _ => {
-            println!("{:?} {:?}", ty.sty, ty_path_def);
             report_ambiguous_associated_type(tcx,
                                              span,
                                              &ty.user_string(tcx),
@@ -1167,6 +1182,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
     };
 
+    let trait_did = bound.0.def_id;
+    let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
+
     let item_did = if trait_did.krate == ast::LOCAL_CRATE {
         // `ty::trait_items` used below requires information generated
         // by type collection, which may be in progress at this point.
index f38ebf111fd3f683d5eed7662e88bd0e89cf968d..95b943b254785ff0725dcc8801664ed19d06a703 100644 (file)
@@ -1815,7 +1815,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                     ty::ty_param(p) => if p.idx > cur_idx {
                         span_err!(tcx.sess, path.span, E0128,
                                   "type parameters with a default cannot use \
-                                  forward declared identifiers");
+                                   forward declared identifiers");
                         },
                         _ => {}
                     }
index ec913aa844dbdbec925350dfec5055c722b23333..d058c6a5a3b93fbb6c6bf3f6d232d8e9fdc0806f 100644 (file)
@@ -16,10 +16,18 @@ trait Foo {
     type Baz;
 }
 
+trait SuperFoo {
+    type SuperBaz;
+}
+
 impl Foo for Bar {
     type Baz = bool;
 }
 
+impl SuperFoo for Bar {
+    type SuperBaz = bool;
+}
+
 impl Bar {
     fn f() {
         let _: <Self>::Baz = true;
index c9837da58e75a1d4a86801075a806d1c873199bf..bb7e02d0d8b9bebf5abc9c9c26f9811b7f18cd21 100644 (file)
@@ -12,7 +12,7 @@
 
 trait One<A> { fn foo(&self) -> A; }
 
-fn foo(_: &One()) //~ ERROR no associated type `Output` defined in `One<()>`
+fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>`
 {}
 
 fn main() { }
index 9f0682df3fe443c70b639a85a9515b06067ab5ed..20fdd52b82a3e257127e9d588a07a0767abfc51e 100644 (file)
@@ -14,7 +14,7 @@
 
 fn foo(_: &Three())
 //~^ ERROR wrong number of type arguments
-//~| ERROR no associated type `Output`
+//~| ERROR associated type `Output` not found
 {}
 
 fn main() { }
index 40635cf3ddda32ca7bd689f94c011bad1eaa42e3..027fa6b0fe3b0866a70d208681c06dd8422ba1f5 100644 (file)
@@ -14,7 +14,7 @@
 
 fn foo(_: Zero())
     //~^ ERROR wrong number of type arguments
-    //~| ERROR no associated type `Output` defined in `Zero`
+    //~| ERROR associated type `Output` not found for `Zero`
 {}
 
 fn main() { }
index e6e18d996b9e2e7adce47d19f41e49daa46c2204..04bbfc445edeaab920911845a249d8f4a30d7220 100644 (file)
@@ -14,6 +14,6 @@ trait Trait {}
 
 fn f<F:Trait(isize) -> isize>(x: F) {}
 //~^ ERROR wrong number of type arguments: expected 0, found 1
-//~| ERROR no associated type `Output`
+//~| ERROR associated type `Output` not found
 
 fn main() {}
index 746ddc9892abe59e12aa3a0b0555f2325323b300..688b66a0a87744553a75916813929b52775b879c 100644 (file)
@@ -40,19 +40,31 @@ pub struct Baz<X> {
     pub f: X,
 }
 
-trait Bar<X> {
+trait SuperBar {
+    type SuperQux;
+}
+
+trait Bar<X>: SuperBar {
     type Qux;
 
-    fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
+    fn bar(x: Self, y: &Self, z: Box<Self>, _: Self::SuperQux) -> Self;
     fn dummy(&self, x: X) { }
 }
 
+impl SuperBar for Box<Baz<isize>> {
+    type SuperQux = bool;
+}
+
 impl Bar<isize> for Box<Baz<isize>> {
     type Qux = i32;
 
-    fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
+    fn bar(_x: Self, _y: &Self, _z: Box<Self>, _: Self::SuperQux) -> Self {
         let _: Self::Qux = 42;
         let _: <Self as Bar<isize>>::Qux = 42;
+
+        let _: Self::SuperQux = true;
+        let _: <Self as SuperBar>::SuperQux = true;
+
         box Baz { f: 42 }
     }
 }
@@ -61,5 +73,6 @@ fn main() {
     let _: Foo = Foo::foo(Foo, &Foo, box Foo);
     let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
                                       &box Baz { f: 42 },
-                                      box box Baz { f: 42 });
+                                      box box Baz { f: 42 },
+                                      true);
 }