From 63b36ea7c211406a76c34cba5ac9b7218e003757 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 7 Apr 2015 17:59:10 +1200 Subject: [PATCH] Work with assoc types in a super trait. And fix a bug with type param visibility though the Self rib. --- src/librustc_resolve/lib.rs | 12 +- src/librustc_typeck/astconv.rs | 114 ++++++++++-------- src/librustc_typeck/collect.rs | 2 +- src/test/compile-fail/self-impl.rs | 8 ++ ...r-wrong-number-number-type-parameters-1.rs | 2 +- ...r-wrong-number-number-type-parameters-3.rs | 2 +- ...gar-wrong-number-number-type-parameters.rs | 2 +- .../unboxed-closure-sugar-wrong-trait.rs | 2 +- src/test/run-pass/self-impl.rs | 21 +++- 9 files changed, 102 insertions(+), 63 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 002e5cc5e82..f90c7640f8c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1815,12 +1815,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { 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); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1e7e27762f6..6617781ce2b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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, 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_param_name: &str, + assoc_name: &str, + span: Span) + -> Result, 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 = + 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. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f38ebf111fd..95b943b2547 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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"); }, _ => {} } diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs index ec913aa844d..d058c6a5a3b 100644 --- a/src/test/compile-fail/self-impl.rs +++ b/src/test/compile-fail/self-impl.rs @@ -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 _: ::Baz = true; diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index c9837da58e7..bb7e02d0d8b 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -12,7 +12,7 @@ trait One { 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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs index 9f0682df3fe..20fdd52b82a 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -14,7 +14,7 @@ trait Three { fn dummy(&self) -> (A,B,C); } fn foo(_: &Three()) //~^ ERROR wrong number of type arguments -//~| ERROR no associated type `Output` +//~| ERROR associated type `Output` not found {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index 40635cf3ddd..027fa6b0fe3 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -14,7 +14,7 @@ trait Zero { fn dummy(&self); } 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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index e6e18d996b9..04bbfc445ed 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -14,6 +14,6 @@ trait Trait {} fn f 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() {} diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs index 746ddc9892a..688b66a0a87 100644 --- a/src/test/run-pass/self-impl.rs +++ b/src/test/run-pass/self-impl.rs @@ -40,19 +40,31 @@ pub struct Baz { pub f: X, } -trait Bar { +trait SuperBar { + type SuperQux; +} + +trait Bar: SuperBar { type Qux; - fn bar(x: Self, y: &Self, z: Box) -> Self; + fn bar(x: Self, y: &Self, z: Box, _: Self::SuperQux) -> Self; fn dummy(&self, x: X) { } } +impl SuperBar for Box> { + type SuperQux = bool; +} + impl Bar for Box> { type Qux = i32; - fn bar(_x: Self, _y: &Self, _z: Box) -> Self { + fn bar(_x: Self, _y: &Self, _z: Box, _: Self::SuperQux) -> Self { let _: Self::Qux = 42; let _: >::Qux = 42; + + let _: Self::SuperQux = true; + let _: ::SuperQux = true; + box Baz { f: 42 } } } @@ -61,5 +73,6 @@ fn main() { let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Box> = Bar::bar(box Baz { f: 42 }, &box Baz { f: 42 }, - box box Baz { f: 42 }); + box box Baz { f: 42 }, + true); }