From d63e19b121b3d5aee811a8394d68c46e843286d3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 7 Feb 2022 10:17:19 +0100 Subject: [PATCH 1/5] Revert replacement in `trace` `trace` is made for multi-line output, since it has to show large parts of programs accurately. Replacing newline with space does not work here. It messes up the layout and changes the meaning of code. --- compiler/src/dotty/tools/dotc/reporting/trace.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/trace.scala b/compiler/src/dotty/tools/dotc/reporting/trace.scala index 804188b20780..10179f9d3789 100644 --- a/compiler/src/dotty/tools/dotc/reporting/trace.scala +++ b/compiler/src/dotty/tools/dotc/reporting/trace.scala @@ -76,7 +76,7 @@ trait TraceSyntax: else // Avoid evaluating question multiple time, since each evaluation // may cause some extra logging output. - val q = question.replace('\n', ' ') + val q = question val leading = s"==> $q?" val trailing = (res: T) => s"<== $q = ${showOp(res)}" var finalized = false From 1ecdddce6951f6a46cce86159ff0e1b3a56bf085 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Feb 2022 11:25:21 +0100 Subject: [PATCH 2/5] Fix TreeTypeMap to correctly substitute parameters Fix TreeTypeMap to correctly substitute parameters when copying local class members. Fixes #12508 --- .../src/dotty/tools/dotc/ast/TreeTypeMap.scala | 14 +++++++++++++- tests/pos/i12508.scala | 8 ++++++++ tests/pos/i12508a.scala | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i12508.scala create mode 100644 tests/pos/i12508a.scala diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index d38ce8ca6888..74da63f7d7da 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -204,11 +204,23 @@ class TreeTypeMap( lazy val origCls = mapped.zip(syms).filter(_._1.isClass).toMap mapped.filter(_.isClass).foldLeft(substMap) { (tmap, cls) => val origDcls = cls.info.decls.toList.filterNot(_.is(TypeParam)) - val mappedDcls = mapSymbols(origDcls, tmap, mapAlways = true) + val tmap0 = tmap.withSubstitution(origCls(cls).typeParams, cls.typeParams) + val mappedDcls = mapSymbols(origDcls, tmap0, mapAlways = true) val tmap1 = tmap.withMappedSyms( origCls(cls).typeParams ::: origDcls, cls.typeParams ::: mappedDcls) origDcls.lazyZip(mappedDcls).foreach(cls.asClass.replace) tmap1 } + + override def toString = + def showSyms(syms: List[Symbol]) = + syms.map(sym => s"$sym#${sym.id}").mkString(", ") + s"""TreeTypeMap( + |typeMap = $typeMap + |treeMap = $treeMap + |oldOwners = ${showSyms(oldOwners)} + |newOwners = ${showSyms(newOwners)} + |substFrom = ${showSyms(substFrom)} + |substTo = ${showSyms(substTo)}""".stripMargin } diff --git a/tests/pos/i12508.scala b/tests/pos/i12508.scala new file mode 100644 index 000000000000..cb5e118f1d44 --- /dev/null +++ b/tests/pos/i12508.scala @@ -0,0 +1,8 @@ +class Test { + inline def test(fun: Any): Any = ??? + test { + class Foo[X]: + def x: X = ??? + def foo: Unit = this.x.toString + } +} \ No newline at end of file diff --git a/tests/pos/i12508a.scala b/tests/pos/i12508a.scala new file mode 100644 index 000000000000..fa1a77f9021f --- /dev/null +++ b/tests/pos/i12508a.scala @@ -0,0 +1,14 @@ +def fun(a: Any, b: Any = 2): Any = ??? +def test = + fun( + b = println(1), + a = { + class Foo[X]: + def x: X = ??? + def foo: Unit = this.x.toString + locally { + def x: X = ??? + println(x.toString) + } + } + ) \ No newline at end of file From 30ed58a24edb28637c88a0abee21ead8c367b5a4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Feb 2022 11:32:19 +0100 Subject: [PATCH 3/5] Add original test and test with sealed class hierarchy --- tests/pos/i12508.scala | 9 +++++++++ tests/pos/i12508b.scala | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/pos/i12508b.scala diff --git a/tests/pos/i12508.scala b/tests/pos/i12508.scala index cb5e118f1d44..896801559177 100644 --- a/tests/pos/i12508.scala +++ b/tests/pos/i12508.scala @@ -5,4 +5,13 @@ class Test { def x: X = ??? def foo: Unit = this.x.toString } +} +class Test2 { + inline def test(fun: => Any): Any = fun + test { + case class Pair[X, Y]( + x: X, + y: Y, + ) + } } \ No newline at end of file diff --git a/tests/pos/i12508b.scala b/tests/pos/i12508b.scala new file mode 100644 index 000000000000..f1d4836dc380 --- /dev/null +++ b/tests/pos/i12508b.scala @@ -0,0 +1,13 @@ +def fun(a: Any, b: Any = 2): Any = ??? +def test = + fun( + b = println(1), + a = { + sealed class Foo[X]: + def x: X = ??? + def foo: Unit = this.x.toString + class Bar extends Foo[String] + class Baz[Y] extends Foo[Y] + if ??? then Bar() else Baz[Int] + } + ) \ No newline at end of file From c86fb4fc9a88ff93f948cae8a077f69733700430 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Feb 2022 20:20:25 +0100 Subject: [PATCH 4/5] Don't re-type imports. TreeCheck fails if imports are in code that needs a change owner. --- compiler/src/dotty/tools/dotc/typer/ReTyper.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 85be8c32227a..7dcaa85d529a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -52,6 +52,9 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking override def typedSuper(tree: untpd.Super, pt: Type)(using Context): Tree = promote(tree) + override def typedImport(tree: untpd.Import, sym: Symbol)(using Context): Tree = + promote(tree) + override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree = { assertTyped(tree) From e0ff75d7e3d609087990f77f5f1046d34ee5bb7e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Feb 2022 20:21:35 +0100 Subject: [PATCH 5/5] Properly map children of mapped classes If sealed classes are mapped in TypeTreeMap or mapSymbols, their children have to be mapped accordingly. --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 10 +++++++++- .../dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- .../tools/dotc/transform/SyntheticMembers.scala | 2 +- tests/pos/i12508c.scala | 12 ++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i12508c.scala diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 7f0969d55f07..93255f8d757d 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -826,11 +826,19 @@ object Symbols { copy.info = completer copy.denot match case cd: ClassDenotation => - cd.registeredCompanion = cd.unforcedRegisteredCompanion.subst(originals, copies) + cd.registeredCompanion = original.registeredCompanion.subst(originals, copies) case _ => } copies.foreach(_.ensureCompleted()) // avoid memory leak + + // Update Child annotations of classes encountered previously to new values + // if some child is among the mapped symbols + for orig <- ttmap1.substFrom do + if orig.is(Sealed) && orig.children.exists(originals.contains) then + val sealedCopy = orig.subst(ttmap1.substFrom, ttmap1.substTo) + sealedCopy.annotations = sealedCopy.annotations.mapConserve(ttmap1.apply) + copies } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index cf5942a178f0..23c7f3b0e3e0 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -1040,7 +1040,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else if (sym.is(ModuleClass) && sym.isPackageObject && sym.name.stripModuleClassSuffix == tpnme.PACKAGE) nameString(sym.owner.name) else if (sym.is(ModuleClass)) - nameString(sym.name.stripModuleClassSuffix) + nameString(sym.name.stripModuleClassSuffix) + idString(sym) else if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym) else diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 3a94a78b3d8e..eb6fc2feff7e 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -140,7 +140,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { val parentEnum = vdef.owner.companionClass val children = parentEnum.children.zipWithIndex val candidate: Option[Int] = children.collectFirst { case (child, idx) if child == vdef => idx } - assert(candidate.isDefined, i"could not find child for $vdef") + assert(candidate.isDefined, i"could not find child for $vdef in ${parentEnum.children}%, % of $parentEnum") Literal(Constant(candidate.get)) def toStringBody(vrefss: List[List[Tree]]): Tree = diff --git a/tests/pos/i12508c.scala b/tests/pos/i12508c.scala new file mode 100644 index 000000000000..97c81cd61fcd --- /dev/null +++ b/tests/pos/i12508c.scala @@ -0,0 +1,12 @@ +def fun(a: Any, b: Any = 2): Any = ??? + +def test = + fun( + b = println(1), + a = { + enum Option[+X]: + case Some(x: X) + case None + if ??? then Option.Some(1) else Option.None + } + ) \ No newline at end of file