From e4a9f0664ffc316c04c30a98636a4fd253415cbe Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 16 Jul 2025 18:58:21 +0200 Subject: [PATCH 1/3] Add missing case to TypeComparer We now have: x.type^{x} <: x.type --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 1 + tests/neg-custom-args/captures/i23207.check | 7 ------- tests/neg-custom-args/captures/i23207.scala | 4 +++- tests/pos-custom-args/captures/singleton-conformance.scala | 6 ++++++ 4 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 tests/pos-custom-args/captures/singleton-conformance.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index f1b829828319..d675bda73eed 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -547,6 +547,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling if tp2.isAny then true else if compareCaptures(tp1, refs1, tp2, tp2.captureSet) || !ctx.mode.is(Mode.CheckBoundsOrSelfType) && tp1.isAlwaysPure + || parent1.isSingleton && refs1.elems.forall(parent1 eq _) then val tp2a = if tp1.isBoxedCapturing && !parent1.isBoxedCapturing diff --git a/tests/neg-custom-args/captures/i23207.check b/tests/neg-custom-args/captures/i23207.check index 48285e55bc11..df7c0572341e 100644 --- a/tests/neg-custom-args/captures/i23207.check +++ b/tests/neg-custom-args/captures/i23207.check @@ -5,10 +5,3 @@ | Required: A | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:16:11 --------------------------------------- -16 | b.getBox.x // error - | ^^^^^^^^^^ - | Found: (Box[(b : B^{io})^{b}]#x : (b : B^{io})^{b}) - | Required: A^? - | - | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/i23207.scala b/tests/neg-custom-args/captures/i23207.scala index 37246d610ea9..736482927987 100644 --- a/tests/neg-custom-args/captures/i23207.scala +++ b/tests/neg-custom-args/captures/i23207.scala @@ -13,4 +13,6 @@ def leak(io: AnyRef^): A = val b = new B val box = b.getBox val a: A = box.x // error - b.getBox.x // error \ No newline at end of file + val c = b.getBox.x // now OK + val _: B^{b} = c + c \ No newline at end of file diff --git a/tests/pos-custom-args/captures/singleton-conformance.scala b/tests/pos-custom-args/captures/singleton-conformance.scala new file mode 100644 index 000000000000..7858e2adee2c --- /dev/null +++ b/tests/pos-custom-args/captures/singleton-conformance.scala @@ -0,0 +1,6 @@ +import language.experimental.captureChecking + +def id[T](x: T): T = x + +trait A: + def t(): this.type = id(this) \ No newline at end of file From 6b61b01209044c8faded133018ac9e1bf04eed35 Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 17 Jul 2025 17:26:55 +0200 Subject: [PATCH 2/3] Update test --- tests/neg-custom-args/captures/i23207.check | 18 ++++++++++++++++++ tests/neg-custom-args/captures/i23207.scala | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tests/neg-custom-args/captures/i23207.check b/tests/neg-custom-args/captures/i23207.check index df7c0572341e..78a5406ce03d 100644 --- a/tests/neg-custom-args/captures/i23207.check +++ b/tests/neg-custom-args/captures/i23207.check @@ -5,3 +5,21 @@ | Required: A | | longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:18:13 --------------------------------------- +18 | val _: A = c // error + | ^ + | Found: (c : B^{b}) + | Required: A + | + | longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:23:2 ---------------------------------------- +23 | class B extends A: // error, now we see the error for the whole block since there are no nested errors + | ^ + | Found: A^{io} + | Required: A +24 | val hide: AnyRef^{io} = io +25 | val b = new B +26 | val c = b.getBox.x +27 | c + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/i23207.scala b/tests/neg-custom-args/captures/i23207.scala index 736482927987..36402944d393 100644 --- a/tests/neg-custom-args/captures/i23207.scala +++ b/tests/neg-custom-args/captures/i23207.scala @@ -13,6 +13,16 @@ def leak(io: AnyRef^): A = val b = new B val box = b.getBox val a: A = box.x // error - val c = b.getBox.x // now OK - val _: B^{b} = c - c \ No newline at end of file + val c = b.getBox.x + val _: B^{b} = c // ok + val _: A = c // error + c // no error here since we don't propagate expected type into the last expression of a block + // and the whole block's span overlaps with previous errors + +def leak2(io: AnyRef^): A = + class B extends A: // error, now we see the error for the whole block since there are no nested errors + val hide: AnyRef^{io} = io + + val b = new B + val c = b.getBox.x + c From f93c18e05a862ec65b1555367dc847514563b71a Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 17 Jul 2025 15:37:48 +0200 Subject: [PATCH 3/3] Fix no-patches test The previous version failed in the "Scala-3 with Capture Checking" test. --- tests/neg/no-patches.check | 6 +++--- tests/neg/no-patches.scala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/neg/no-patches.check b/tests/neg/no-patches.check index 69428b83905d..2636c9bbd04a 100644 --- a/tests/neg/no-patches.check +++ b/tests/neg/no-patches.check @@ -3,9 +3,9 @@ | ^^^^^^^^^^^^^^^^^^^^ | value 3.4 is not a member of object language -- [E008] Not Found Error: tests/neg/no-patches.scala:4:36 ------------------------------------------------------------- -4 |val _ = scala.language.experimental.captureChecking // error: we do not patch `scala.language.experimental` - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | value captureChecking is not a member of object language.experimental +4 |val _ = scala.language.experimental.modularity // error: we do not patch `scala.language.experimental` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | value modularity is not a member of object language.experimental -- [E008] Not Found Error: tests/neg/no-patches.scala:5:15 ------------------------------------------------------------- 5 |val _ = Predef.summon[DummyImplicit] // error: we do not patch `scala.Predef` | ^^^^^^^^^^^^^ diff --git a/tests/neg/no-patches.scala b/tests/neg/no-patches.scala index 9e36d0a84d88..a07d9836412a 100644 --- a/tests/neg/no-patches.scala +++ b/tests/neg/no-patches.scala @@ -1,5 +1,5 @@ //> using options -Yno-stdlib-patches val _ = scala.language.`3.4` // error: we do not patch `scala.language` -val _ = scala.language.experimental.captureChecking // error: we do not patch `scala.language.experimental` +val _ = scala.language.experimental.modularity // error: we do not patch `scala.language.experimental` val _ = Predef.summon[DummyImplicit] // error: we do not patch `scala.Predef`