From e57e4c0313442db43e004eb415cd352b4ff82703 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Mar 2019 13:05:29 +0100 Subject: [PATCH 1/3] Fix typing of new Assume ``` class C[X] type A[X] = C[X] ``` The previous rule for `new A` overwrote the type of `A` with `C`, in order to satisfy the condition that the type of `new` should be a class type. Overwriting types like that in Typer is wrong, since it is not preserved by pickling. We tried to patch up things in RefinedPrinter, but this is not enough, as test case `alias-new.scala` shows. This test caused the type in a `new` to be unpickled as a . The fix is to treat eta-reduction in new types in a purely functional way, applied in both Typer and TypeAssigner. The problem was encountered when systematically testing creation methods, but it has nothing to do with them. --- .../src/dotty/tools/dotc/printing/RefinedPrinter.scala | 8 ++------ compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 10 +++++++++- compiler/src/dotty/tools/dotc/typer/Typer.scala | 8 ++------ tests/pos/alias-new.scala | 9 +++++++++ 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 tests/pos/alias-new.scala diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index b5cc53874251..e0e308c7fe5f 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -331,7 +331,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.hasType && tree.symbol == defn.QuotedExpr_splice) keywordStr("${") ~ toTextLocal(qual) ~ keywordStr("}") else if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}") else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name)) - else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR) + else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR || ctx.settings.YprintDebug.value) case tree: This => optDotPrefix(tree) ~ keywordStr("this") ~ idText(tree) case Super(qual: This, mix) => @@ -356,11 +356,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { keywordStr("new ") ~ { tpt match { case tpt: Template => toTextTemplate(tpt, ofNew = true) - case _ => - if (tpt.hasType) - toTextLocal(tpt.typeOpt.underlyingClassRef(refinementOK = false)) - else - toTextLocal(tpt) + case _ => toTextLocal(tpt) } } case Typed(expr, tpt) => diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 222db7012d53..78a80ee4cc91 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -301,8 +301,16 @@ trait TypeAssigner { ConstFold(tree.withType(tp)) } + /** Normalize type T appearing in a new T by following eta expansions to + * avoid higher-kinded types. + */ + def typeOfNew(tpt: Tree)(implicit ctx: Context): Type = tpt.tpe.dealias match { + case TypeApplications.EtaExpansion(tycon) => tycon + case t => tpt.tpe + } + def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context): New = - tree.withType(tpt.tpe) + tree.withType(typeOfNew(tpt)) def assignType(tree: untpd.Literal)(implicit ctx: Context): Literal = tree.withType { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 845dff35f8f2..0803a5b59005 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -533,11 +533,8 @@ class Typer extends Namer case _ => var tpt1 = typedType(tree.tpt) tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.sourcePos)) - tpt1.tpe.dealias match { - case TypeApplications.EtaExpansion(tycon) => tpt1 = tpt1.withType(tycon) - case _ => - } - if (checkClassType(tpt1.tpe, tpt1.sourcePos, traitReq = false, stablePrefixReq = true) eq defn.ObjectType) + + if (checkClassType(typeOfNew(tpt1), tpt1.sourcePos, traitReq = false, stablePrefixReq = true) eq defn.ObjectType) tpt1 = TypeTree(defn.ObjectType).withSpan(tpt1.span) tpt1 match { @@ -548,7 +545,6 @@ class Typer extends Namer } assignType(cpy.New(tree)(tpt1), tpt1) - // todo in a later phase: checkInstantiatable(cls, tpt1.pos) } } diff --git a/tests/pos/alias-new.scala b/tests/pos/alias-new.scala new file mode 100644 index 000000000000..4db37f3cde6e --- /dev/null +++ b/tests/pos/alias-new.scala @@ -0,0 +1,9 @@ +object O { + class B[T] +} +object O2 { + type B[T] = O.B[T] +} +object Test { + val x: O2.B[String] = new O2.B() +} \ No newline at end of file From ff63727108028ebacbdafde9e3b8c65269645418 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 18 Mar 2019 14:34:59 +0100 Subject: [PATCH 2/3] Fix HK new decompilation --- library/src/scala/tasty/reflect/Printers.scala | 8 ++++---- tests/run-with-compiler/i3847-b.check | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 4f0a749d94c2..27081a62e64c 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -593,8 +593,8 @@ trait Printers printParent(fun) if (!args.isEmpty || needEmptyParens) inParens(printTrees(args, ", ")) - case IsTerm(Term.Select(Term.New(tpt), _)) => - printTypeTree(tpt) + case IsTerm(Term.Select(Term.IsNew(newTree), _)) => + printType(newTree.tpe) case IsTerm(parent) => throw new MatchError(parent.show) } @@ -772,9 +772,9 @@ trait Printers } this += "this" - case Term.New(tpt) => + case Term.IsNew(tree) => this += "new " - printTypeTree(tpt) + printType(tree.tpe) case Term.NamedArg(name, arg) => this += name += " = " diff --git a/tests/run-with-compiler/i3847-b.check b/tests/run-with-compiler/i3847-b.check index 8158391f2453..4abe207a759e 100644 --- a/tests/run-with-compiler/i3847-b.check +++ b/tests/run-with-compiler/i3847-b.check @@ -1 +1 @@ -new scala.Array[scala.List[scala.Int]](1) +new scala.Array[scala.collection.immutable.List[scala.Int]](1) From 5b8753320a83e89a424b1c7ed7068d2d909444c8 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Tue, 19 Mar 2019 14:23:54 +0100 Subject: [PATCH 3/3] Add parens for clarity --- compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index e0e308c7fe5f..6dbdf681798e 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -331,7 +331,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.hasType && tree.symbol == defn.QuotedExpr_splice) keywordStr("${") ~ toTextLocal(qual) ~ keywordStr("}") else if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}") else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name)) - else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR || ctx.settings.YprintDebug.value) + else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided (name != nme.CONSTRUCTOR || ctx.settings.YprintDebug.value)) case tree: This => optDotPrefix(tree) ~ keywordStr("this") ~ idText(tree) case Super(qual: This, mix) =>