summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-10-30 18:42:56 +0100
committerJason Zaugg <jzaugg@gmail.com>2013-10-31 09:24:02 +0100
commit251c2b9313728bbac5e47ee096b65d1183624650 (patch)
treef8f45da7d1632e04604d80808decf6e6df601f12
parentc38235fd44f1ccb280e31a2f34f58deb59c5b2ee (diff)
downloadscala-251c2b9313728bbac5e47ee096b65d1183624650.tar.gz
scala-251c2b9313728bbac5e47ee096b65d1183624650.tar.bz2
scala-251c2b9313728bbac5e47ee096b65d1183624650.zip
SI-7944 FOUND: stray undetermined type params in vicinity of implicits
Implicit search created a nested Context into which the results of its typechecking, namely, errors and undetermined type parameters (roughly: those inferred as Nothing) are stashed. The code the drives the process was checking for errors, but discarded those undetermined type parameters. This commit copies them from the child context to the parent, which lets `Typer#adapt` to get to: else if (hasUndetsInMonoMode) { // (9) assert(!context.inTypeConstructorAllowed, context) //@M instantiatePossiblyExpectingUnit(tree, mode, pt) } Our lost TypeVar has found its way home! The reward for which is being instantiated, based on another type inference session adapting the expression's type to the expected type.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala6
-rw-r--r--test/files/pos/t7944.scala24
2 files changed, 29 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 987a3d2202..1e89e79cdd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -78,7 +78,11 @@ trait Implicits {
})
debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
}
- context.undetparams = context.undetparams filterNot result.subst.from.contains
+ // SI-7944 undetermined type parameters that result from inference within typedImplicit land in
+ // `implicitSearchContext.undetparams`, *not* in `context.undetparams`
+ // Here, we copy them up to parent context (analogously to the way the errors are copied above),
+ // and then filter out any which *were* inferred and are part of the substitutor in the implicit search result.
+ context.undetparams = ((context.undetparams ++ implicitSearchContext.undetparams) filterNot result.subst.from.contains).distinct
if (Statistics.canEnable) Statistics.stopTimer(implicitNanos, start)
if (Statistics.canEnable) Statistics.stopCounter(rawTypeImpl, rawTypeStart)
diff --git a/test/files/pos/t7944.scala b/test/files/pos/t7944.scala
new file mode 100644
index 0000000000..2fe2c5866d
--- /dev/null
+++ b/test/files/pos/t7944.scala
@@ -0,0 +1,24 @@
+class M[+A, +B]
+
+object Test {
+ implicit class EitherOps[A, B](self: Either[A, B]) {
+ def disjunction: M[A, B] = null
+ }
+
+ def foo = {
+ val l: Either[Int, Nothing] = Left[Int, Nothing](1)
+
+ var ok = EitherOps(l).disjunction
+
+ val runawayTypeVar = l.disjunction
+
+ // reported bug:
+ // found : M[Int,B]; required: M[Int,Nothing]
+ val assign: M[Int, Nothing] = runawayTypeVar
+
+ // variations on the theme, all failed before similarly.
+ val assign1: M[Int, Nothing] = {val temp = runawayTypeVar; temp}
+ val assign2: M[Int, String] = runawayTypeVar
+ val assign3: M[Int, Nothing] = {val temp = Left(1).disjunction; temp}
+ }
+}