summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala6
-rw-r--r--src/library/scala/Predef.scala9
-rw-r--r--test/files/neg/t0590.check5
5 files changed, 23 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index c23d29f159..0472f4fb21 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -420,7 +420,9 @@ self: Analyzer =>
*/
def tryImplicit(info: ImplicitInfo): SearchResult =
if (containsError(info.tpe) ||
- (isLocal && shadowed.contains(info.name)) // || (isView && (info.sym == Predef_identity || info.sym == Predef_conforms))
+ (isLocal && shadowed.contains(info.name)) //||
+ // (isView && (info.sym == Predef_identity || info.sym == Predef_conforms})) //@M this condition prevents no-op conversions, which are a problem (besides efficiency),
+ // one example is removeNames in NamesDefaults, which relies on the type checker failing in case of ambiguity between an assignment/named arg
) SearchFailure
else typedImplicit(info)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 482c53fac5..9d485cc730 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -390,9 +390,16 @@ trait NamesDefaults { self: Analyzer =>
argPos(index) = pos
rhs
case t: Tree =>
- errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+
+ //@M was: errorTree(arg, ...)
+ // this throws an exception that's caught in `tryTypedApply` (as it uses `silent`)
+ // unfortunately, tryTypedApply recovers from the exception if you use errorTree(arg, ...) and conforms is allowed as a view (see tryImplicit in Implicits)
+ // because it tries to produce a new qualifier (if the old one was P, the new one will be conforms.apply(P)), and if that works, it pretends nothing happened
+ // so, to make sure tryTypedApply fails, pass EmptyTree instead
+ errorTree(EmptyTree, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+
"name of the method and the name of a variable currently in scope.")
}
+ //@M note that we don't get here when an ambiguity was detected (during the computation of res),
+ // as errorTree throws an exception
typer.context.undetparams = udp
res
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 13a9d6e142..b609f1f24b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -992,8 +992,10 @@ trait Typers { self: Analyzer =>
((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue) &&
phase.id <= currentRun.typerPhase.id && !qtpe.isError && !tp.isError &&
qtpe.typeSymbol != NullClass && qtpe.typeSymbol != NothingClass && qtpe != WildcardType &&
- context.implicitsEnabled) { // don't try to convert a top-level type that's the subject of an implicit search
- // (otherwise we get divergence, e.g., starting at `conforms` during ant quick.bin)
+ context.implicitsEnabled) { // don't try to adapt a top-level type that's the subject of an implicit search
+ // this happens because, if isView, typedImplicit tries to apply the "current" implicit value to
+ // a value that needs to be coerced, so we check whether the implicit value has an `apply` method
+ // (if we allow this, we get divergence, e.g., starting at `conforms` during ant quick.bin)
// note: implicit arguments are still inferred (this kind of "chaining" is allowed)
val coercion = inferView(qual, qtpe, name, tp)
if (coercion != EmptyTree)
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 1dcffd342c..1345d9270f 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -76,6 +76,9 @@ object Predef {
val Map = collection.immutable.Map
val Set = collection.immutable.Set
+ // @see `conforms` for the implicit version
+ def identity[A](x: A): A = x
+
// errors and asserts -------------------------------------------------
def error(message: String): Nothing = throw new RuntimeException(message)
@@ -179,8 +182,6 @@ object Predef {
def readf3(format: String) = Console.readf3(format)
// views --------------------------------------------------------------
- implicit def identity[A](x: A): A = x
-
implicit def byteWrapper(x: Byte) = new runtime.RichByte(x)
implicit def shortWrapper(x: Short) = new runtime.RichShort(x)
implicit def intWrapper(x: Int) = new runtime.RichInt(x)
@@ -253,8 +254,8 @@ object Predef {
// reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred)
// to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters)
// simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`)
- // sealed abstract class <:<[-From, +To] extends (From => To)
- // implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
+ sealed abstract class <:<[-From, +To] extends (From => To)
+ implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
def currentThread = java.lang.Thread.currentThread()
}
diff --git a/test/files/neg/t0590.check b/test/files/neg/t0590.check
index b928c1cb76..a3ef70c6cd 100644
--- a/test/files/neg/t0590.check
+++ b/test/files/neg/t0590.check
@@ -1,5 +1,6 @@
-t0590.scala:2: error: diverging implicit expansion for type (Null(null)) => T
-starting with method foo in object Test
+t0590.scala:2: error: type mismatch;
+ found : Null(null)
+ required: T
implicit def foo[T] : T = null
^
one error found