diff options
author | Lukas Rytz <lukas.rytz@typesafe.com> | 2014-08-26 19:56:26 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@typesafe.com> | 2014-08-26 19:56:26 +0200 |
commit | b9048bb8a7d91e032eb57afa3ec12d3987980fe9 (patch) | |
tree | 56f24e877becd5ae9bd39825621f4f8db1da6116 | |
parent | eb741483c44290f0fcfb0c6abd99584d9fafe4b7 (diff) | |
parent | 756e551b30461b548ea59e99562634775b7ebd74 (diff) | |
download | scala-b9048bb8a7d91e032eb57afa3ec12d3987980fe9.tar.gz scala-b9048bb8a7d91e032eb57afa3ec12d3987980fe9.tar.bz2 scala-b9048bb8a7d91e032eb57afa3ec12d3987980fe9.zip |
Merge pull request #3905 from gourlaysama/wip/t5691-2
SI-5691 lint warning when a type parameter shadows an existing type.
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/Warnings.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala | 17 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 6 | ||||
-rw-r--r-- | test/files/neg/forgot-interpolator.scala | 4 | ||||
-rw-r--r-- | test/files/neg/t4851.check | 4 | ||||
-rw-r--r-- | test/files/neg/t4851/J2.java | 4 | ||||
-rw-r--r-- | test/files/neg/t5691.check | 24 | ||||
-rw-r--r-- | test/files/neg/t5691.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t5691.scala | 27 | ||||
-rw-r--r-- | test/files/neg/t6675b.scala | 2 |
10 files changed, 85 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index bec068b56a..4c37633301 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -38,6 +38,7 @@ trait Warnings { warnMissingInterpolator, warnDocDetached, warnPrivateShadow, + warnTypeParameterShadow, warnPolyImplicitOverload, warnOptionImplicit, warnDelayedInit, @@ -83,6 +84,8 @@ trait Warnings { "A ScalaDoc comment appears to be detached from its element.") val warnPrivateShadow = lintflag("private-shadow", "A private field (or class parameter) shadows a superclass field.") + val warnTypeParameterShadow = lintflag("type-parameter-shadow", + "A local type parameter shadows a type already in scope.") val warnPolyImplicitOverload = lintflag("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds") val warnOptionImplicit = lintflag("option-implicit", diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 89b064e7c1..8d29d28908 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -600,6 +600,23 @@ trait TypeDiagnostics { ) } + // warn about class/method/type-members' type parameters that shadow types already in scope + def warnTypeParameterShadow(tparams: List[TypeDef], sym: Symbol): Unit = + if (settings.warnTypeParameterShadow && !isPastTyper && !sym.isSynthetic) { + def enclClassOrMethodOrTypeMember(c: Context): Context = + if (!c.owner.exists || c.owner.isClass || c.owner.isMethod || (c.owner.isType && !c.owner.isParameter)) c + else enclClassOrMethodOrTypeMember(c.outer) + + val tt = tparams.filter(_.name != typeNames.WILDCARD).foreach { tp => + // we don't care about type params shadowing other type params in the same declaration + enclClassOrMethodOrTypeMember(context).outer.lookupSymbol(tp.name, s => s != tp.symbol && s.hasRawInfo && reallyExists(s)) match { + case LookupSucceeded(_, sym2) => context.warning(tp.pos, + s"type parameter ${tp.name} defined in $sym shadows $sym2 defined in ${sym2.owner}. You may want to rename your type parameter, or possibly remove it.") + case _ => + } + } + } + /** Report a type error. * * @param pos The position where to report the error diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 0621fbefe4..422b940cd3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1726,6 +1726,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper |you want, you must write the annotation class in Java.""".stripMargin) } + warnTypeParameterShadow(tparams1, clazz) + if (!isPastTyper) { for (ann <- clazz.getAnnotation(DeprecatedAttr)) { val m = companionSymbolOf(clazz, context) @@ -2128,6 +2130,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val tparams1 = ddef.tparams mapConserve typedTypeDef val vparamss1 = ddef.vparamss mapConserve (_ mapConserve typedValDef) + warnTypeParameterShadow(tparams1, meth) + meth.annotations.map(_.completeInfo()) for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1) @@ -2204,6 +2208,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val typedMods = typedModifiers(tdef.mods) tdef.symbol.annotations.map(_.completeInfo()) + warnTypeParameterShadow(tparams1, tdef.symbol) + // @specialized should not be pickled when compiling with -no-specialize if (settings.nospecialization && currentRun.compiles(tdef.symbol)) { tdef.symbol.removeAnnotation(definitions.SpecializedClass) diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala index a53054d890..ca1ac30821 100644 --- a/test/files/neg/forgot-interpolator.scala +++ b/test/files/neg/forgot-interpolator.scala @@ -54,8 +54,8 @@ package test { } } import annotation._ - @implicitNotFound("No Z in ${A}") // no warn - class Z[A] + @implicitNotFound("No Z in ${T}") // no warn + class Z[T] } diff --git a/test/files/neg/t4851.check b/test/files/neg/t4851.check index 132dd91b50..d5711a889b 100644 --- a/test/files/neg/t4851.check +++ b/test/files/neg/t4851.check @@ -29,13 +29,13 @@ S.scala:7: warning: Adapting argument list by creating a 3-tuple: this may not b val y2 = new Some(1, 2, 3) ^ S.scala:9: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. - signature: J2[T](x: T): J2[T] + signature: J2(x: T): J2[T] given arguments: <none> after adaptation: new J2((): Unit) val z1 = new J2 ^ S.scala:10: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. - signature: J2[T](x: T): J2[T] + signature: J2(x: T): J2[T] given arguments: <none> after adaptation: new J2((): Unit) val z2 = new J2() diff --git a/test/files/neg/t4851/J2.java b/test/files/neg/t4851/J2.java index 82954d9489..a90f48e269 100644 --- a/test/files/neg/t4851/J2.java +++ b/test/files/neg/t4851/J2.java @@ -1,11 +1,11 @@ public class J2<T> { T x; - public <T> J(T x) { + public J2(T x) { this.x = x; } public String toString() { return "J2:" + x.getClass(); } -}
\ No newline at end of file +} diff --git a/test/files/neg/t5691.check b/test/files/neg/t5691.check new file mode 100644 index 0000000000..a51ca98a10 --- /dev/null +++ b/test/files/neg/t5691.check @@ -0,0 +1,24 @@ +t5691.scala:7: warning: type parameter D defined in method foobar shadows trait D defined in class B. You may want to rename your type parameter, or possibly remove it. + def foobar[D](in: D) = in.toString + ^ +t5691.scala:10: warning: type parameter D defined in type MySeq shadows trait D defined in class B. You may want to rename your type parameter, or possibly remove it. + type MySeq[D] = Seq[D] + ^ +t5691.scala:15: warning: type parameter T defined in method bar shadows type T defined in class Foo. You may want to rename your type parameter, or possibly remove it. + def bar[T](w: T) = w.toString + ^ +t5691.scala:13: warning: type parameter T defined in class Foo shadows type T defined in class B. You may want to rename your type parameter, or possibly remove it. + class Foo[T](t: T) { + ^ +t5691.scala:19: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it. + class C[M[List[_]]] + ^ +t5691.scala:20: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it. + type E[M[List[_]]] = Int + ^ +t5691.scala:21: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it. + def foo[N[M[List[_]]]] = ??? + ^ +error: No warnings can be incurred under -Xfatal-warnings. +7 warnings found +one error found diff --git a/test/files/neg/t5691.flags b/test/files/neg/t5691.flags new file mode 100644 index 0000000000..0e09b8575b --- /dev/null +++ b/test/files/neg/t5691.flags @@ -0,0 +1 @@ +-Xlint:type-parameter-shadow -language:higherKinds -Xfatal-warnings diff --git a/test/files/neg/t5691.scala b/test/files/neg/t5691.scala new file mode 100644 index 0000000000..e6a9bdc16a --- /dev/null +++ b/test/files/neg/t5691.scala @@ -0,0 +1,27 @@ +class B { + + type T = Int + trait D + + // method parameter shadows some other type + def foobar[D](in: D) = in.toString + + // type member's parameter shadows some other type + type MySeq[D] = Seq[D] + + // class parameter shadows some other type + class Foo[T](t: T) { + // a type parameter shadows another type parameter + def bar[T](w: T) = w.toString + } + + // even deeply nested... + class C[M[List[_]]] + type E[M[List[_]]] = Int + def foo[N[M[List[_]]]] = ??? + + // ...but not between type parameters in the same list + class F[A, M[L[A]]] // no warning! + type G[A, M[L[A]]] = Int // no warning! + def bar[A, N[M[L[A]]]] = ??? // no warning! +} diff --git a/test/files/neg/t6675b.scala b/test/files/neg/t6675b.scala index c86c9c3955..da27e1b91f 100644 --- a/test/files/neg/t6675b.scala +++ b/test/files/neg/t6675b.scala @@ -13,7 +13,7 @@ object NativelyTwo { } -class A { +class E { def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight(a) => a } // warn def f2 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b)) => a } // no warn def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b, c)) => a } // fail |