From 3ed7f067dc0319cd9e7bb6a8253ba031d0bdf1f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 14:01:31 -0500 Subject: [PATCH 1/4] Fix fallout in libs. For the most part I just tagged impls as `#[old_impl_check]`. --- src/libcollections/btree/node.rs | 3 ++- src/libcollections/lib.rs | 1 + src/librustc/lib.rs | 1 + src/librustc/util/ppaux.rs | 1 + src/libserialize/collection_impls.rs | 4 ++++ src/libserialize/lib.rs | 1 + src/libstd/collections/hash/map.rs | 10 ++++++++++ src/libstd/collections/hash/set.rs | 15 +++++++++++++++ src/libstd/io/mod.rs | 1 + src/libstd/lib.rs | 1 + src/libsyntax/ast.rs | 4 ++-- 11 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 0a93bbf89c997..1c646032bf15a 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -1417,7 +1417,7 @@ pub type MutTraversal<'a, K, V> = AbsTraversal = AbsTraversal>; - +#[old_impl_check] impl> Iterator for AbsTraversal { type Item = TraversalItem; @@ -1433,6 +1433,7 @@ impl> Iterator for AbsTraversal { } } +#[old_impl_check] impl> DoubleEndedIterator for AbsTraversal { fn next_back(&mut self) -> Option> { let tail_is_edge = self.tail_is_edge; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 5bf5f78af94c2..00d3e795f7432 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -26,6 +26,7 @@ #![feature(unsafe_destructor, slicing_syntax)] #![feature(unboxed_closures)] #![feature(old_orphan_check)] +#![feature(old_impl_check)] #![feature(associated_types)] #![no_std] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3ed712b15dfdc..d22e3208bbef7 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -28,6 +28,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(unboxed_closures)] #![feature(old_orphan_check)] +#![feature(old_impl_check)] #![feature(associated_types)] extern crate arena; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8c2a9993004d9..e5e425c9c2699 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1349,6 +1349,7 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder { } } +#[old_impl_check] impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap where K : Hash + Eq + Repr<'tcx>, V : Repr<'tcx>, diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 7ba329c518e91..d89a4754d2efe 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -156,6 +156,7 @@ impl< } } +#[old_impl_check] impl< K: Encodable + Hash + Eq, V: Encodable, @@ -175,6 +176,7 @@ impl< } } +#[old_impl_check] impl< K: Decodable + Hash + Eq, V: Decodable, @@ -195,6 +197,7 @@ impl< } } +#[old_impl_check] impl< T: Encodable + Hash + Eq, X, @@ -212,6 +215,7 @@ impl< } } +#[old_impl_check] impl< T: Decodable + Hash + Eq, S, diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 8fe15f00ded73..ee94095bd158f 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -26,6 +26,7 @@ Core encoding and decoding interfaces. #![feature(macro_rules, default_type_params, phase, slicing_syntax, globs)] #![feature(unboxed_closures)] #![feature(associated_types)] +#![feature(old_impl_check)] // test harness access #[cfg(test)] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a3fc38c34e84f..5372c51f95fff 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -439,6 +439,7 @@ impl SearchResult { } } +#[old_impl_check] impl, V, S, H: Hasher> HashMap { fn make_hash>(&self, x: &X) -> SafeHash { table::make_hash(&self.hasher, x) @@ -517,6 +518,7 @@ impl HashMap { } } +#[old_impl_check] impl, V, S, H: Hasher> HashMap { /// Creates an empty hashmap which will use the given hasher to hash keys. /// @@ -1191,6 +1193,7 @@ fn search_entry_hashed<'a, K, V, Q: ?Sized>(table: &'a mut RawTable, hash: } #[stable] +#[old_impl_check] impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap { fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } @@ -1202,9 +1205,11 @@ impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap, V: Eq, S, H: Hasher> Eq for HashMap {} #[stable] +#[old_impl_check] impl + Show, V: Show, S, H: Hasher> Show for HashMap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -1219,6 +1224,7 @@ impl + Show, V: Show, S, H: Hasher> Show for HashMap } #[stable] +#[old_impl_check] impl, V, S, H: Hasher + Default> Default for HashMap { #[stable] fn default() -> HashMap { @@ -1227,6 +1233,7 @@ impl, V, S, H: Hasher + Default> Default for HashMap } #[stable] +#[old_impl_check] impl + Eq, Q: ?Sized, V, S, H: Hasher> Index for HashMap where Q: BorrowFrom + Hash + Eq { @@ -1239,6 +1246,7 @@ impl + Eq, Q: ?Sized, V, S, H: Hasher> Index for HashMap + Eq, Q: ?Sized, V, S, H: Hasher> IndexMut for HashMap where Q: BorrowFrom + Hash + Eq { @@ -1472,6 +1480,7 @@ impl<'a, Q: ?Sized + 'a + ToOwned, K: 'a, V: 'a> VacantEntry<'a, Q, K, V> { } #[stable] +#[old_impl_check] impl, V, S, H: Hasher + Default> FromIterator<(K, V)> for HashMap { fn from_iter>(iter: T) -> HashMap { let lower = iter.size_hint().0; @@ -1482,6 +1491,7 @@ impl, V, S, H: Hasher + Default> FromIterator<(K, V)> for Has } #[stable] +#[old_impl_check] impl, V, S, H: Hasher> Extend<(K, V)> for HashMap { fn extend>(&mut self, mut iter: T) { for (k, v) in iter { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 211bfe2c10e8f..1b3d401fb8435 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -128,6 +128,7 @@ impl HashSet { } } +#[old_impl_check] impl, S, H: Hasher> HashSet { /// Creates a new empty hash set which will use the given hasher to hash /// keys. @@ -571,6 +572,7 @@ impl, S, H: Hasher> HashSet { } #[stable] +#[old_impl_check] impl, S, H: Hasher> PartialEq for HashSet { fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } @@ -580,9 +582,11 @@ impl, S, H: Hasher> PartialEq for HashSet { } #[stable] +#[old_impl_check] impl, S, H: Hasher> Eq for HashSet {} #[stable] +#[old_impl_check] impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -597,6 +601,7 @@ impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { } #[stable] +#[old_impl_check] impl, S, H: Hasher + Default> FromIterator for HashSet { fn from_iter>(iter: I) -> HashSet { let lower = iter.size_hint().0; @@ -607,6 +612,7 @@ impl, S, H: Hasher + Default> FromIterator for HashSet, S, H: Hasher> Extend for HashSet { fn extend>(&mut self, mut iter: I) { for k in iter { @@ -616,6 +622,7 @@ impl, S, H: Hasher> Extend for HashSet { } #[stable] +#[old_impl_check] impl, S, H: Hasher + Default> Default for HashSet { #[stable] fn default() -> HashSet { @@ -624,6 +631,7 @@ impl, S, H: Hasher + Default> Default for HashSet { } #[stable] +#[old_impl_check] impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> BitOr<&'b HashSet> for &'a HashSet { type Output = HashSet; @@ -654,6 +662,7 @@ BitOr<&'b HashSet> for &'a HashSet { } #[stable] +#[old_impl_check] impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> BitAnd<&'b HashSet> for &'a HashSet { type Output = HashSet; @@ -684,6 +693,7 @@ BitAnd<&'b HashSet> for &'a HashSet { } #[stable] +#[old_impl_check] impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> BitXor<&'b HashSet> for &'a HashSet { type Output = HashSet; @@ -714,6 +724,7 @@ BitXor<&'b HashSet> for &'a HashSet { } #[stable] +#[old_impl_check] impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> Sub<&'b HashSet> for &'a HashSet { type Output = HashSet; @@ -816,6 +827,7 @@ impl<'a, K: 'a> Iterator for Drain<'a, K> { } #[stable] +#[old_impl_check] impl<'a, T, S, H> Iterator for Intersection<'a, T, H> where T: Eq + Hash, H: Hasher { @@ -839,6 +851,7 @@ impl<'a, T, S, H> Iterator for Intersection<'a, T, H> } #[stable] +#[old_impl_check] impl<'a, T, S, H> Iterator for Difference<'a, T, H> where T: Eq + Hash, H: Hasher { @@ -862,6 +875,7 @@ impl<'a, T, S, H> Iterator for Difference<'a, T, H> } #[stable] +#[old_impl_check] impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> where T: Eq + Hash, H: Hasher { @@ -872,6 +886,7 @@ impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> } #[stable] +#[old_impl_check] impl<'a, T, S, H> Iterator for Union<'a, T, H> where T: Eq + Hash, H: Hasher { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 5bef473db990c..61ed387dd07eb 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1604,6 +1604,7 @@ pub struct IncomingConnections<'a, A: ?Sized +'a> { inc: &'a mut A, } +#[old_impl_check] impl<'a, T, A: ?Sized + Acceptor> Iterator for IncomingConnections<'a, A> { type Item = IoResult; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b9f226c5aca73..592163e0e8c6b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -108,6 +108,7 @@ #![feature(default_type_params, phase, lang_items, unsafe_destructor)] #![feature(slicing_syntax, unboxed_closures)] #![feature(old_orphan_check)] +#![feature(old_impl_check)] #![feature(associated_types)] // Don't link to std. We are std. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7aa7c4fcfb301..0054cb9509ac6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -982,8 +982,8 @@ pub enum Sign { Plus } -impl Sign where T: Int { - pub fn new(n: T) -> Sign { +impl Sign { + pub fn new(n: T) -> Sign { if n < Int::zero() { Minus } else { From 2375a79152b8a6554c3e97a3f127fedd75f7495f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 06:17:42 -0500 Subject: [PATCH 2/4] Implement impl reachability rules. This is a [breaking-change]. Type parameters on impls must now also appear in the trait ref, self type, or some associated type declared on the impl. This ensures that they are constrianed in some way and that the semantics of the trait system are well-defined (always a good thing). There are three major ways to fix this error: 1. Convert the trait to use associated types; most often the type parameters are not constrained because they are in fact outputs of the impl. 2. Move the type parameters to methods. 3. Add an additional type parameter to the self type or trait so that the unused parameter can appear there. In some cases, it is not possible to fix the impl because the trait definition needs to be changed first (and that may be out of your control). In that case, for the time being, you can opt out of these rules by using `#[old_impl_check]` on the impl and adding a `#![feature(old_impl_check)]` to your crate declaration. --- src/librustc/lint/builtin.rs | 1 + src/librustc_typeck/collect.rs | 100 ++++++++++++++++++++++++++++++++- src/libsyntax/feature_gate.rs | 10 ++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 425e34cd9f042..69da0f9a2109b 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -669,6 +669,7 @@ impl LintPass for UnusedAttributes { // FIXME: #19470 this shouldn't be needed forever "old_orphan_check", + "old_impl_check", ]; static CRATE_ATTRS: &'static [&'static str] = &[ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index bbafcdae1bba1..137f33d301d19 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -35,7 +35,7 @@ use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; use middle::subst; -use middle::subst::{Substs}; +use middle::subst::{Substs, TypeSpace}; use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{self, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; @@ -47,6 +47,7 @@ use util::ppaux; use util::ppaux::{Repr,UserString}; use write_ty_to_tcx; +use std::collections::HashSet; use std::rc::Rc; use syntax::abi; @@ -644,6 +645,10 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { Some(selfty), None); } + + enforce_impl_ty_params_are_constrained(ccx.tcx, + generics, + local_def(it.id)); }, ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); @@ -1605,3 +1610,96 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( }) } } + +/// Checks that all the type parameters on an impl +fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, + ast_generics: &ast::Generics, + impl_def_id: ast::DefId) +{ + let impl_scheme = ty::lookup_item_type(tcx, impl_def_id); + let impl_trait_ref = ty::impl_trait_ref(tcx, impl_def_id); + + // The trait reference is an input, so find all type parameters + // reachable from there, to start (if this is an inherent impl, + // then just examine the self type). + let mut input_parameters: HashSet<_> = + impl_trait_ref.iter() + .flat_map(|t| t.input_types().iter()) // Types in trait ref, if any + .chain(Some(impl_scheme.ty).iter()) // Self type, always + .flat_map(|t| t.walk()) + .filter_map(to_opt_param_ty) + .collect(); + + loop { + let num_inputs = input_parameters.len(); + + let mut projection_predicates = + impl_scheme.generics.predicates + .iter() + .filter_map(|predicate| { + match *predicate { + // Ignore higher-ranked binders. For the purposes + // of this check, they don't matter because they + // only affect named regions, and we're just + // concerned about type parameters here. + ty::Predicate::Projection(ref data) => Some(data.0.clone()), + _ => None, + } + }); + + for projection in projection_predicates { + // Special case: watch out for some kind of sneaky attempt + // to project out an associated type defined by this very trait. + if Some(projection.projection_ty.trait_ref.clone()) == impl_trait_ref { + continue; + } + + let relies_only_on_inputs = + projection.projection_ty.trait_ref.input_types().iter() + .flat_map(|t| t.walk()) + .filter_map(to_opt_param_ty) + .all(|t| input_parameters.contains(&t)); + + if relies_only_on_inputs { + input_parameters.extend( + projection.ty.walk().filter_map(to_opt_param_ty)); + } + } + + if input_parameters.len() == num_inputs { + break; + } + } + + for (index, ty_param) in ast_generics.ty_params.iter().enumerate() { + let param_ty = ty::ParamTy { space: TypeSpace, + idx: index as u32, + name: ty_param.ident.name }; + if !input_parameters.contains(¶m_ty) { + if ty::has_attr(tcx, impl_def_id, "old_impl_check") { + tcx.sess.span_warn( + ty_param.span, + format!("the type parameter `{}` is not constrained by the \ + impl trait, self type, or predicates", + param_ty.user_string(tcx)).as_slice()); + } else { + tcx.sess.span_err( + ty_param.span, + format!("the type parameter `{}` is not constrained by the \ + impl trait, self type, or predicates", + param_ty.user_string(tcx)).as_slice()); + tcx.sess.span_help( + ty_param.span, + format!("you can temporarily opt out of this rule by placing \ + the `#[old_impl_check]` attribute on the impl").as_slice()); + } + } + } + + fn to_opt_param_ty<'tcx>(ty: Ty<'tcx>) -> Option { + match ty.sty { + ty::ty_param(ref d) => Some(d.clone()), + _ => None, + } + } +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0810d4ee93ac7..8132c9fe78b67 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -86,6 +86,9 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ // A way to temporarily opt out of the new orphan rules. This will *never* be accepted. ("old_orphan_check", Deprecated), + // A way to temporarily opt out of the new impl rules. This will *never* be accepted. + ("old_impl_check", Deprecated), + // OIBIT specific features ("optin_builtin_traits", Active), @@ -294,6 +297,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { i.span, "the new orphan check rules will eventually be strictly enforced"); } + + if attr::contains_name(i.attrs[], + "old_impl_check") { + self.gate_feature("old_impl_check", + i.span, + "`#[old_impl_check]` will be removed in the future"); + } } _ => {} From d91323992c7597311d32867c89bc997a9f0c160d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 15:56:07 -0500 Subject: [PATCH 3/4] Fix fallout in tests. --- src/test/auxiliary/nested_item.rs | 8 ++++---- src/test/compile-fail/coherence-all-remote.rs | 4 ++-- src/test/compile-fail/issue-12028.rs | 19 ++++++++++--------- src/test/compile-fail/issue-13853-5.rs | 2 +- src/test/compile-fail/issue-16562.rs | 2 +- src/test/run-pass/issue-3743.rs | 12 +++++++++--- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/test/auxiliary/nested_item.rs b/src/test/auxiliary/nested_item.rs index 1a2f429c9ebc1..21784bda27a8f 100644 --- a/src/test/auxiliary/nested_item.rs +++ b/src/test/auxiliary/nested_item.rs @@ -18,8 +18,8 @@ pub fn foo() -> int { // issue 8134 struct Foo; -impl Foo { - pub fn foo(&self) { +impl Foo { + pub fn foo(&self) { static X: uint = 1; } } @@ -33,8 +33,8 @@ impl> Parser { } struct Bar; -impl Foo { - pub fn bar(&self) { +impl Foo { + pub fn bar(&self) { static X: uint = 1; } } diff --git a/src/test/compile-fail/coherence-all-remote.rs b/src/test/compile-fail/coherence-all-remote.rs index d88b8751ea7b0..d86256a77765e 100644 --- a/src/test/compile-fail/coherence-all-remote.rs +++ b/src/test/compile-fail/coherence-all-remote.rs @@ -11,9 +11,9 @@ // aux-build:coherence-lib.rs extern crate "coherence-lib" as lib; -use lib::Remote; +use lib::Remote1; -impl Remote for int { } +impl Remote1 for int { } //~^ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/issue-12028.rs b/src/test/compile-fail/issue-12028.rs index 78502efdec520..24ffc5e9ee373 100644 --- a/src/test/compile-fail/issue-12028.rs +++ b/src/test/compile-fail/issue-12028.rs @@ -22,27 +22,28 @@ trait Stream { fn result(&self) -> u64; } -trait StreamHasher { - fn stream(&self) -> S; +trait StreamHasher { + type S : Stream; + fn stream(&self) -> Self::S; } ////////////////////////////////////////////////////////////////////////////// -trait StreamHash>: Hash { - fn input_stream(&self, stream: &mut S); +trait StreamHash: Hash { + fn input_stream(&self, stream: &mut H::S); } -impl> Hash for u8 { +impl Hash for u8 { fn hash2(&self, hasher: &H) -> u64 { let mut stream = hasher.stream(); self.input_stream(&mut stream); //~ ERROR type annotations required - stream.result() + Stream::result(&stream) } } -impl> StreamHash for u8 { - fn input_stream(&self, stream: &mut S) { - stream.input(&[*self]); +impl StreamHash for u8 { + fn input_stream(&self, stream: &mut H::S) { + Stream::input(&*stream, &[*self]); } } diff --git a/src/test/compile-fail/issue-13853-5.rs b/src/test/compile-fail/issue-13853-5.rs index b3a4f341f8448..6a017f7bb30c1 100644 --- a/src/test/compile-fail/issue-13853-5.rs +++ b/src/test/compile-fail/issue-13853-5.rs @@ -15,7 +15,7 @@ trait Deserializable { } impl<'a, T: Deserializable> Deserializable for &'a str { - //~^ ERROR unable to infer enough type information + //~^ ERROR type parameter `T` is not constrained fn deserialize_token>(_x: D, _y: &'a str) -> &'a str { } } diff --git a/src/test/compile-fail/issue-16562.rs b/src/test/compile-fail/issue-16562.rs index 3c784c3b770e4..626a442a2c355 100644 --- a/src/test/compile-fail/issue-16562.rs +++ b/src/test/compile-fail/issue-16562.rs @@ -18,7 +18,7 @@ struct Col { trait Collection { fn len(&self) -> uint; } impl Collection for Col { -//~^ ERROR unable to infer enough type information +//~^ ERROR type parameter `T` is not constrained fn len(&self) -> uint { unimplemented!() } diff --git a/src/test/run-pass/issue-3743.rs b/src/test/run-pass/issue-3743.rs index 43852fb332400..382ea0c575887 100644 --- a/src/test/run-pass/issue-3743.rs +++ b/src/test/run-pass/issue-3743.rs @@ -30,17 +30,23 @@ impl Vec2 { } // Right-hand-side operator visitor pattern -trait RhsOfVec2Mul { fn mul_vec2_by(&self, lhs: &Vec2) -> Result; } +trait RhsOfVec2Mul { + type Result; + + fn mul_vec2_by(&self, lhs: &Vec2) -> Self::Result; +} // Vec2's implementation of Mul "from the other side" using the above trait -impl> Mul for Vec2 { +impl> Mul for Vec2 { type Output = Res; fn mul(self, rhs: Rhs) -> Res { rhs.mul_vec2_by(&self) } } // Implementation of 'f64 as right-hand-side of Vec2::Mul' -impl RhsOfVec2Mul for f64 { +impl RhsOfVec2Mul for f64 { + type Result = Vec2; + fn mul_vec2_by(&self, lhs: &Vec2) -> Vec2 { lhs.vmul(*self) } } From d31105e4f5e880e17f7607addae3573440a4c68a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 16:21:45 -0500 Subject: [PATCH 4/4] Add new tests covering various cases. --- .../compile-fail/impl-unused-tps-inherent.rs | 35 +++++++++ src/test/compile-fail/impl-unused-tps.rs | 72 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/test/compile-fail/impl-unused-tps-inherent.rs create mode 100644 src/test/compile-fail/impl-unused-tps.rs diff --git a/src/test/compile-fail/impl-unused-tps-inherent.rs b/src/test/compile-fail/impl-unused-tps-inherent.rs new file mode 100644 index 0000000000000..3803bb9b045ed --- /dev/null +++ b/src/test/compile-fail/impl-unused-tps-inherent.rs @@ -0,0 +1,35 @@ +// 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. + +struct MyType; + +struct MyType1(T); + +trait Bar { + type Out; +} + +impl MyType { + //~^ ERROR the type parameter `T` is not constrained +} + +impl MyType1 { + // OK, T is used in `Foo`. +} + +impl MyType1 { + //~^ ERROR the type parameter `U` is not constrained +} + +impl MyType1 where T: Bar { + // OK, T is used in `Foo`. +} + +fn main() { } diff --git a/src/test/compile-fail/impl-unused-tps.rs b/src/test/compile-fail/impl-unused-tps.rs new file mode 100644 index 0000000000000..99c6c6b89858c --- /dev/null +++ b/src/test/compile-fail/impl-unused-tps.rs @@ -0,0 +1,72 @@ +// 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. + +trait Foo { + fn get(&self, A: &A) { } +} + +trait Bar { + type Out; +} + +impl Foo for [int;0] { + // OK, T is used in `Foo`. +} + +impl Foo for [int;1] { + //~^ ERROR the type parameter `U` is not constrained +} + +impl Foo for [int;2] where T : Bar { + // OK, `U` is now constrained by the output type parameter. +} + +impl,U> Foo for [int;3] { + // OK, same as above but written differently. +} + +impl Foo for U { + // OK, T, U are used everywhere. Note that the coherence check + // hasn't executed yet, so no errors about overlap. +} + +impl Bar for T { + //~^ ERROR the type parameter `U` is not constrained + + type Out = U; + + // Using `U` in an associated type within the impl is not good enough! +} + +impl Bar for T + where T : Bar +{ + //~^^^ ERROR the type parameter `U` is not constrained + + // This crafty self-referential attempt is still no good. +} + +impl Foo for T + where (T,U): Bar +{ + //~^^^ ERROR the type parameter `U` is not constrained + //~| ERROR the type parameter `V` is not constrained + + // Here, `V` is bound by an output type parameter, but the inputs + // are not themselves constrained. +} + +impl Foo<(T,U)> for T + where (T,U): Bar +{ + // As above, but both T and U ARE constrained. +} + +fn main() { }