Skip to content

Commit

Permalink
Merge pull request #3614 from kitbellew/3610
Browse files Browse the repository at this point in the history
Support quoted type variables in Dialect and ScalametaParser
  • Loading branch information
kitbellew committed Mar 7, 2024
2 parents eab853f + 3e44535 commit 6cb9294
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 3 deletions.
12 changes: 12 additions & 0 deletions scalameta/dialects/shared/src/main/scala/scala/meta/Dialect.scala
Expand Up @@ -110,6 +110,8 @@ final class Dialect private[meta] (
val allowInfixMods: Boolean,
// Scala 3 splices/quotes
val allowSpliceAndQuote: Boolean,
// https://docs.scala-lang.org/sips/quote-pattern-type-variable-syntax.html
val allowQuotedTypeVariables: Boolean,
// Scala 3 disallowed symbol literals
val allowSymbolLiterals: Boolean,
// Scala 3 disallowed symbol literals
Expand Down Expand Up @@ -235,6 +237,7 @@ final class Dialect private[meta] (
allowTypeMatch = false,
allowInfixMods = false,
allowSpliceAndQuote = false,
allowQuotedTypeVariables = false,
allowSymbolLiterals = true,
allowDependentFunctionTypes = false,
allowPostfixStarVarargSplices = false,
Expand Down Expand Up @@ -409,6 +412,9 @@ final class Dialect private[meta] (
def withAllowSpliceAndQuote(newValue: Boolean): Dialect = {
privateCopy(allowSpliceAndQuote = newValue)
}
def withAllowQuotedTypeVariables(newValue: Boolean): Dialect = {
privateCopy(allowQuotedTypeVariables = newValue)
}
def withAllowSymbolLiterals(newValue: Boolean): Dialect = {
privateCopy(allowSymbolLiterals = newValue)
}
Expand Down Expand Up @@ -524,6 +530,7 @@ final class Dialect private[meta] (
allowTypeMatch: Boolean = this.allowTypeMatch,
allowInfixMods: Boolean = this.allowInfixMods,
allowSpliceAndQuote: Boolean = this.allowSpliceAndQuote,
allowQuotedTypeVariables: Boolean = this.allowQuotedTypeVariables,
allowSymbolLiterals: Boolean = this.allowSymbolLiterals,
allowDependentFunctionTypes: Boolean = this.allowDependentFunctionTypes,
allowPostfixStarVarargSplices: Boolean = this.allowPostfixStarVarargSplices,
Expand Down Expand Up @@ -585,6 +592,7 @@ final class Dialect private[meta] (
allowTypeMatch = allowTypeMatch,
allowInfixMods = allowInfixMods,
allowSpliceAndQuote = allowSpliceAndQuote,
allowQuotedTypeVariables = allowQuotedTypeVariables,
allowSymbolLiterals = allowSymbolLiterals,
allowDependentFunctionTypes = allowDependentFunctionTypes,
allowPostfixStarVarargSplices = allowPostfixStarVarargSplices,
Expand Down Expand Up @@ -648,6 +656,7 @@ final class Dialect private[meta] (
allowTypeMatch = allowTypeMatch,
allowInfixMods = allowInfixMods,
allowSpliceAndQuote = allowSpliceAndQuote,
allowQuotedTypeVariables = allowQuotedTypeVariables,
allowSymbolLiterals = allowSymbolLiterals,
allowDependentFunctionTypes = allowDependentFunctionTypes,
allowPostfixStarVarargSplices = allowPostfixStarVarargSplices,
Expand Down Expand Up @@ -736,6 +745,7 @@ final class Dialect private[meta] (
allowTypeMatch: Boolean,
allowInfixMods: Boolean,
allowSpliceAndQuote: Boolean,
allowQuotedTypeVariables: Boolean,
allowSymbolLiterals: Boolean,
allowDependentFunctionTypes: Boolean,
allowPostfixStarVarargSplices: Boolean,
Expand Down Expand Up @@ -795,6 +805,7 @@ final class Dialect private[meta] (
&& this.allowTypeMatch == allowTypeMatch
&& this.allowInfixMods == allowInfixMods
&& this.allowSpliceAndQuote == allowSpliceAndQuote
&& this.allowQuotedTypeVariables == allowQuotedTypeVariables
&& this.allowSymbolLiterals == allowSymbolLiterals
&& this.allowDependentFunctionTypes == allowDependentFunctionTypes
&& this.allowPostfixStarVarargSplices == allowPostfixStarVarargSplices
Expand Down Expand Up @@ -857,6 +868,7 @@ final class Dialect private[meta] (
allowTypeMatch = that.allowTypeMatch,
allowInfixMods = that.allowInfixMods,
allowSpliceAndQuote = that.allowSpliceAndQuote,
allowQuotedTypeVariables = that.allowQuotedTypeVariables,
allowSymbolLiterals = that.allowSymbolLiterals,
allowDependentFunctionTypes = that.allowDependentFunctionTypes,
allowPostfixStarVarargSplices = that.allowPostfixStarVarargSplices,
Expand Down
Expand Up @@ -153,6 +153,7 @@ package object dialects {
.withAllowParamClauseInterleaving(true)

implicit val Scala34: Dialect = Scala33
.withAllowQuotedTypeVariables(true)

implicit val Scala3: Dialect = Scala34

Expand Down
Expand Up @@ -849,6 +849,23 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
}).getOrElse(t)
}

def typeBlock(): Type =
// TypeBlock, https://dotty.epfl.ch/docs/internals/syntax.html#expressions-3
if (dialect.allowQuotedTypeVariables && token.is[KwType]) autoPos {
val typeDefs = listBy[Stat.TypeDef] { buf =>
@tailrec def iter(): Unit = {
buf += typeDefOrDcl(Nil)
if (StatSep(token)) {
next()
if (token.is[KwType]) iter()
}
}
iter()
}
Type.Block(typeDefs, typ())
}
else typ()

private def typeFuncOnArrow(
paramPos: Int,
params: List[Type],
Expand Down Expand Up @@ -2297,7 +2314,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
next()
token match {
case _: LeftBrace => Term.QuotedMacroExpr(autoPos(inBracesOnOpen(blockWithinDelims())))
case _: LeftBracket => Term.QuotedMacroType(inBracketsOnOpen(typ()))
case _: LeftBracket => Term.QuotedMacroType(inBracketsOnOpen(typeBlock()))
case t => syntaxError("Quotation only works for expressions and types", at = t)
}
})
Expand Down Expand Up @@ -2982,6 +2999,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
* initiated from non-pattern context.
*/
def typ() = outPattern.typ()
private def typeBlock() = outPattern.typeBlock()
def typeIndentedOpt() = outPattern.typeIndentedOpt()
def quasiquoteType() = outPattern.quasiquoteType()
def entrypointType() = outPattern.entrypointType()
Expand Down
3 changes: 3 additions & 0 deletions scalameta/trees/shared/src/main/scala/scala/meta/Trees.scala
Expand Up @@ -424,6 +424,9 @@ object Type {
@ast class ParamClause(values: List[Param]) extends Member.ParamClause

@ast class Match(tpe: Type, cases: List[TypeCase] @nonEmpty) extends Type with Tree.WithCases

@ast class Block(typeDefs: List[Stat.TypeDef], tpe: Type) extends Type

def fresh(): Type.Name = fresh("fresh")
def fresh(prefix: String): Type.Name = Type.Name(prefix + Fresh.nextId())
}
Expand Down
Expand Up @@ -705,6 +705,7 @@ object TreeSyntax {
}
val cbounds = r(t.cbounds.map { s(kw(":"), " ", _) })
s(w(mods, " "), variance, t.name, t.tparamClause, tbounds, vbounds, cbounds)
case t: Type.Block => s(w(r(t.typeDefs, "; "), "; "), t.tpe)

// Pat
case t: Pat.Var =>
Expand Down
Expand Up @@ -469,6 +469,7 @@ class SurfaceSuite extends FunSuite {
|scala.meta.Type.Apply
|scala.meta.Type.ApplyInfix
|scala.meta.Type.ArgClause
|scala.meta.Type.Block
|scala.meta.Type.Bounds
|scala.meta.Type.ByName
|scala.meta.Type.ContextFunction
Expand Down
Expand Up @@ -24,7 +24,7 @@ class ReflectionSuite extends FunSuite {
val sym = symbolOf[scala.meta.Tree]
assert(sym.isRoot)
val root = sym.asRoot
assertEquals((root.allBranches.length, root.allLeafs.length), (50, 408))
assertEquals((root.allBranches.length, root.allLeafs.length), (50, 410))
}

test("If") {
Expand Down Expand Up @@ -98,6 +98,7 @@ class ReflectionSuite extends FunSuite {
|List[scala.meta.Mod]
|List[scala.meta.Pat]
|List[scala.meta.Source]
|List[scala.meta.Stat.TypeDef]
|List[scala.meta.Stat]
|List[scala.meta.Term.Name]
|List[scala.meta.Term.Param]
Expand Down
Expand Up @@ -440,4 +440,32 @@ class MacroSuite extends BaseDottySuite {
)
)
}

test("#3610 1") {
val code = "'[ List[Int] ]"
val tree = Term.QuotedMacroType(Type.Apply(pname("List"), List(pname("Int"))))
runTestAssert[Stat](code)(tree)
}

test("#3610 2") {
val code = "'[ type t = Int; List[t] ]"
val tree = Term.QuotedMacroType(
Type.Block(
List(Defn.Type(Nil, pname("t"), Nil, pname("Int"), noBounds)),
Type.Apply(pname("List"), List(pname("t")))
)
)
runTestAssert[Stat](code)(tree)
}

test("#3610 3") {
val code = "'[ type tail <: Tuple; *:[Int, tail] ]"
val tree = Term.QuotedMacroType(
Type.Block(
List(Decl.Type(Nil, pname("tail"), Nil, bounds(hi = "Tuple"))),
Type.Apply(pname("*:"), List(pname("Int"), pname("tail")))
)
)
runTestAssert[Stat](code)(tree)
}
}
Expand Up @@ -109,7 +109,7 @@ class PublicSuite extends TreeSuiteBase {
}

test("scala.meta.dialects.Scala33.toString") {
assertNoDiff(scala.meta.dialects.Scala33.toString, "Scala34")
assertNoDiff(scala.meta.dialects.Scala33.toString, "Scala33")
}

test("scala.meta.dialects.Scala34.toString") {
Expand Down
Expand Up @@ -2064,4 +2064,19 @@ class SyntacticSuite extends scala.meta.tests.parsers.ParseSuite {
)
}

test("#3610 Type.Block 1") {
val tree = Type.Block(Nil, pname("Int"))
assertEquals(tree.syntax, "Int")
}

test("#3610 Type.Block 2") {
val tree = Type.Block(List(Decl.Type(Nil, pname("t"), Nil, noBounds)), pname("t"))
assertEquals(tree.syntax, "type t; t")
}

test("#3610 Type.Block 3") {
val tree = Type.Block(List(Defn.Type(Nil, pname("t"), Nil, pname("Int"))), pname("t"))
assertEquals(tree.syntax, "type t = Int; t")
}

}

0 comments on commit 6cb9294

Please sign in to comment.