From 0c5dd9e02f03143372237018c55e12a07c13f8c1 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 30 Apr 2013 21:14:06 +0200 Subject: [backport] SI-7470 implements fundep materialization Backports 21a8c6c from the 2.11.x branch under -Xfundep-materialization as per Miles Sabin's request. Thanks Miles! --- .../scala/tools/nsc/settings/ScalaSettings.scala | 1 + .../scala/tools/nsc/typechecker/Macros.scala | 32 +++++++++++-- test/files/neg/t5923c.check | 4 ++ test/files/neg/t5923c/Macros_1.scala | 39 ++++++++++++++++ test/files/neg/t5923c/Test_2.scala | 12 +++++ test/files/run/t5923a-fundep.check | 3 ++ test/files/run/t5923a-fundep.flags | 1 + test/files/run/t5923a-fundep/Macros_1.scala | 52 ++++++++++++++++++++++ test/files/run/t5923a-fundep/Test_2.scala | 5 +++ test/files/run/t5923a-nofundep.check | 3 ++ test/files/run/t5923a-nofundep/Macros_1.scala | 14 ++++++ test/files/run/t5923a-nofundep/Test_2.scala | 5 +++ test/files/run/t5923a.check | 3 -- test/files/run/t5923a/Macros_1.scala | 14 ------ test/files/run/t5923a/Test_2.scala | 5 --- test/files/run/t5923c.check | 1 + test/files/run/t5923c.flags | 1 + test/files/run/t5923c/Macros_1.scala | 39 ++++++++++++++++ test/files/run/t5923c/Test_2.scala | 12 +++++ test/files/run/t5923d.check | 0 test/files/run/t5923d/Macros_1.scala | 9 ++++ test/files/run/t5923d/Test_2.scala | 7 +++ 22 files changed, 236 insertions(+), 26 deletions(-) create mode 100644 test/files/neg/t5923c.check create mode 100644 test/files/neg/t5923c/Macros_1.scala create mode 100644 test/files/neg/t5923c/Test_2.scala create mode 100644 test/files/run/t5923a-fundep.check create mode 100644 test/files/run/t5923a-fundep.flags create mode 100644 test/files/run/t5923a-fundep/Macros_1.scala create mode 100644 test/files/run/t5923a-fundep/Test_2.scala create mode 100644 test/files/run/t5923a-nofundep.check create mode 100644 test/files/run/t5923a-nofundep/Macros_1.scala create mode 100644 test/files/run/t5923a-nofundep/Test_2.scala delete mode 100644 test/files/run/t5923a.check delete mode 100644 test/files/run/t5923a/Macros_1.scala delete mode 100644 test/files/run/t5923a/Test_2.scala create mode 100644 test/files/run/t5923c.check create mode 100644 test/files/run/t5923c.flags create mode 100644 test/files/run/t5923c/Macros_1.scala create mode 100644 test/files/run/t5923c/Test_2.scala create mode 100644 test/files/run/t5923d.check create mode 100644 test/files/run/t5923d/Macros_1.scala create mode 100644 test/files/run/t5923d/Test_2.scala diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index dbfaa2c531..3a6d183c32 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -111,6 +111,7 @@ trait ScalaSettings extends AbsScalaSettings val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") val Xdivergence211 = BooleanSetting ("-Xdivergence211", "Turn on the 2.11 behavior of implicit divergence not terminating recursive implicit searches (SI-7291).") + val XfundepMaterialization = BooleanSetting("-Xfundep-materialization", "Turn on the 2.11 behavior of macro expansion being able to influence type inference in implicit searches") /** Compatibility stubs for options whose value name did * not previously match the option name. diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index d6ec5f2cb0..6801dc068c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -713,6 +713,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { var expectedTpe = expandee.tpe if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType + if (settings.XfundepMaterialization.value) { + // approximation is necessary for whitebox macros to guide type inference + // read more in the comments for onDelayed below + val undetparams = expectedTpe collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol } + expectedTpe = deriveTypeWithWildcards(undetparams)(expectedTpe) + } + // also see http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc val expanded0 = duplicateAndKeepPositions(expanded) val expanded1 = typecheck("macro def return type", expanded0, expectedTpe) @@ -766,9 +773,24 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // (in a sense that a datatype's uniform representation is unambiguously determined by the datatype, // e.g. for Foo it will be Int :: String :: Boolean :: HNil), there's no way to convey this information // to the typechecker. Therefore the typechecker will infer Nothing for L, which is hardly what we want. + // + // =========== THE SOLUTION =========== + // + // To give materializers a chance to say their word before vanilla inference kicks in, + // we infer as much as possible (e.g. in the example above even though L is hopeless, C still can be inferred to Foo) + // and then trigger macro expansion with the undetermined type parameters still there. + // Thanks to that the materializer can take a look at what's going on and react accordingly. + // + // NOTE: This functionality is only available under the -Xfundep-materialization flag in Scala 2.10, + // but is enabled by default in Scala 2.11. val shouldInstantiate = typer.context.undetparams.nonEmpty && !inPolyMode(mode) - if (shouldInstantiate) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt) - else delayed + if (shouldInstantiate) { + if (settings.XfundepMaterialization.value) { + forced += delayed + typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false) + macroExpand(typer, delayed, mode, pt) + } else typer.instantiatePossiblyExpectingUnit(delayed, mode, pt) + } else delayed case Fallback(fallback) => typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt)) case Other(result) => @@ -886,10 +908,12 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { * 2) undetparams (sym.isTypeParameter && !sym.isSkolem) */ var hasPendingMacroExpansions = false + private val forced = perRunCaches.newWeakSet[Tree] private val delayed = perRunCaches.newWeakMap[Tree, scala.collection.mutable.Set[Int]] private def isDelayed(expandee: Tree) = delayed contains expandee private def calculateUndetparams(expandee: Tree): scala.collection.mutable.Set[Int] = - delayed.get(expandee).getOrElse { + if (forced(expandee)) scala.collection.mutable.Set[Int]() + else delayed.getOrElse(expandee, { val calculated = scala.collection.mutable.Set[Symbol]() expandee foreach (sub => { def traverse(sym: Symbol) = if (sym != null && (undetparams contains sym.id)) calculated += sym @@ -898,7 +922,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { }) macroLogVerbose("calculateUndetparams: %s".format(calculated)) calculated map (_.id) - } + }) private val undetparams = perRunCaches.newSet[Int] def notifyUndetparamsAdded(newUndets: List[Symbol]): Unit = { undetparams ++= newUndets map (_.id) diff --git a/test/files/neg/t5923c.check b/test/files/neg/t5923c.check new file mode 100644 index 0000000000..6d3d6b1b78 --- /dev/null +++ b/test/files/neg/t5923c.check @@ -0,0 +1,4 @@ +Test_2.scala:7: error: could not find implicit value for parameter iso: Iso[Test.Foo,L] + val equiv = foo(Foo(23, "foo", true)) + ^ +one error found diff --git a/test/files/neg/t5923c/Macros_1.scala b/test/files/neg/t5923c/Macros_1.scala new file mode 100644 index 0000000000..0b7a3399e2 --- /dev/null +++ b/test/files/neg/t5923c/Macros_1.scala @@ -0,0 +1,39 @@ +import language.experimental.macros +import scala.reflect.macros.Context + +trait Iso[T, U] { + def to(t : T) : U + // def from(u : U) : T +} + +object Iso { + implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U] + def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context): c.Expr[Iso[T, U]] = { + import c.universe._ + import definitions._ + import Flag._ + + val sym = c.weakTypeOf[T].typeSymbol + if (!sym.isClass || !sym.asClass.isCaseClass) c.abort(c.enclosingPosition, s"$sym is not a case class") + val fields = sym.typeSignature.declarations.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x } + + def mkTpt() = { + val core = Ident(TupleClass(fields.length) orElse UnitClass) + if (fields.length == 0) core + else AppliedTypeTree(core, fields map (f => TypeTree(f.typeSignature))) + } + + def mkFrom() = { + if (fields.length == 0) Literal(Constant(Unit)) + else Apply(Ident(newTermName("Tuple" + fields.length)), fields map (f => Select(Ident(newTermName("f")), newTermName(f.name.toString.trim)))) + } + + val evidenceClass = ClassDef(Modifiers(FINAL), newTypeName("$anon"), List(), Template( + List(AppliedTypeTree(Ident(newTypeName("Iso")), List(Ident(sym), mkTpt()))), + emptyValDef, + List( + DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))), + DefDef(Modifiers(), newTermName("to"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("f"), Ident(sym), EmptyTree))), TypeTree(), mkFrom())))) + c.Expr[Iso[T, U]](Block(List(evidenceClass), Apply(Select(New(Ident(newTypeName("$anon"))), nme.CONSTRUCTOR), List()))) + } +} diff --git a/test/files/neg/t5923c/Test_2.scala b/test/files/neg/t5923c/Test_2.scala new file mode 100644 index 0000000000..a00f4ed7db --- /dev/null +++ b/test/files/neg/t5923c/Test_2.scala @@ -0,0 +1,12 @@ +// see the comments for macroExpandApply.onDelayed for an explanation of what's tested here +object Test extends App { + case class Foo(i: Int, s: String, b: Boolean) + def foo[C, L](c: C)(implicit iso: Iso[C, L]): L = iso.to(c) + + { + val equiv = foo(Foo(23, "foo", true)) + def typed[T](t: => T) {} + typed[(Int, String, Boolean)](equiv) + println(equiv) + } +} \ No newline at end of file diff --git a/test/files/run/t5923a-fundep.check b/test/files/run/t5923a-fundep.check new file mode 100644 index 0000000000..7165b734ac --- /dev/null +++ b/test/files/run/t5923a-fundep.check @@ -0,0 +1,3 @@ +C(Int) +C(String) +C(Nothing) diff --git a/test/files/run/t5923a-fundep.flags b/test/files/run/t5923a-fundep.flags new file mode 100644 index 0000000000..c8b4511960 --- /dev/null +++ b/test/files/run/t5923a-fundep.flags @@ -0,0 +1 @@ +-Xfundep-materialization \ No newline at end of file diff --git a/test/files/run/t5923a-fundep/Macros_1.scala b/test/files/run/t5923a-fundep/Macros_1.scala new file mode 100644 index 0000000000..97076eb102 --- /dev/null +++ b/test/files/run/t5923a-fundep/Macros_1.scala @@ -0,0 +1,52 @@ +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: Context)(ttag: c.WeakTypeTag[T]) = { + import c.universe._ + val ttag0 = ttag; + { + // When we're expanding implicitly[C[Nothing]], the type inferencer will see + // that foo[T] returns C[T] and that we request an implicit of type C[Nothing]. + // + // Then the type inferencer will try to match C[T] against C[Nothing] and infer everything it can infer + // from that match, but not more (e.g. if we were returning Iso[T, U] and the type we were looking at was Iso[Foo, L], + // we wouldn't want U to be auto-inferred to Nothing, as it usually happens with normal methods, + // but would rather want it to remain unknown, so that our macro could take a stab at inferring it: + // see the comments in this commit for more information). + // + // Equipped with common sense, in our case of C[T] and C[Nothing] we would expect T to be inferred as Nothing, and then we + // would expect T in the corresponding macro invocation to be Nothing. Unfortunately it is not that simple. + // + // Internally the type inferencer uses Nothing as a dummy value, which stands for "don't know how to + // infer this type parameter". In the Iso example, matching Iso[T, U] against Iso[Foo, L] would result in + // T being inferred as Foo and U being inferred as Nothing (!!). Then the type inferencer will think: + // "Aha! U ended up being Nothing. This means that I failed to infer it, + // therefore the result of my work is: T -> Foo, U -> still unknown". + // + // That's all very good and works very well until Nothing is a genuine result of type inference, + // as in our original example of inferring T in C[T] from C[Nothing]. In that case, the inferencer becomes confused + // and here in the macro implementation we get weakTypeOf[T] equal to some dummy type carrying a type parameter + // instead of Nothing. + // + // This eccentric behavior of the type inferencer is a long-standing problem in scalac, + // so the best one can do for now until it's fixed is to work around, manually converting + // suspicious T's into Nothings. Of course, this means that we would have to approximate, + // because there's no way to know whether having T here stands for a failed attempt to infer Nothing + // or for a failed attempt to infer anything, but at least we're in full control of making the best + // of this sad situation. + implicit def ttag: WeakTypeTag[T] = { + val tpe = ttag0.tpe + val sym = tpe.typeSymbol.asType + if (sym.isParameter && !sym.isSkolem) TypeTag.Nothing.asInstanceOf[TypeTag[T]] + else ttag0 + } + reify(C[T](c.literal(weakTypeOf[T].toString).splice)) + } + } +} \ No newline at end of file diff --git a/test/files/run/t5923a-fundep/Test_2.scala b/test/files/run/t5923a-fundep/Test_2.scala new file mode 100644 index 0000000000..001ff9aea8 --- /dev/null +++ b/test/files/run/t5923a-fundep/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/t5923a-nofundep.check b/test/files/run/t5923a-nofundep.check new file mode 100644 index 0000000000..7165b734ac --- /dev/null +++ b/test/files/run/t5923a-nofundep.check @@ -0,0 +1,3 @@ +C(Int) +C(String) +C(Nothing) diff --git a/test/files/run/t5923a-nofundep/Macros_1.scala b/test/files/run/t5923a-nofundep/Macros_1.scala new file mode 100644 index 0000000000..6d21362c4d --- /dev/null +++ b/test/files/run/t5923a-nofundep/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-nofundep/Test_2.scala b/test/files/run/t5923a-nofundep/Test_2.scala new file mode 100644 index 0000000000..001ff9aea8 --- /dev/null +++ b/test/files/run/t5923a-nofundep/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/t5923a.check b/test/files/run/t5923a.check deleted file mode 100644 index 7165b734ac..0000000000 --- a/test/files/run/t5923a.check +++ /dev/null @@ -1,3 +0,0 @@ -C(Int) -C(String) -C(Nothing) diff --git a/test/files/run/t5923a/Macros_1.scala b/test/files/run/t5923a/Macros_1.scala deleted file mode 100644 index 6d21362c4d..0000000000 --- a/test/files/run/t5923a/Macros_1.scala +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 001ff9aea8..0000000000 --- a/test/files/run/t5923a/Test_2.scala +++ /dev/null @@ -1,5 +0,0 @@ -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/t5923c.check b/test/files/run/t5923c.check new file mode 100644 index 0000000000..bed7429108 --- /dev/null +++ b/test/files/run/t5923c.check @@ -0,0 +1 @@ +(23,foo,true) diff --git a/test/files/run/t5923c.flags b/test/files/run/t5923c.flags new file mode 100644 index 0000000000..c8b4511960 --- /dev/null +++ b/test/files/run/t5923c.flags @@ -0,0 +1 @@ +-Xfundep-materialization \ No newline at end of file diff --git a/test/files/run/t5923c/Macros_1.scala b/test/files/run/t5923c/Macros_1.scala new file mode 100644 index 0000000000..0b7a3399e2 --- /dev/null +++ b/test/files/run/t5923c/Macros_1.scala @@ -0,0 +1,39 @@ +import language.experimental.macros +import scala.reflect.macros.Context + +trait Iso[T, U] { + def to(t : T) : U + // def from(u : U) : T +} + +object Iso { + implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U] + def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context): c.Expr[Iso[T, U]] = { + import c.universe._ + import definitions._ + import Flag._ + + val sym = c.weakTypeOf[T].typeSymbol + if (!sym.isClass || !sym.asClass.isCaseClass) c.abort(c.enclosingPosition, s"$sym is not a case class") + val fields = sym.typeSignature.declarations.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x } + + def mkTpt() = { + val core = Ident(TupleClass(fields.length) orElse UnitClass) + if (fields.length == 0) core + else AppliedTypeTree(core, fields map (f => TypeTree(f.typeSignature))) + } + + def mkFrom() = { + if (fields.length == 0) Literal(Constant(Unit)) + else Apply(Ident(newTermName("Tuple" + fields.length)), fields map (f => Select(Ident(newTermName("f")), newTermName(f.name.toString.trim)))) + } + + val evidenceClass = ClassDef(Modifiers(FINAL), newTypeName("$anon"), List(), Template( + List(AppliedTypeTree(Ident(newTypeName("Iso")), List(Ident(sym), mkTpt()))), + emptyValDef, + List( + DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))), + DefDef(Modifiers(), newTermName("to"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("f"), Ident(sym), EmptyTree))), TypeTree(), mkFrom())))) + c.Expr[Iso[T, U]](Block(List(evidenceClass), Apply(Select(New(Ident(newTypeName("$anon"))), nme.CONSTRUCTOR), List()))) + } +} diff --git a/test/files/run/t5923c/Test_2.scala b/test/files/run/t5923c/Test_2.scala new file mode 100644 index 0000000000..a00f4ed7db --- /dev/null +++ b/test/files/run/t5923c/Test_2.scala @@ -0,0 +1,12 @@ +// see the comments for macroExpandApply.onDelayed for an explanation of what's tested here +object Test extends App { + case class Foo(i: Int, s: String, b: Boolean) + def foo[C, L](c: C)(implicit iso: Iso[C, L]): L = iso.to(c) + + { + val equiv = foo(Foo(23, "foo", true)) + def typed[T](t: => T) {} + typed[(Int, String, Boolean)](equiv) + println(equiv) + } +} \ No newline at end of file diff --git a/test/files/run/t5923d.check b/test/files/run/t5923d.check new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/files/run/t5923d/Macros_1.scala b/test/files/run/t5923d/Macros_1.scala new file mode 100644 index 0000000000..f32d1af704 --- /dev/null +++ b/test/files/run/t5923d/Macros_1.scala @@ -0,0 +1,9 @@ +import scala.language.experimental.macros +import scala.reflect.macros.Context + +trait MappedRow +trait RowMapper[T <: MappedRow] +object RowMapper { + implicit def mapper[T <: MappedRow]: RowMapper[T] = macro impl[T] + def impl[T <: MappedRow : c.WeakTypeTag](c: Context) = c.universe.reify(new RowMapper[T]{}) +} \ No newline at end of file diff --git a/test/files/run/t5923d/Test_2.scala b/test/files/run/t5923d/Test_2.scala new file mode 100644 index 0000000000..6be10227c2 --- /dev/null +++ b/test/files/run/t5923d/Test_2.scala @@ -0,0 +1,7 @@ +class RowA extends MappedRow +class RowB extends MappedRow + +object Test extends App { + implicitly[RowMapper[RowA]] + implicitly[RowMapper[RowB]] +} \ No newline at end of file -- cgit v1.2.3 From 364c8e9fde9212d9c7cf543ffe73206b2b00c67d Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 3 Jul 2014 13:16:08 +0200 Subject: pull request feedback --- src/compiler/scala/tools/nsc/typechecker/Macros.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 6801dc068c..f0770e84c4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -912,6 +912,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { private val delayed = perRunCaches.newWeakMap[Tree, scala.collection.mutable.Set[Int]] private def isDelayed(expandee: Tree) = delayed contains expandee private def calculateUndetparams(expandee: Tree): scala.collection.mutable.Set[Int] = + // !settings.XfundepMaterialization.value implies forced.isEmpty if (forced(expandee)) scala.collection.mutable.Set[Int]() else delayed.getOrElse(expandee, { val calculated = scala.collection.mutable.Set[Symbol]() -- cgit v1.2.3 From 5966a11ae1f494f1c7271a6a574b3ff4365f5847 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 9 Sep 2014 16:18:24 +0200 Subject: -Xfundep-materialization => -Yfundep-materialization To quote gkossakowski: Thinking about it more, could we hide this behind 'Y' flag instead? We have lesser obligation to keep around Y flags and this is something we should remove from 2.11/2.12. --- src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Macros.scala | 6 +++--- test/files/run/t5923a-fundep.flags | 2 +- test/files/run/t5923c.flags | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 3a6d183c32..56fc4d7594 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -111,7 +111,6 @@ trait ScalaSettings extends AbsScalaSettings val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") val Xdivergence211 = BooleanSetting ("-Xdivergence211", "Turn on the 2.11 behavior of implicit divergence not terminating recursive implicit searches (SI-7291).") - val XfundepMaterialization = BooleanSetting("-Xfundep-materialization", "Turn on the 2.11 behavior of macro expansion being able to influence type inference in implicit searches") /** Compatibility stubs for options whose value name did * not previously match the option name. @@ -180,6 +179,7 @@ trait ScalaSettings extends AbsScalaSettings val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() + val YfundepMaterialization = BooleanSetting("-Yfundep-materialization", "Turn on the 2.11 behavior of macro expansion being able to influence type inference in implicit searches") def stop = stopAfter diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index f0770e84c4..c0844ec8fc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -713,7 +713,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { var expectedTpe = expandee.tpe if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType - if (settings.XfundepMaterialization.value) { + if (settings.YfundepMaterialization.value) { // approximation is necessary for whitebox macros to guide type inference // read more in the comments for onDelayed below val undetparams = expectedTpe collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol } @@ -785,7 +785,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { // but is enabled by default in Scala 2.11. val shouldInstantiate = typer.context.undetparams.nonEmpty && !inPolyMode(mode) if (shouldInstantiate) { - if (settings.XfundepMaterialization.value) { + if (settings.YfundepMaterialization.value) { forced += delayed typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false) macroExpand(typer, delayed, mode, pt) @@ -912,7 +912,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { private val delayed = perRunCaches.newWeakMap[Tree, scala.collection.mutable.Set[Int]] private def isDelayed(expandee: Tree) = delayed contains expandee private def calculateUndetparams(expandee: Tree): scala.collection.mutable.Set[Int] = - // !settings.XfundepMaterialization.value implies forced.isEmpty + // !settings.YfundepMaterialization.value implies forced.isEmpty if (forced(expandee)) scala.collection.mutable.Set[Int]() else delayed.getOrElse(expandee, { val calculated = scala.collection.mutable.Set[Symbol]() diff --git a/test/files/run/t5923a-fundep.flags b/test/files/run/t5923a-fundep.flags index c8b4511960..384b48d1b0 100644 --- a/test/files/run/t5923a-fundep.flags +++ b/test/files/run/t5923a-fundep.flags @@ -1 +1 @@ --Xfundep-materialization \ No newline at end of file +-Yfundep-materialization \ No newline at end of file diff --git a/test/files/run/t5923c.flags b/test/files/run/t5923c.flags index c8b4511960..384b48d1b0 100644 --- a/test/files/run/t5923c.flags +++ b/test/files/run/t5923c.flags @@ -1 +1 @@ --Xfundep-materialization \ No newline at end of file +-Yfundep-materialization \ No newline at end of file -- cgit v1.2.3