From 473dcb1b1174c2e585b1e2069cd7af2251f17415 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 26 Sep 2024 21:06:14 +0200 Subject: [PATCH 1/5] Allow opaque type def in repl [Cherry-picked a0db7c1ebf476cfdd1c0396b0ba1bd622e2d36b4] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 2fa0745ab98e..1e70cef04265 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -4389,6 +4389,8 @@ object Parsers { stats += closure(in.offset, Location.InBlock, modifiers(BitSet(IMPLICIT))) else if isIdent(nme.extension) && followingIsExtension() then stats += extension() + else if ctx.mode.is(Mode.Interactive) && isDefIntro(localModifierTokens) then + stats +++= localDef(in.offset) else if isDefIntro(localModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then stats +++= localDef(in.offset) else From 01264848ca9834f110880ebbb8b38f487b656901 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 4 Oct 2024 03:42:03 +0200 Subject: [PATCH 2/5] Only allow opaque type def at outermost [Cherry-picked 16ebbea25de6074ead7388c09434758c424700a6] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 4 ++-- compiler/src/dotty/tools/repl/ParseResult.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 1e70cef04265..082082db40aa 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -4377,7 +4377,7 @@ object Parsers { * | Expr1 * | */ - def blockStatSeq(): List[Tree] = checkNoEscapingPlaceholders { + def blockStatSeq(outermost: Boolean = false): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] while var empty = false @@ -4389,7 +4389,7 @@ object Parsers { stats += closure(in.offset, Location.InBlock, modifiers(BitSet(IMPLICIT))) else if isIdent(nme.extension) && followingIsExtension() then stats += extension() - else if ctx.mode.is(Mode.Interactive) && isDefIntro(localModifierTokens) then + else if outermost && ctx.mode.is(Mode.Interactive) && isDefIntro(localModifierTokens) then stats +++= localDef(in.offset) else if isDefIntro(localModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then stats +++= localDef(in.offset) diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index b9139343bca1..24a624173050 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -122,7 +122,7 @@ object ParseResult { private def parseStats(using Context): List[untpd.Tree] = { val parser = new Parser(ctx.source) - val stats = parser.blockStatSeq() + val stats = parser.blockStatSeq(outermost = true) parser.accept(Tokens.EOF) stats } From 2fa37be82ca2008ea33edcbe942d00a7fba9dd5c Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 11 Oct 2024 05:50:21 +0200 Subject: [PATCH 3/5] Add REPL test --- .../dotty/tools/repl/ReplCompilerTests.scala | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/compiler/test/dotty/tools/repl/ReplCompilerTests.scala b/compiler/test/dotty/tools/repl/ReplCompilerTests.scala index f09bdcd513be..9fe5ffcf072e 100644 --- a/compiler/test/dotty/tools/repl/ReplCompilerTests.scala +++ b/compiler/test/dotty/tools/repl/ReplCompilerTests.scala @@ -372,6 +372,34 @@ class ReplCompilerTests extends ReplTest: assertTrue(last, last.startsWith("val res0: tpolecat.type = null")) assertTrue(last, last.endsWith("""// result of "res0.toString" is null""")) + @Test def `i9879`: Unit = initially: + run { + """|opaque type A = Int; def getA: A = 0 + |object Wrapper { opaque type A = Int; def getA: A = 1 } + |val x = getA + |val y = Wrapper.getA""".stripMargin + } + val expected = List( + "def getA: A", + "// defined object Wrapper", + "val x: A = 0", + "val y: Wrapper.A = 1" + ) + assertEquals(expected, lines()) + + @Test def `i9879b`: Unit = initially: + run { + """|def test = + | type A = Int + | opaque type B = String + | object Wrapper { opaque type C = Int } + | ()""".stripMargin + } + val all = lines() + assertEquals(6, all.length) + assertTrue(all.head.startsWith("-- [E103] Syntax Error")) + assertTrue(all.exists(_.trim().startsWith("| Illegal start of statement: this modifier is not allowed here"))) + object ReplCompilerTests: private val pattern = Pattern.compile("\\r[\\n]?|\\n"); From 0059f14c731c921f75ad4ffdc0daefc6737f6458 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Thu, 13 Feb 2025 19:48:08 +0100 Subject: [PATCH 4/5] Add REPL test [Cherry-picked 634d9b79beae0e4098ef93affd25a5d761268e14][modified] From 88450806360536e8c0f7c3b77cf5db7c02e0a4ce Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 18 Oct 2024 10:44:58 +0200 Subject: [PATCH 5/5] Remove extra if [Cherry-picked 3a98a1cd3efd52fdb7e92f03d7d9ddc7f8ed3282] --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 082082db40aa..a4b3adbb7a00 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -4389,9 +4389,11 @@ object Parsers { stats += closure(in.offset, Location.InBlock, modifiers(BitSet(IMPLICIT))) else if isIdent(nme.extension) && followingIsExtension() then stats += extension() - else if outermost && ctx.mode.is(Mode.Interactive) && isDefIntro(localModifierTokens) then - stats +++= localDef(in.offset) - else if isDefIntro(localModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then + else if isDefIntro(localModifierTokens, + excludedSoftModifiers = + // Allow opaque definitions at outermost level in REPL. + if outermost && ctx.mode.is(Mode.Interactive) + then Set.empty else Set(nme.`opaque`)) then stats +++= localDef(in.offset) else empty = true