From 7653e85f676f7a5d965b5ca879000954ad723f2a Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Fri, 22 Nov 2024 12:56:13 +0100 Subject: [PATCH 1/6] Delete duplicate inductive-implicits test This is a duplicate of `tests/bench/inductive-implicits.scala`, which is already tested from `dotty.tools.dotc.BootstrappedOnlyCompilationTest`, also without `-Yno-deep-subtypes`. --- .../inductive-implicits-bench.scala | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 tests/pos-deep-subtype/inductive-implicits-bench.scala diff --git a/tests/pos-deep-subtype/inductive-implicits-bench.scala b/tests/pos-deep-subtype/inductive-implicits-bench.scala deleted file mode 100644 index aff8bffd8024..000000000000 --- a/tests/pos-deep-subtype/inductive-implicits-bench.scala +++ /dev/null @@ -1,127 +0,0 @@ -// Adapted from https://github.com/scala/compiler-benchmark/blob/master/corpus/induction/latest/inductive-implicits-bench.scala - -// With polymorphic implicit pruning: -// set resolvers in compilation += "pr-scala snapshots" at "https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots/" -// set scalaVersion in compilation := "2.13.0-pre-765b3ed-SNAPSHOT" -// -// Without polymorphic implicit pruning: -// set resolvers in compilation += "scala-integration" at "https://scala-ci.typesafe.com/artifactory/scala-integration/" -// set scalaVersion in compilation := "2.13.0-pre-1c56f0a" -// -// Then: -// cold -psource=induction -jvmArgs -Xss4M -jvmArgs -Xmx2G -// -// Nb. this is *very* slow without the pruning (> 400s). -// With the pruning: 10-20s on reasonable hardware. - -package shapeless { - sealed trait HList extends Product with Serializable - - final case class ::[+H, +T <: HList](head : H, tail : T) extends HList { - def ::[HH](h : HH) : HH :: H :: T = shapeless.::(h, this) - - override def toString = head match { - case _: ::[_, _] => "("+head.toString+") :: "+tail.toString - case _ => head.toString+" :: "+tail.toString - } - } - - sealed trait HNil extends HList { - def ::[H](h : H) = shapeless.::(h, this) - override def toString = "HNil" - } - - case object HNil extends HNil - - //@annotation.inductive - trait Selector[L <: HList, U] { - def apply(l: L): U - } - - object Selector { - def apply[L <: HList, U](implicit selector: Selector[L, U]): Selector[L, U] = selector - - implicit def inHead[H, T <: HList]: Selector[H :: T, H] = - new Selector[H :: T, H] { - def apply(l : H :: T) = l.head - } - - implicit def inTail[H, T <: HList, U] - (implicit st : Selector[T, U]): Selector[H :: T, U] = - new Selector[H :: T, U] { - def apply(l : H :: T) = st(l.tail) - } - } -} - -import shapeless.* - -object Test extends App { - val sel = Selector[L, Boolean] - - type L = - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - /* - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: Int :: - // - */ - Boolean :: - HNil -} From d3b9d767a4f74457482e7d2c5ec9a9ef8d55b230 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Fri, 22 Nov 2024 12:38:05 +0100 Subject: [PATCH 2/6] Comment out 35 more lines in inductive-implicits To avoid reaching the stack limit. --- tests/bench/inductive-implicits.scala | 76 +++++++++++++-------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/bench/inductive-implicits.scala b/tests/bench/inductive-implicits.scala index 58714214ce33..09f147caef3e 100644 --- a/tests/bench/inductive-implicits.scala +++ b/tests/bench/inductive-implicits.scala @@ -174,49 +174,49 @@ object Test extends App { Int :: Int :: // - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: -// - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: -// - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: - Int :: -// - Int :: - Int :: - Int :: - Int :: - Int :: // Int :: // Int :: // Int :: // Int :: // Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// // +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// // +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// // +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: +// Int :: // // // Int :: // Int :: From 67024a914784d5a912ce1ac2715cfd332eab7f35 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Tue, 3 Dec 2024 15:28:09 +0100 Subject: [PATCH 3/6] Only trust the type application part for case class unapplies --- .../tools/dotc/transform/TypeTestsCasts.scala | 11 +++++------ tests/neg/i22051.scala | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tests/neg/i22051.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index c1dd6bc6509e..a8c8ec8ce1d8 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -56,7 +56,7 @@ object TypeTestsCasts { * 9. if `X` is `T1 | T2`, checkable(T1, P) && checkable(T2, P). * 10. otherwise, "" */ - def whyUncheckable(X: Type, P: Type, span: Span)(using Context): String = atPhase(Phases.refchecksPhase.next) { + def whyUncheckable(X: Type, P: Type, span: Span, trustTypeApplication: Boolean)(using Context): String = atPhase(Phases.refchecksPhase.next) { extension (inline s1: String) inline def &&(inline s2: String): String = if s1 == "" then s2 else s1 extension (inline b: Boolean) inline def |||(inline s: String): String = if b then "" else s @@ -143,7 +143,7 @@ object TypeTestsCasts { case defn.ArrayOf(tpE) => recur(tpE, tpT) case _ => recur(defn.AnyType, tpT) } - case tpe @ AppliedType(tycon, targs) => + case tpe @ AppliedType(tycon, targs) if !trustTypeApplication => X.widenDealias match { case OrType(tp1, tp2) => // This case is required to retrofit type inference, @@ -366,8 +366,7 @@ object TypeTestsCasts { if (sym.isTypeTest) { val argType = tree.args.head.tpe val isTrusted = tree.hasAttachment(PatternMatcher.TrustedTypeTestKey) - if !isTrusted then - checkTypePattern(expr.tpe, argType, expr.srcPos) + checkTypePattern(expr.tpe, argType, expr.srcPos, isTrusted) transformTypeTest(expr, argType, flagUnrelated = enclosingInlineds.isEmpty) // if test comes from inlined code, dont't flag it even if it always false } @@ -392,10 +391,10 @@ object TypeTestsCasts { def checkBind(tree: Bind)(using Context) = checkTypePattern(defn.ThrowableType, tree.body.tpe, tree.srcPos) - private def checkTypePattern(exprTpe: Type, castTpe: Type, pos: SrcPos)(using Context) = + private def checkTypePattern(exprTpe: Type, castTpe: Type, pos: SrcPos, trustTypeApplication: Boolean = false)(using Context) = val isUnchecked = exprTpe.widenTermRefExpr.hasAnnotation(defn.UncheckedAnnot) if !isUnchecked then - val whyNot = whyUncheckable(exprTpe, castTpe, pos.span) + val whyNot = whyUncheckable(exprTpe, castTpe, pos.span, trustTypeApplication) if whyNot.nonEmpty then report.uncheckedWarning(UncheckedTypePattern(castTpe, whyNot), pos) diff --git a/tests/neg/i22051.scala b/tests/neg/i22051.scala new file mode 100644 index 000000000000..ba6805a4e166 --- /dev/null +++ b/tests/neg/i22051.scala @@ -0,0 +1,19 @@ +//> using options -Werror + +def boundary[T](body: (T => RuntimeException) => T): T = + case class Break(value: T) extends RuntimeException + try body(Break.apply) + catch case Break(t) => t // error: pattern matching on local classes is unsound currently + +def test = + boundary[Int]: EInt => + val v: String = boundary[String]: EString => + throw EInt(3) + v.length // a runtime error: java.lang.ClassCastException + +def boundaryCorrectBehaviour[T](body: (T => RuntimeException) => T): T = + object local: + // A correct implementation, but is still treated as a local class right now + case class Break(value: T) extends RuntimeException + try body(local.Break.apply) + catch case local.Break(t) => t // error From a7b23d6f1890ce31cf52b72848b559d7873c4213 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Tue, 3 Dec 2024 16:11:36 +0100 Subject: [PATCH 4/6] Move test to warn --- tests/{neg => warn}/i22051.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) rename tests/{neg => warn}/i22051.scala (77%) diff --git a/tests/neg/i22051.scala b/tests/warn/i22051.scala similarity index 77% rename from tests/neg/i22051.scala rename to tests/warn/i22051.scala index ba6805a4e166..e1e902e16379 100644 --- a/tests/neg/i22051.scala +++ b/tests/warn/i22051.scala @@ -1,9 +1,7 @@ -//> using options -Werror - def boundary[T](body: (T => RuntimeException) => T): T = case class Break(value: T) extends RuntimeException try body(Break.apply) - catch case Break(t) => t // error: pattern matching on local classes is unsound currently + catch case Break(t) => t // warn: pattern matching on local classes is unsound currently def test = boundary[Int]: EInt => @@ -16,4 +14,4 @@ def boundaryCorrectBehaviour[T](body: (T => RuntimeException) => T): T = // A correct implementation, but is still treated as a local class right now case class Break(value: T) extends RuntimeException try body(local.Break.apply) - catch case local.Break(t) => t // error + catch case local.Break(t) => t // warn From 2ae14c270e7f8ec1d887fc851c79a236d1fd5661 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Wed, 8 Jan 2025 11:29:25 +0100 Subject: [PATCH 5/6] chore: add regression test for #22320 --- tests/neg/i22320.check | 12 ++++++++++++ tests/neg/i22320.scala | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/neg/i22320.check create mode 100644 tests/neg/i22320.scala diff --git a/tests/neg/i22320.check b/tests/neg/i22320.check new file mode 100644 index 000000000000..3bada9a0b73c --- /dev/null +++ b/tests/neg/i22320.check @@ -0,0 +1,12 @@ +-- [E008] Not Found Error: tests/neg/i22320.scala:19:19 ---------------------------------------------------------------- +19 | val z = system.z // error + | ^^^^^^^^ + | value z is not a member of a.System. + | An extension method was tried, but could not be fully constructed: + | + | a.z(system) + | + | failed with: + | + | Found: (system : a.System) + | Required: a.SimulatedSystem diff --git a/tests/neg/i22320.scala b/tests/neg/i22320.scala new file mode 100644 index 000000000000..4a9eccf08474 --- /dev/null +++ b/tests/neg/i22320.scala @@ -0,0 +1,19 @@ +package a: + opaque type System = Any + opaque type SimulatedSystem <: System = System + + extension (system: System) + def x: BigInt = ??? + def y: BigInt = ??? + end extension + + extension (system: SimulatedSystem) + def z: BigInt = ??? + end extension + +package b: + import a.* + def issue(system: System) = + val x = system.x + val y = system.y + val z = system.z // error \ No newline at end of file From 1f2a8354cf26a964797af2a5bd684485f68e78e2 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Wed, 8 Jan 2025 11:49:48 +0100 Subject: [PATCH 6/6] fix: align the spec to allow the marker --- docs/_spec/01-lexical-syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_spec/01-lexical-syntax.md b/docs/_spec/01-lexical-syntax.md index e1686204116e..b7fb455fc2fd 100644 --- a/docs/_spec/01-lexical-syntax.md +++ b/docs/_spec/01-lexical-syntax.md @@ -137,7 +137,7 @@ Otherwise, soft keywords are treated as actual keywords in the following situati - `as`, if it appears in a renaming import clause. - `derives`, if it appears after an extension clause or after the name and possibly parameters of a class, trait, object, or enum definition. - `end`, if it appears at the start of a line following a statement (i.e. definition or toplevel expression) and is followed on the same line by a single non-comment token that is: - - one of the keywords `for`, `given`, `if`, `match`, `new`, `this`, `throw`, `try`, `val`, `while`, or + - one of the keywords `for`, `given`, `if`, `match`, `new`, `this`, `throw`, `try`, `val`, `while`, `extension` or - an identifier. - `extension`, if it appears at the start of a statement and is followed by `(` or `[`. - `inline`, if it is followed by any token that can start an expression.