summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2009-08-21 08:57:51 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2009-08-21 08:57:51 +0000
commit69d4d8c0a34c94e72d69af1039c0a6131b97bb82 (patch)
treea9b6d4e6633ed2cd59dd33375d2c549136eeff95
parent832114b93349fa60b7c272c1c2189325bae49ca6 (diff)
downloadscala-69d4d8c0a34c94e72d69af1039c0a6131b97bb82.tar.gz
scala-69d4d8c0a34c94e72d69af1039c0a6131b97bb82.tar.bz2
scala-69d4d8c0a34c94e72d69af1039c0a6131b97bb82.zip
improved previous fix for implicits and `conforms`
because conforms/identity was no longer prevented from being used as a view (which does not make sense, but preventing it shouldn't be necessary), removeNames in NamesDefaults suddenly didn't detect all ambiguities because it relied on tryTypedApply failing fixed by using an EmptyTree as an ambiguous argument instead of the argument, so failure is guaranteed fixed check file for t0590 also reintroduced conforms, because we now have a new starr
-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