From f986cff95081067c9551282ca42bc3d6d284aeeb Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 28 May 2023 11:14:36 -0700 Subject: [PATCH 1/3] Add test with an anonymous self type --- .../scala/scala/meta/tests/parsers/ParseSuite.scala | 9 +++++---- .../scala/meta/tests/parsers/TemplateSuite.scala | 13 +++++++++++++ .../meta/tests/prettyprinters/TreeSyntaxSuite.scala | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala index e82bfc27d9..dc8c94edc9 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/ParseSuite.scala @@ -66,12 +66,13 @@ class ParseSuite extends TreeSuiteBase with CommonTrees { code: String, f: ScalametaParser => T, syntax: String = null - )(tree: Tree)(implicit loc: munit.Location): Unit = + )(tree: Tree)(implicit loc: munit.Location, dialect: Dialect): Unit = checkTree(parseRule(code, f), syntax)(tree) - protected def checkStat(code: String, syntax: String = null)(tree: Tree)( - implicit loc: munit.Location - ): Unit = + protected def checkStat( + code: String, + syntax: String = null + )(tree: Tree)(implicit loc: munit.Location, dialect: Dialect): Unit = checkParsedTree(code, _.entrypointStat(), syntax)(tree) protected def runTestError[T <: Tree]( diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala index 79c60a6450..a4ee9c2664 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala @@ -382,4 +382,17 @@ class TemplateSuite extends ParseSuite { assertNoDiff(err.shortMessage, "class type required but A.type found") } + test("#3142: template with anonymous self type") { + val code = "class foo { _: Int => }" + val syntax = "class foo { : Int => }" + val tree = Defn.Class( + Nil, + Type.Name("foo"), + Nil, + Ctor.Primary(Nil, Name(""), Nil), + Template(Nil, Nil, Self(Name(""), Some(Type.Name("Int"))), Nil, Nil) + ) + checkStat(code, syntax)(tree) + } + } diff --git a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala index aaecb82fb4..74d275d4c7 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala @@ -58,6 +58,7 @@ class TreeSyntaxSuite extends scala.meta.tests.parsers.ParseSuite { testBlockAfterDef(k => testBlockAddNL(s"$k foo: Int")) testBlockNoNL("class foo { self => }") + testBlockNoNL("class foo { _: Int => }", "class foo { : Int => }") testBlockNoNL("type foo") testBlockAfterDef(k => testBlockAddNL(s"$k foo: Int = 1")) testBlockAfterDef(k => testBlockNoNL(s"$k foo: Int = {1}", s"$k foo: Int = {\n 1\n}")) From 5eec2cbe9b76f055e601f9eb2d2d6fb408bc8eb3 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 28 May 2023 12:35:17 -0700 Subject: [PATCH 2/3] Trees: add methods checking if Self is empty --- .../scala/meta/internal/parsers/ScalametaParser.scala | 2 +- .../trees/shared/src/main/scala/scala/meta/Trees.scala | 5 ++++- .../meta/internal/prettyprinters/TreeSyntax.scala | 10 ++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala index 3204cdea13..a660c9a44f 100644 --- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala +++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala @@ -4108,7 +4108,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser => if (isAfterOptNewLine[LeftBrace]) { // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(enumCaseAllowed) - if (token.is[KwWith] && self.name.is[Name.Anonymous] && self.decltpe.isEmpty) { + if (token.is[KwWith] && self.isEmpty) { val edefs = body.map(ensureEarlyDef) next() val parents = templateParents(afterExtend) diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala b/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala index aed3790709..116e4bfaeb 100644 --- a/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala +++ b/scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala @@ -440,6 +440,7 @@ object Pat { @branch trait Member extends Tree { def name: Name + final def isNameAnonymous: Boolean = name.is[Name.Anonymous] } object Member { @branch trait Term extends Member { @@ -837,7 +838,9 @@ object Ctor { @replacedField("4.6.0") final def argss: List[List[Term]] = argClauses.map(_.values).toList } -@ast class Self(name: Name, decltpe: Option[Type]) extends Member with Tree.WithDeclTpeOpt +@ast class Self(name: Name, decltpe: Option[Type]) extends Member with Tree.WithDeclTpeOpt { + final def isEmpty: Boolean = isNameAnonymous && decltpe.isEmpty +} @ast class Template( early: List[Stat], diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala index 06af43702b..3cdcac7ec9 100644 --- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala +++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala @@ -518,10 +518,8 @@ object TreeSyntax { case t: Term.New => m(SimpleExpr, s(kw("new"), " ", t.init)) case t: Term.EndMarker => s(kw("end"), " ", t.name.value) case t: Term.NewAnonymous => - val needsExplicitBraces = { - val selfIsEmpty = t.templ.self.name.is[Name.Anonymous] && t.templ.self.decltpe.isEmpty - t.templ.early.isEmpty && t.templ.inits.length < 2 && selfIsEmpty && t.templ.stats.isEmpty - } + val needsExplicitBraces = t.templ.early.isEmpty && t.templ.inits.lengthCompare(2) < 0 && + t.templ.self.isEmpty && t.templ.stats.isEmpty m(SimpleExpr, s(kw("new"), " ", t.templ), w(" {", "", "}", needsExplicitBraces)) case _: Term.Placeholder => m(SimpleExpr1, kw("_")) case t: Term.Eta => m(PostfixExpr, s(p(SimpleExpr1, t.expr), " ", kw("_"))) @@ -916,7 +914,7 @@ object TreeSyntax { // Template case t: Template => - val isSelfEmpty = t.self.name.is[Name.Anonymous] && t.self.decltpe.isEmpty + val isSelfEmpty = t.self.isEmpty val useExtends = (t.inits.nonEmpty || t.early.nonEmpty) && t.parent.exists(p => p.isNot[Defn.Given] && p.isNot[Term.NewAnonymous]) val extendsKeyword = if (useExtends) "extends" else "" @@ -1061,7 +1059,7 @@ object TreeSyntax { private def isUsingOrImplicit(m: Mod): Boolean = m.is[Mod.ParamsType] private def printParam(t: Term.Param, keepImplicit: Boolean = false): Show.Result = { val mods = if (keepImplicit) t.mods else t.mods.filterNot(isUsingOrImplicit) - val nameType = if (t.name.is[Name.Anonymous]) { + val nameType = if (t.isNameAnonymous) { o(t.decltpe) } else { s(t.name, t.decltpe) From 15c79373b2e57ace501c0f224db2fe29749bbe11 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sun, 28 May 2023 12:24:30 -0700 Subject: [PATCH 3/3] TreeSyntax: fix half-empty Self --- .../scala/scala/meta/internal/prettyprinters/TreeSyntax.scala | 4 +++- .../test/scala/scala/meta/tests/parsers/TemplateSuite.scala | 3 +-- .../scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala index 3cdcac7ec9..dc99663385 100644 --- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala +++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala @@ -910,7 +910,9 @@ object TreeSyntax { ) // Self - case t: Self => s(t.name, t.decltpe) + case t: Self => + if (t.isNameAnonymous && t.decltpe.nonEmpty) s("_", t.decltpe) + else s(t.name, t.decltpe) // Template case t: Template => diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala index a4ee9c2664..6d1893bace 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala @@ -384,7 +384,6 @@ class TemplateSuite extends ParseSuite { test("#3142: template with anonymous self type") { val code = "class foo { _: Int => }" - val syntax = "class foo { : Int => }" val tree = Defn.Class( Nil, Type.Name("foo"), @@ -392,7 +391,7 @@ class TemplateSuite extends ParseSuite { Ctor.Primary(Nil, Name(""), Nil), Template(Nil, Nil, Self(Name(""), Some(Type.Name("Int"))), Nil, Nil) ) - checkStat(code, syntax)(tree) + checkStat(code, code)(tree) } } diff --git a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala index 74d275d4c7..26d5094c1d 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/TreeSyntaxSuite.scala @@ -58,7 +58,7 @@ class TreeSyntaxSuite extends scala.meta.tests.parsers.ParseSuite { testBlockAfterDef(k => testBlockAddNL(s"$k foo: Int")) testBlockNoNL("class foo { self => }") - testBlockNoNL("class foo { _: Int => }", "class foo { : Int => }") + testBlockNoNL("class foo { _: Int => }") testBlockNoNL("type foo") testBlockAfterDef(k => testBlockAddNL(s"$k foo: Int = 1")) testBlockAfterDef(k => testBlockNoNL(s"$k foo: Int = {1}", s"$k foo: Int = {\n 1\n}"))