From 2df18bf17f4d007a395373958d129c5955c7206e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 16 May 2021 12:42:24 +0200 Subject: [PATCH 1/8] Don't typecheck Scala2 macro calls in retyping mode --- compiler/src/dotty/tools/dotc/typer/ReTyper.scala | 1 + compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index a744ca39f41f..0a9943067127 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -134,4 +134,5 @@ class ReTyper extends Typer with ReChecking { override protected def addAccessorDefs(cls: Symbol, body: List[Tree])(using Context): List[Tree] = body override protected def checkEqualityEvidence(tree: tpd.Tree, pt: Type)(using Context): Unit = () override protected def matchingApply(methType: MethodOrPoly, pt: FunProto)(using Context): Boolean = true + override protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree = promote(call) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index cda1daafd252..5d4b6bbcc492 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3900,7 +3900,7 @@ class Typer extends Namer report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos) /** Types the body Scala 2 macro declaration `def f = macro ` */ - private def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree = + protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree = // TODO check that call is to a method with valid signature def typedPrefix(tree: untpd.RefTree)(splice: Context ?=> Tree => Tree)(using Context): Tree = { tryAlternatively { From e58ece83e32e2a6cc25325469d5e4ae5caba4257 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 20 May 2021 18:24:12 +0200 Subject: [PATCH 2/8] Don't instantiate variables to Nothing in canDefineFurther The purpose of canDefineFurther is to discover new members. That is not helped by instantiating a type variable to `Nothing`. Avoiding the instantiation helpos error messages. There was one test (i864.scala) that fails now but compiled previously with a surprising instantiation to Nothing. I believe it is better to issue an error message in this case. --- .../dotty/tools/dotc/typer/Inferencing.scala | 7 +++++-- tests/neg/i4986a.check | 2 +- tests/neg/i7056.check | 21 ++++++++++++++----- tests/{pos => neg}/i864.scala | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) rename tests/{pos => neg}/i864.scala (74%) diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 409225138ea9..fd29f585eed8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -33,7 +33,10 @@ object Inferencing { */ def isFullyDefined(tp: Type, force: ForceDegree.Value)(using Context): Boolean = { val nestedCtx = ctx.fresh.setNewTyperState() - val result = new IsFullyDefinedAccumulator(force)(using nestedCtx).process(tp) + val result = + try new IsFullyDefinedAccumulator(force)(using nestedCtx).process(tp) + catch case ex: StackOverflowError => + false // can happen for programs with illegal recusions, e.g. neg/recursive-lower-constraint.scala if (result) nestedCtx.typerState.commit() result } @@ -43,7 +46,7 @@ object Inferencing { */ def canDefineFurther(tp: Type)(using Context): Boolean = val prevConstraint = ctx.typerState.constraint - isFullyDefined(tp, force = ForceDegree.all) + isFullyDefined(tp, force = ForceDegree.failBottom) && (ctx.typerState.constraint ne prevConstraint) /** The fully defined type, where all type variables are forced. diff --git a/tests/neg/i4986a.check b/tests/neg/i4986a.check index 5375d0fd002b..3aac0a7b2cf3 100644 --- a/tests/neg/i4986a.check +++ b/tests/neg/i4986a.check @@ -4,6 +4,6 @@ |Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int].. |I found: | - | collection.BuildFrom.buildFromIterableOps[Nothing, Nothing, Nothing] + | collection.BuildFrom.buildFromIterableOps[CC, A0, A] | |But method buildFromIterableOps in trait BuildFromLowPriority2 does not match type collection.BuildFrom[List[Int], Int, List[String]]. diff --git a/tests/neg/i7056.check b/tests/neg/i7056.check index 1695c1e4b6f0..0f9a85f36321 100644 --- a/tests/neg/i7056.check +++ b/tests/neg/i7056.check @@ -1,7 +1,18 @@ --- [E008] Not Found Error: tests/neg/i7056.scala:19:10 ----------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/i7056.scala:19:8 -------------------------------------------------------------- 19 |val z = x.idnt1 // error - | ^^^^^^^ - | value idnt1 is not a member of B. - | An extension method was tried, but could not be fully constructed: + | ^ + | Found: (given_PartialId_B : B) + | Required: PartialId[T] | - | given_T1_T[T](given_PartialId_B).idnt1() + | where: T is a type variable with constraint <: A + | + | + | Note: a match type could not be fully reduced: + | + | trying to reduce PartialId[T] + | failed since selector T + | matches none of the cases + | + | case B => T + +longer explanation available when compiling with `-explain` diff --git a/tests/pos/i864.scala b/tests/neg/i864.scala similarity index 74% rename from tests/pos/i864.scala rename to tests/neg/i864.scala index 8d2b859998e9..b372d00a569b 100644 --- a/tests/pos/i864.scala +++ b/tests/neg/i864.scala @@ -6,5 +6,5 @@ object C { trait X[T] implicit def u[A, B]: X[A | B] = new X[A | B] {} def y[T](implicit x: X[T]): T = ??? - val x: a.type & b.type | b.type & c.type = y + val x: a.type & b.type | b.type & c.type = y // error } From 0e290dc558b2835c43c7d58046ab40de155e6d34 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 May 2021 18:12:30 +0200 Subject: [PATCH 3/8] Generalize use of canDefineFurther in recover We should retry adapt if we can instantiate typevars in either the type of the tree or the expected type --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 5d4b6bbcc492..c46a4f7e4c21 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3678,7 +3678,7 @@ class Typer extends Namer return readapt(tree.cast(target)) def recover(failure: SearchFailureType) = - if canDefineFurther(wtp) then readapt(tree) + if canDefineFurther(wtp) || canDefineFurther(pt) then readapt(tree) else err.typeMismatch(tree, pt, failure) pt match From 22d97827082716f234e0c90b487ac5da2453c852 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 May 2021 18:14:10 +0200 Subject: [PATCH 4/8] Reclassify test --- .../typeclass-encoding3.scala} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/{pos/typeclass-encoding2.scala => neg/typeclass-encoding3.scala} (98%) diff --git a/tests/pos/typeclass-encoding2.scala b/tests/neg/typeclass-encoding3.scala similarity index 98% rename from tests/pos/typeclass-encoding2.scala rename to tests/neg/typeclass-encoding3.scala index 13db93f91204..ff403314cd1a 100644 --- a/tests/pos/typeclass-encoding2.scala +++ b/tests/neg/typeclass-encoding3.scala @@ -344,5 +344,6 @@ object functors { ??? // $this.flatMap[A](identity) disabled since it does not typecheck } - MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5))) + MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5))) // ok, synthesizes (using ListMonad) + MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5)))(using ListMonad) // error } \ No newline at end of file From 55a223c7ab3231cc0c0e138eda29ba29ec2c989d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 20 May 2021 18:24:57 +0200 Subject: [PATCH 5/8] Fix dependent variable approximation for by-name parameters --- compiler/src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index fd29f585eed8..97f14e2fe5a4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -690,7 +690,7 @@ trait Inferencing { this: Typer => val arg = findArg(call) if !arg.isEmpty then - var argType = arg.tpe + var argType = arg.tpe.widenExpr.widenTermRefExpr if !argType.isSingleton then argType = SkolemType(argType) argType <:< tvar case _ => From 12d2e20dbaf138aaa1bf720ef98d7671d726ec70 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 May 2021 18:43:42 +0200 Subject: [PATCH 6/8] Fix check file --- tests/neg-scalajs/jsconstructortag-error-in-typer.check | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/neg-scalajs/jsconstructortag-error-in-typer.check b/tests/neg-scalajs/jsconstructortag-error-in-typer.check index a18ed693383e..22212957403f 100644 --- a/tests/neg-scalajs/jsconstructortag-error-in-typer.check +++ b/tests/neg-scalajs/jsconstructortag-error-in-typer.check @@ -4,7 +4,7 @@ |no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaClass] was found for parameter tag of method constructorTag in package scala.scalajs.js. |I found: | - | scala.scalajs.js.ConstructorTag.materialize[Nothing] + | scala.scalajs.js.ConstructorTag.materialize[T] | |But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaClass]. -- Error: tests/neg-scalajs/jsconstructortag-error-in-typer.scala:10:39 ------------------------------------------------ @@ -13,7 +13,7 @@ |no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaTrait] was found for parameter tag of method constructorTag in package scala.scalajs.js. |I found: | - | scala.scalajs.js.ConstructorTag.materialize[Nothing] + | scala.scalajs.js.ConstructorTag.materialize[T] | |But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaTrait]. -- Error: tests/neg-scalajs/jsconstructortag-error-in-typer.scala:11:45 ------------------------------------------------ @@ -22,6 +22,6 @@ |no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaObject.type] was found for parameter tag of method constructorTag in package scala.scalajs.js. |I found: | - | scala.scalajs.js.ConstructorTag.materialize[Nothing] + | scala.scalajs.js.ConstructorTag.materialize[T] | |But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaObject.type]. From f674c184d97966182b03dd79f0ee53c067860a65 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 May 2021 23:07:00 +0200 Subject: [PATCH 7/8] Reclassify test This was deemed too hard before for type inference, but it works now. --- tests/neg/i7056.check | 18 ------------------ tests/{neg => pos}/i7056.scala | 3 ++- 2 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 tests/neg/i7056.check rename tests/{neg => pos}/i7056.scala (84%) diff --git a/tests/neg/i7056.check b/tests/neg/i7056.check deleted file mode 100644 index 0f9a85f36321..000000000000 --- a/tests/neg/i7056.check +++ /dev/null @@ -1,18 +0,0 @@ --- [E007] Type Mismatch Error: tests/neg/i7056.scala:19:8 -------------------------------------------------------------- -19 |val z = x.idnt1 // error - | ^ - | Found: (given_PartialId_B : B) - | Required: PartialId[T] - | - | where: T is a type variable with constraint <: A - | - | - | Note: a match type could not be fully reduced: - | - | trying to reduce PartialId[T] - | failed since selector T - | matches none of the cases - | - | case B => T - -longer explanation available when compiling with `-explain` diff --git a/tests/neg/i7056.scala b/tests/pos/i7056.scala similarity index 84% rename from tests/neg/i7056.scala rename to tests/pos/i7056.scala index d16aa949000e..a347dfe7b519 100644 --- a/tests/neg/i7056.scala +++ b/tests/pos/i7056.scala @@ -16,4 +16,5 @@ given [T <: A](using PartialId[T]): T1[T] = new T1[T] { given PartialId[B] = ??? val x: B = ??? -val z = x.idnt1 // error +val z = x.idnt1 // used to be an error, now ok + From 8a2158c244222ef3b2b41b0f7e29556db0f75c7d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 25 May 2021 19:41:48 +0200 Subject: [PATCH 8/8] Add dependent function test --- tests/pos/depfun.scala | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/pos/depfun.scala diff --git a/tests/pos/depfun.scala b/tests/pos/depfun.scala new file mode 100644 index 000000000000..683b04b32e39 --- /dev/null +++ b/tests/pos/depfun.scala @@ -0,0 +1,17 @@ +// The following test is derived from scala/reflect/TypeTest.scala, but using +// a dependent function instead of a dependent SAM. It shows that the special treatment +// using a DependentTypeTree is not needed for plain function types. +// But for SAM types, the treatment is needed, otherwise TypeTest.scala does +// not typecheck. Todo: Figure out the reason for this difference. +object Test: + + type F[S, T] = (x: S) => Option[x.type & T] + + /** Trivial type test that always succeeds */ + def identity[T]: F[T, T] = Some(_) + + val x: 1 = 1 + val y = identity(x) + val z: Option[1] = y + +