From 8aa8cfed11cf492f2c3742d44b078648988839b5 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 12 Jul 2022 12:45:56 +0200 Subject: [PATCH] Fix looping implicits check Ignore embedded lazy val definitions --- .../transform/CheckLoopingImplicits.scala | 2 +- .../fatal-warnings/i13542.scala | 2 +- tests/neg/i13044.check | 132 ------------------ .../fatal-warnings/not-looping-implicit.scala | 43 ++++++ 4 files changed, 45 insertions(+), 134 deletions(-) create mode 100644 tests/pos-special/fatal-warnings/not-looping-implicit.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala index 47f65f04cff7..7c8082265161 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckLoopingImplicits.scala @@ -98,7 +98,7 @@ class CheckLoopingImplicits extends MiniPhase: checkNotLooping(finalizer) case SeqLiteral(elems, _) => elems.foreach(checkNotLooping) - case t: ValDef => + case t: ValDef if !t.symbol.is(Lazy) => checkNotLooping(t.rhs) case _ => diff --git a/tests/neg-custom-args/fatal-warnings/i13542.scala b/tests/neg-custom-args/fatal-warnings/i13542.scala index 3da18c233583..0ce46313dcad 100644 --- a/tests/neg-custom-args/fatal-warnings/i13542.scala +++ b/tests/neg-custom-args/fatal-warnings/i13542.scala @@ -40,7 +40,7 @@ val x5 = val x6 = implicit def barToFoo4(bar: Bar): Foo = - lazy val y = bar.toFoo // error + lazy val y = bar.toFoo if false then y else ??? val foo: Foo = Bar(1) diff --git a/tests/neg/i13044.check b/tests/neg/i13044.check index 437e84c0f480..c5584aadf767 100644 --- a/tests/neg/i13044.check +++ b/tests/neg/i13044.check @@ -1,135 +1,3 @@ --- Warning: tests/neg/i13044.scala:50:40 ------------------------------------------------------------------------------- -50 | implicit def typeSchema: Schema[A] = Schema.gen // error // error - | ^^^^^^^^^^ - |Infinite loop in function body - |{ - | val SchemaDerivation_this: Schema.type = Schema - | { - | val SchemaDerivation_this: (SchemaDerivation_this : Schema.type) = SchemaDerivation_this - | { - | val $scrutinee1: - | scala.deriving.Mirror.Product{ - | MirroredMonoType = A; MirroredType = A; MirroredLabel = ("A" : String); MirroredElemTypes = (A, B); - | MirroredElemLabels = (("a" : String), ("b" : String)) - | } - | = - | A.$asInstanceOf[ - | scala.deriving.Mirror.Product{ - | MirroredMonoType = A; MirroredType = A; MirroredLabel = ("A" : String); MirroredElemTypes = (A, B); - | MirroredElemLabels = (("a" : String), ("b" : String)) - | } - | ] - | val m: - | scala.deriving.Mirror.Product{ - | MirroredMonoType = A; MirroredType = A; MirroredLabel = ("A" : String); MirroredElemTypes = (A, B); - | MirroredElemLabels = (("a" : String), ("b" : String)) - | } - | = $scrutinee1 - | lazy val fields: List[Schema[Any]] = - | { - | val SchemaDerivation_this: (SchemaDerivation_this : (SchemaDerivation_this : Schema.type)) = - | SchemaDerivation_this - | { - | val builder: Schema[Any] = TestApp.typeSchema.asInstanceOf[Schema[Any]] - | { - | val SchemaDerivation_this: - | (SchemaDerivation_this : (SchemaDerivation_this : (SchemaDerivation_this : Schema.type))) - | = SchemaDerivation_this - | ( - | { - | val builder: Schema[Any] = - | { - | val SchemaDerivation_this: Schema.type = Schema - | ( - | { - | val SchemaDerivation_this: (SchemaDerivation_this : Schema.type) = SchemaDerivation_this - | { - | val $scrutinee4: - | scala.deriving.Mirror.Product{ - | MirroredMonoType = B; MirroredType = B; MirroredLabel = ("B" : String); - | MirroredElemTypes = C *: EmptyTuple.type - | ; MirroredElemLabels = ("c" : String) *: EmptyTuple.type - | } - | = - | B.$asInstanceOf[ - | scala.deriving.Mirror.Product{ - | MirroredMonoType = B; MirroredType = B; MirroredLabel = ("B" : String); - | MirroredElemTypes = C *: EmptyTuple.type - | ; MirroredElemLabels = ("c" : String) *: EmptyTuple.type - | } - | ] - | val m: - | scala.deriving.Mirror.Product{ - | MirroredMonoType = B; MirroredType = B; MirroredLabel = ("B" : String); - | MirroredElemTypes = C *: EmptyTuple.type - | ; MirroredElemLabels = ("c" : String) *: EmptyTuple.type - | } - | = $scrutinee4 - | lazy val fields: List[Schema[Any]] = - | { - | val SchemaDerivation_this: - | (SchemaDerivation_this : (SchemaDerivation_this : Schema.type)) - | = SchemaDerivation_this - | { - | val builder: Schema[Any] = - | { - | val SchemaDerivation_this: Schema.type = Schema - | ( - | { - | val SchemaDerivation_this: (...SchemaDerivation_this : ....type) = - | SchemaDerivation_this - | { - | val $scrutinee6: - | ...{ - | MirroredMonoType...; MirroredType...; MirroredLabel...; - | MirroredElemTypes... - | ; MirroredElemLabels... - | } - | = ....$asInstanceOf[...] - | val m: ... = ...$scrutinee6 - | lazy val fields: ... = - | { - | val SchemaDerivation_this: ... = ... - | ...:... - | } - | { - | final class $anon() extends ...(), ... { - | def build: ... = ... - | } - | ...():... - | } - | }:...[...] - | } - | :Schema[C]) - | }.asInstanceOf[Schema[Any]] - | SchemaDerivation_this.recurse[EmptyTuple.type].::[Schema[Any]](builder) - | }:List[Schema[Any]] - | } - | { - | final class $anon() extends Object(), Schema[B] { - | def build: B = ??? - | } - | new Object with Schema[B] {...}():Schema[B] - | } - | }:Schema[B] - | } - | :Schema[B]) - | }.asInstanceOf[Schema[Any]] - | SchemaDerivation_this.recurse[EmptyTuple.type].::[Schema[Any]](builder) - | } - | :List[Schema[Any]]) - | }.::[Schema[Any]](builder) - | }:List[Schema[Any]] - | } - | { - | final class $anon() extends Object(), Schema[A] { - | def build: A = ??? - | } - | new Object with Schema[A] {...}():Schema[A] - | } - | }:Schema[A] - | }:Schema[A] - |} -- Error: tests/neg/i13044.scala:50:40 --------------------------------------------------------------------------------- 50 | implicit def typeSchema: Schema[A] = Schema.gen // error // error | ^^^^^^^^^^ diff --git a/tests/pos-special/fatal-warnings/not-looping-implicit.scala b/tests/pos-special/fatal-warnings/not-looping-implicit.scala new file mode 100644 index 000000000000..a35945bfe373 --- /dev/null +++ b/tests/pos-special/fatal-warnings/not-looping-implicit.scala @@ -0,0 +1,43 @@ +import scala.deriving.Mirror +import scala.compiletime._ + +trait Schema[T] + +object Schema { + implicit val stringSchema: Schema[String] = new Schema[String] {} + implicit def listSchema[A](implicit ev: Schema[A]): Schema[List[A]] = new Schema[List[A]] {} + implicit def mapSchema[A, B](implicit evA: Schema[A], evB: Schema[B]): Schema[Map[A, B]] = + new Schema[Map[A, B]] {} + + inline def recurse[Label, A <: Tuple](index: Int = 0): List[(String, Schema[Any], Int)] = + inline erasedValue[(Label, A)] match { + case (_: (name *: names), _: (t *: ts)) => + val label = constValue[name].toString + val builder = summonInline[Schema[t]].asInstanceOf[Schema[Any]] + (label, builder, index) :: recurse[names, ts](index + 1) + case (_: EmptyTuple, _) => Nil + } + + inline def derived[A]: Schema[A] = + inline summonInline[Mirror.Of[A]] match { + case m: Mirror.SumOf[A] => + lazy val members = recurse[m.MirroredElemLabels, m.MirroredElemTypes]() + new Schema[A] {} + case m: Mirror.ProductOf[A] => + lazy val fields = recurse[m.MirroredElemLabels, m.MirroredElemTypes]() + new Schema[A] {} + } + + inline given gen[A]: Schema[A] = derived[A] +} + +sealed trait InputValue +object InputValue { + case class ListValue(values: List[InputValue]) extends InputValue + case class ObjectValue(fields: Map[String, InputValue]) extends InputValue + case class VariableValue(name: String) extends InputValue +} + +@main def Test = + implicit lazy val inputValueSchema: Schema[InputValue] = Schema.gen + println(summon[Schema[InputValue]]) \ No newline at end of file