diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 6 | ||||
-rw-r--r-- | src/library/scala/Predef.scala | 9 | ||||
-rw-r--r-- | test/files/neg/t0590.check | 5 |
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 |