summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala20
-rw-r--r--test/files/run/t5923a.check3
-rw-r--r--test/files/run/t5923a/Macros_1.scala14
-rw-r--r--test/files/run/t5923a/Test_2.scala5
-rw-r--r--test/files/run/t5923b.check3
-rw-r--r--test/files/run/t5923b/Test.scala7
7 files changed, 67 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index d07297bb35..ecae55562b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -394,7 +394,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
case Fallback(fallback) =>
typer.typed1(fallback, EXPRmode, WildcardType)
case Delayed(delayed) =>
- delayed
+ typer.instantiate(delayed, EXPRmode, WildcardType)
case Skipped(skipped) =>
skipped
case Failure(failure) =>
@@ -778,6 +778,29 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
expanded2
}
}
+ override def onDelayed(delayed: Tree) = {
+ // If we've been delayed (i.e. bailed out of the expansion because of undetermined type params present in the expandee),
+ // then there are two possible situations we're in:
+ // 1) We're in POLYmode, when the typer tests the waters wrt type inference
+ // (e.g. as in typedArgToPoly in doTypedApply).
+ // 2) We're out of POLYmode, which means that the typer is out of tricks to infer our type
+ // (e.g. if we're an argument to a function call, then this means that no previous argument lists
+ // can determine our type variables for us).
+ //
+ // Situation #1 is okay for us, since there's no pressure. In POLYmode we're just verifying that
+ // there's nothing outrageously wrong with our undetermined type params (from what I understand!).
+ //
+ // Situation #2 requires measures to be taken. If we're in it, then noone's going to help us infer
+ // the undetermined type params. Therefore we need to do something ourselves or otherwise this
+ // expandee will forever remaing not expanded (see SI-5692). A traditional way out of this conundrum
+ // is to call `instantiate` and let the inferencer try to find the way out. It works for simple cases,
+ // but sometimes, if the inferencer lacks information, it will be forced to approximate. This prevents
+ // an important class of macros, fundep materializers, from working, which I perceive is a problem we need to solve.
+ // For details see SI-7470.
+ val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
+ if (shouldInstantiate) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
+ else delayed
+ }
}
expander(expandee)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 001808e6bc..2de59056ef 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1091,7 +1091,6 @@ trait Typers extends Adaptations with Tags {
instantiateToMethodType(mt)
case _ =>
- def vanillaAdapt(tree: Tree) = {
def shouldInsertApply(tree: Tree) = mode.inAll(EXPRmode | FUNmode) && (tree.tpe match {
case _: MethodType | _: OverloadedType | _: PolyType => false
case _ => applyPossible
@@ -1107,16 +1106,15 @@ trait Typers extends Adaptations with Tags {
}
if (tree.isType)
adaptType()
+ else if (mode.inExprModeButNot(FUNmode) && treeInfo.isMacroApplication(tree))
+ macroExpandApply(this, tree, mode, pt)
else if (mode.inAll(PATTERNmode | FUNmode))
adaptConstrPattern()
else if (shouldInsertApply(tree))
insertApply()
- else if (!context.undetparams.isEmpty && !mode.inPolyMode) { // (9)
+ else if (context.undetparams.nonEmpty && !mode.inPolyMode) { // (9)
assert(!mode.inHKMode, mode) //@M
- if (mode.inExprModeButNot(FUNmode) && pt.typeSymbol == UnitClass)
- instantiateExpectingUnit(tree, mode)
- else
- instantiate(tree, mode, pt)
+ instantiatePossiblyExpectingUnit(tree, mode, pt)
} else if (tree.tpe <:< pt) {
tree
} else {
@@ -1242,9 +1240,6 @@ trait Typers extends Adaptations with Tags {
fallBack
}
}
- val tree1 = if (mode.inExprModeButNot(FUNmode) && treeInfo.isMacroApplication(tree)) macroExpandApply(this, tree, mode, pt) else tree
- if (tree == tree1) vanillaAdapt(tree1) else tree1
- }
}
def instantiate(tree: Tree, mode: Mode, pt: Type): Tree = {
@@ -1264,6 +1259,13 @@ trait Typers extends Adaptations with Tags {
}
}
+ def instantiatePossiblyExpectingUnit(tree: Tree, mode: Mode, pt: Type): Tree = {
+ if (mode.inExprModeButNot(FUNmode) && pt.typeSymbol == UnitClass)
+ instantiateExpectingUnit(tree, mode)
+ else
+ instantiate(tree, mode, pt)
+ }
+
private def isAdaptableWithView(qual: Tree) = {
val qtpe = qual.tpe.widen
( !isPastTyper
diff --git a/test/files/run/t5923a.check b/test/files/run/t5923a.check
new file mode 100644
index 0000000000..7165b734ac
--- /dev/null
+++ b/test/files/run/t5923a.check
@@ -0,0 +1,3 @@
+C(Int)
+C(String)
+C(Nothing)
diff --git a/test/files/run/t5923a/Macros_1.scala b/test/files/run/t5923a/Macros_1.scala
new file mode 100644
index 0000000000..6d21362c4d
--- /dev/null
+++ b/test/files/run/t5923a/Macros_1.scala
@@ -0,0 +1,14 @@
+import scala.reflect.macros.Context
+import language.experimental.macros
+
+case class C[T](t: String)
+object C {
+ implicit def foo[T]: C[T] = macro Macros.impl[T]
+}
+
+object Macros {
+ def impl[T: c.WeakTypeTag](c: Context) = {
+ import c.universe._
+ reify(C[T](c.literal(weakTypeOf[T].toString).splice))
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t5923a/Test_2.scala b/test/files/run/t5923a/Test_2.scala
new file mode 100644
index 0000000000..001ff9aea8
--- /dev/null
+++ b/test/files/run/t5923a/Test_2.scala
@@ -0,0 +1,5 @@
+object Test extends App {
+ println(implicitly[C[Int]])
+ println(implicitly[C[String]])
+ println(implicitly[C[Nothing]])
+} \ No newline at end of file
diff --git a/test/files/run/t5923b.check b/test/files/run/t5923b.check
new file mode 100644
index 0000000000..d56076f84e
--- /dev/null
+++ b/test/files/run/t5923b.check
@@ -0,0 +1,3 @@
+class [Ljava.lang.Object;
+class [Ljava.lang.Object;
+class [Ljava.lang.Object;
diff --git a/test/files/run/t5923b/Test.scala b/test/files/run/t5923b/Test.scala
new file mode 100644
index 0000000000..7c2627462a
--- /dev/null
+++ b/test/files/run/t5923b/Test.scala
@@ -0,0 +1,7 @@
+object Test extends App {
+ import scala.collection.generic.CanBuildFrom
+ val cbf = implicitly[CanBuildFrom[Nothing, Nothing, Array[Nothing]]]
+ println(cbf().result.getClass)
+ println(new Array[Nothing](0).getClass)
+ println(Array[Nothing]().getClass)
+} \ No newline at end of file