Skip to content

Commit 75f7c1d

Browse files
committed
Add ParamClause to allow multiple type param clauses
Reflects the changes done in #10940
1 parent 0faf8a6 commit 75f7c1d

File tree

34 files changed

+368
-154
lines changed

34 files changed

+368
-154
lines changed

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ object projects:
324324
sbtDocCommand = ";core/doc ;akka/doc ;shapelessScanner/doc"
325325
)
326326

327-
lazy val ScalaPB = SbtCommunityProject(
327+
lazy val scalaPB = SbtCommunityProject(
328328
project = "ScalaPB",
329329
sbtTestCommand = "dotty-community-build/compile",
330330
// aggregateDoc("runtimeJVM")("scalapbc", "grpcRuntime", "compilerPlugin") fails with

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class CommunityBuildTestB extends CommunityBuildTest:
140140
@Test def scodecBits = projects.scodecBits.run()
141141
@Test def scalap = projects.scalap.run()
142142
@Test def scalaParserCombinators = projects.scalaParserCombinators.run()
143-
@Test def ScalaPB = projects.ScalaPB.run()
143+
@Test def scalaPB = projects.scalaPB.run()
144144
@Test def scalaXml = projects.scalaXml.run()
145145
@Test def scas = projects.scas.run()
146146
@Test def sconfig = projects.sconfig.run()

compiler/src-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,21 +256,22 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
256256
end DefDefTypeTest
257257

258258
object DefDef extends DefDefModule:
259-
def apply(symbol: Symbol, rhsFn: List[TypeRepr] => List[List[Term]] => Option[Term]): DefDef =
260-
withDefaultPos(tpd.DefDef(symbol.asTerm, prefss => {
261-
val (tparams, vparamss) = tpd.splitArgs(prefss)
262-
yCheckedOwners(rhsFn(tparams.map(_.tpe))(vparamss), symbol).getOrElse(tpd.EmptyTree)
263-
}))
264-
def copy(original: Tree)(name: String, typeParams: List[TypeDef], paramss: List[List[ValDef]], tpt: TypeTree, rhs: Option[Term]): DefDef =
265-
tpd.cpy.DefDef(original)(name.toTermName, tpd.joinParams(typeParams, paramss), tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
266-
def unapply(ddef: DefDef): (String, List[TypeDef], List[List[ValDef]], TypeTree, Option[Term]) =
267-
(ddef.name.toString, ddef.typeParams, ddef.termParamss, ddef.tpt, optional(ddef.rhs))
259+
def apply(symbol: Symbol, rhsFn: List[List[Tree]] => Option[Term]): DefDef =
260+
withDefaultPos(tpd.DefDef(symbol.asTerm, prefss =>
261+
yCheckedOwners(rhsFn(prefss), symbol).getOrElse(tpd.EmptyTree)
262+
))
263+
def copy(original: Tree)(name: String, paramss: List[ParamClause], tpt: TypeTree, rhs: Option[Term]): DefDef =
264+
tpd.cpy.DefDef(original)(name.toTermName, paramss, tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
265+
def unapply(ddef: DefDef): (String, List[ParamClause], TypeTree, Option[Term]) =
266+
(ddef.name.toString, ddef.paramss, ddef.tpt, optional(ddef.rhs))
268267
end DefDef
269268

270269
given DefDefMethods: DefDefMethods with
271270
extension (self: DefDef)
272-
def typeParams: List[TypeDef] = self.leadingTypeParams // TODO: adapt to multiple type parameter clauses
273-
def paramss: List[List[ValDef]] = self.termParamss
271+
def paramss: List[ParamClause] = self.paramss
272+
def leadingTypeParams: List[TypeDef] = self.leadingTypeParams
273+
def trailingParamss: List[ParamClause] = self.trailingParamss
274+
def termParamss: List[TermParamClause] = self.termParamss
274275
def returnTpt: TypeTree = self.tpt
275276
def rhs: Option[Term] = optional(self.rhs)
276277
end extension
@@ -750,7 +751,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
750751
tpd.Closure(meth, tss => yCheckedOwners(rhsFn(meth, tss.head.map(withDefaultPos)), meth))
751752

752753
def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match {
753-
case Block((ddef @ DefDef(_, _, params :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
754+
case Block((ddef @ DefDef(_, TermParamClause(params) :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
754755
if ddef.symbol == meth.symbol =>
755756
Some((params, body))
756757
case _ => None
@@ -1481,6 +1482,59 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14811482
end extension
14821483
end AlternativesMethods
14831484

1485+
type ParamClause = tpd.ParamClause
1486+
1487+
object ParamClause extends ParamClauseModule
1488+
1489+
given ParamClauseMethods: ParamClauseMethods with
1490+
extension (self: ParamClause)
1491+
def params: List[ValDef] | List[TypeDef] = self
1492+
end ParamClauseMethods
1493+
1494+
type TermParamClause = List[tpd.ValDef]
1495+
1496+
given TermParamClauseTypeTest: TypeTest[ParamClause, TermParamClause] with
1497+
def unapply(x: ParamClause): Option[TermParamClause & x.type] = x match
1498+
case tpd.ValDefs(_) => Some(x.asInstanceOf[TermParamClause & x.type])
1499+
case _ => None
1500+
end TermParamClauseTypeTest
1501+
1502+
object TermParamClause extends TermParamClauseModule:
1503+
def apply(params: List[ValDef]): TermParamClause =
1504+
if yCheck then
1505+
val implicitParams = params.count(_.symbol.is(dotc.core.Flags.Implicit))
1506+
assert(implicitParams == 0 || implicitParams == params.size, "Expected all or non of parameters to be implicit")
1507+
params
1508+
def unapply(x: TermParamClause): Some[List[ValDef]] = Some(x)
1509+
end TermParamClause
1510+
1511+
given TermParamClauseMethods: TermParamClauseMethods with
1512+
extension (self: TermParamClause)
1513+
def params: List[ValDef] = self
1514+
def isImplicit: Boolean =
1515+
self.nonEmpty && self.head.symbol.is(dotc.core.Flags.Implicit)
1516+
end TermParamClauseMethods
1517+
1518+
type TypeParamClause = List[tpd.TypeDef]
1519+
1520+
given TypeParamClauseTypeTest: TypeTest[ParamClause, TypeParamClause] with
1521+
def unapply(x: ParamClause): Option[TypeParamClause & x.type] = x match
1522+
case tpd.TypeDefs(_) => Some(x.asInstanceOf[TypeParamClause & x.type])
1523+
case _ => None
1524+
end TypeParamClauseTypeTest
1525+
1526+
object TypeParamClause extends TypeParamClauseModule:
1527+
def apply(params: List[TypeDef]): TypeParamClause =
1528+
if params.isEmpty then throw IllegalArgumentException("Empty type parameters")
1529+
params
1530+
def unapply(x: TypeParamClause): Some[List[TypeDef]] = Some(x)
1531+
end TypeParamClause
1532+
1533+
given TypeParamClauseMethods: TypeParamClauseMethods with
1534+
extension (self: TypeParamClause)
1535+
def params: List[TypeDef] = self
1536+
end TypeParamClauseMethods
1537+
14841538
type Selector = untpd.ImportSelector
14851539

14861540
object Selector extends SelectorModule

compiler/src-non-bootstrapped/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
261261
}))
262262
def copy(original: Tree)(name: String, typeParams: List[TypeDef], paramss: List[List[ValDef]], tpt: TypeTree, rhs: Option[Term]): DefDef =
263263
tpd.cpy.DefDef(original)(name.toTermName, tpd.joinParams(typeParams, paramss), tpt, yCheckedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
264-
def unapply(ddef: DefDef): (String, List[TypeDef], List[List[ValDef]], TypeTree, Option[Term]) =
265-
(ddef.name.toString, ddef.typeParams, ddef.termParamss, ddef.tpt, optional(ddef.rhs))
264+
// def unapply(ddef: DefDef): (String, List[TypeDef], List[List[ValDef]], TypeTree, Option[Term]) =
265+
// (ddef.name.toString, ddef.typeParams, ddef.termParamss, ddef.tpt, optional(ddef.rhs))
266266
end DefDef
267267

268268
given DefDefMethods: DefDefMethods with
269269
extension (self: DefDef)
270270
def typeParams: List[TypeDef] = self.leadingTypeParams // TODO: adapt to multiple type parameter clauses
271-
def paramss: List[List[ValDef]] = self.termParamss
271+
// def paramss: List[List[ValDef]] = self.termParamss
272272
def returnTpt: TypeTree = self.tpt
273273
def rhs: Option[Term] = optional(self.rhs)
274274
end extension
@@ -747,12 +747,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
747747
val meth = dotc.core.Symbols.newSymbol(owner, nme.ANON_FUN, Synthetic | Method, tpe)
748748
tpd.Closure(meth, tss => yCheckedOwners(rhsFn(meth, tss.head), meth))
749749

750-
def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match {
751-
case Block((ddef @ DefDef(_, _, params :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
752-
if ddef.symbol == meth.symbol =>
753-
Some((params, body))
754-
case _ => None
755-
}
750+
def unapply(tree: Block): Option[(List[ValDef], Term)] = ???
756751
end Lambda
757752

758753
type If = tpd.If

compiler/src/scala/quoted/runtime/impl/Matcher.scala

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ object Matcher {
206206
}.transformTree(scrutinee)(Symbol.spliceOwner)
207207
}
208208
val names = args.map {
209-
case Block(List(DefDef("$anonfun", _, _, _, Some(Apply(Ident(name), _)))), _) => name
209+
case Block(List(DefDef("$anonfun", _, _, Some(Apply(Ident(name), _)))), _) => name
210210
case arg => arg.symbol.name
211211
}
212212
val argTypes = args.map(x => x.tpe.widenTermRefExpr)
@@ -302,16 +302,19 @@ object Matcher {
302302
tpt1 =?= tpt2 &&& treeOptMatches(rhs1, rhs2)(using rhsEnv)
303303

304304
/* Match def */
305-
case (DefDef(_, typeParams1, paramss1, tpt1, Some(rhs1)), DefDef(_, typeParams2, paramss2, tpt2, Some(rhs2))) =>
305+
case (DefDef(_, paramss1, tpt1, Some(rhs1)), DefDef(_, paramss2, tpt2, Some(rhs2))) =>
306306
def rhsEnv =
307+
val paramSyms: List[(Symbol, Symbol)] =
308+
for
309+
(clause1, clause2) <- paramss1.zip(paramss2)
310+
(param1, param2) <- clause1.params.zip(clause2.params)
311+
yield
312+
param1.symbol -> param2.symbol
307313
val oldEnv: Env = summon[Env]
308-
val newEnv: List[(Symbol, Symbol)] =
309-
(scrutinee.symbol -> pattern.symbol) :: typeParams1.zip(typeParams2).map((tparam1, tparam2) => tparam1.symbol -> tparam2.symbol) :::
310-
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
314+
val newEnv: List[(Symbol, Symbol)] = (scrutinee.symbol -> pattern.symbol) :: paramSyms
311315
oldEnv ++ newEnv
312316

313-
typeParams1 =?= typeParams2
314-
&&& matchLists(paramss1, paramss2)(_ =?= _)
317+
matchLists(paramss1, paramss2)(_ =?= _)
315318
&&& tpt1 =?= tpt2
316319
&&& withEnv(rhsEnv)(rhs1 =?= rhs2)
317320

@@ -343,6 +346,14 @@ object Matcher {
343346
}
344347
end extension
345348

349+
extension (scrutinee: ParamClause)
350+
/** Check that all parameters in the clauses clauses match with =?= and concatenate the results with &&& */
351+
private def =?= (pattern: ParamClause)(using Env)(using DummyImplicit): Matching =
352+
(scrutinee, pattern) match
353+
case (TermParamClause(params1), TermParamClause(params2)) => matchLists(params1, params2)(_ =?= _)
354+
case (TypeParamClause(params1), TypeParamClause(params2)) => matchLists(params1, params2)(_ =?= _)
355+
case _ => notMatched
356+
346357
/** Does the scrutenne symbol match the pattern symbol? It matches if:
347358
* - They are the same symbol
348359
* - The scrutinee has is in the environment and they are equivalent
@@ -382,7 +393,7 @@ object Matcher {
382393
def unapply(args: List[Term]): Option[List[Ident]] =
383394
args.foldRight(Option(List.empty[Ident])) {
384395
case (id: Ident, Some(acc)) => Some(id :: acc)
385-
case (Block(List(DefDef("$anonfun", Nil, List(params), Inferred(), Some(Apply(id: Ident, args)))), Closure(Ident("$anonfun"), None)), Some(acc))
396+
case (Block(List(DefDef("$anonfun", TermParamClause(params) :: Nil, Inferred(), Some(Apply(id: Ident, args)))), Closure(Ident("$anonfun"), None)), Some(acc))
386397
if params.zip(args).forall(_.symbol == _.symbol) =>
387398
Some(id :: acc)
388399
case _ => None

compiler/src/scala/quoted/runtime/impl/printers/Extractors.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ object Extractors {
117117
this += ", " ++= bindings += ", " += expansion += ")"
118118
case ValDef(name, tpt, rhs) =>
119119
this += "ValDef(\"" += name += "\", " += tpt += ", " += rhs += ")"
120-
case DefDef(name, typeParams, paramss, returnTpt, rhs) =>
121-
this += "DefDef(\"" += name += "\", " ++= typeParams += ", " +++= paramss += ", " += returnTpt += ", " += rhs += ")"
120+
case DefDef(name, paramsClauses, returnTpt, rhs) =>
121+
this += "DefDef(\"" += name += "\", " ++= paramsClauses += ", " += returnTpt += ", " += rhs += ")"
122122
case TypeDef(name, rhs) =>
123123
this += "TypeDef(\"" += name += "\", " += rhs += ")"
124124
case ClassDef(name, constr, parents, derived, self, body) =>
@@ -256,6 +256,11 @@ object Extractors {
256256
else if x.isTypeDef then this += "IsTypeDefSymbol(<" += x.fullName += ">)"
257257
else { assert(x.isNoSymbol); this += "NoSymbol()" }
258258

259+
def visitParamClause(x: ParamClause): this.type =
260+
x match
261+
case TermParamClause(params) => this += "TermParamClause(" ++= params += ")"
262+
case TypeParamClause(params) => this += "TypeParamClause(" ++= params += ")"
263+
259264
def +=(x: Boolean): this.type = { sb.append(x); this }
260265
def +=(x: Byte): this.type = { sb.append(x); this }
261266
def +=(x: Short): this.type = { sb.append(x); this }
@@ -301,6 +306,10 @@ object Extractors {
301306
def +=(x: Symbol): self.type = { visitSymbol(x); buff }
302307
}
303308

309+
private implicit class ParamClauseOps(buff: self.type) {
310+
def ++=(x: List[ParamClause]): self.type = { visitList(x, visitParamClause); buff }
311+
}
312+
304313
private def visitOption[U](opt: Option[U], visit: U => this.type): this.type = opt match {
305314
case Some(x) =>
306315
this += "Some("

compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ object SourceCode {
138138
this += "."
139139
printSelectors(selectors)
140140

141-
case cdef @ ClassDef(name, DefDef(_, targs, argss, _, _), parents, derived, self, stats) =>
141+
case cdef @ ClassDef(name, DefDef(_, paramss, _, _), parents, derived, self, stats) =>
142142
printDefAnnotations(cdef)
143143

144144
val flags = cdef.symbol.flags
@@ -155,12 +155,13 @@ object SourceCode {
155155
else if (flags.is(Flags.Abstract)) this += highlightKeyword("abstract class ") += highlightTypeDef(name)
156156
else this += highlightKeyword("class ") += highlightTypeDef(name)
157157

158-
val typeParams = stats.collect { case targ: TypeDef => targ }.filter(_.symbol.isTypeParam).zip(targs)
159158
if (!flags.is(Flags.Module)) {
160-
printTargsDefs(typeParams)
161-
val it = argss.iterator
162-
while (it.hasNext)
163-
printArgsDefs(it.next())
159+
for paramClause <- paramss do
160+
paramClause match
161+
case TermParamClause(params) =>
162+
printArgsDefs(params)
163+
case TypeParamClause(params) =>
164+
printTargsDefs(stats.collect { case targ: TypeDef => targ }.filter(_.symbol.isTypeParam).zip(params))
164165
}
165166

166167
val parents1 = parents.filter {
@@ -212,8 +213,8 @@ object SourceCode {
212213
// Currently the compiler does not allow overriding some of the methods generated for case classes
213214
d.symbol.flags.is(Flags.Synthetic) &&
214215
(d match {
215-
case DefDef("apply" | "unapply" | "writeReplace", _, _, _, _) if d.symbol.owner.flags.is(Flags.Module) => true
216-
case DefDef(n, _, _, _, _) if d.symbol.owner.flags.is(Flags.Case) =>
216+
case DefDef("apply" | "unapply" | "writeReplace", _, _, _) if d.symbol.owner.flags.is(Flags.Module) => true
217+
case DefDef(n, _, _, _) if d.symbol.owner.flags.is(Flags.Case) =>
217218
n == "copy" ||
218219
n.matches("copy\\$default\\$[1-9][0-9]*") || // default parameters for the copy method
219220
n.matches("_[1-9][0-9]*") || // Getters from Product
@@ -301,7 +302,7 @@ object SourceCode {
301302
printTree(body)
302303
}
303304

304-
case ddef @ DefDef(name, targs, argss, tpt, rhs) =>
305+
case ddef @ DefDef(name, paramss, tpt, rhs) =>
305306
printDefAnnotations(ddef)
306307

307308
val isConstructor = name == "<init>"
@@ -316,10 +317,10 @@ object SourceCode {
316317

317318
val name1: String = if (isConstructor) "this" else splicedName(ddef.symbol).getOrElse(name)
318319
this += highlightKeyword("def ") += highlightValDef(name1)
319-
printTargsDefs(targs.zip(targs))
320-
val it = argss.iterator
321-
while (it.hasNext)
322-
printArgsDefs(it.next())
320+
for clause <- paramss do
321+
clause match
322+
case TermParamClause(params) => printArgsDefs(params)
323+
case TypeParamClause(params) => printTargsDefs(params.zip(params))
323324
if (!isConstructor) {
324325
this += ": "
325326
printTypeTree(tpt)
@@ -1251,7 +1252,7 @@ object SourceCode {
12511252

12521253
private def printDefinitionName(tree: Definition): this.type = tree match {
12531254
case ValDef(name, _, _) => this += highlightValDef(name)
1254-
case DefDef(name, _, _, _, _) => this += highlightValDef(name)
1255+
case DefDef(name, _, _, _) => this += highlightValDef(name)
12551256
case ClassDef(name, _, _, _, _, _) => this += highlightTypeDef(name.stripSuffix("$"))
12561257
case TypeDef(name, _) => this += highlightTypeDef(name)
12571258
}

0 commit comments

Comments
 (0)