diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/CaseDefOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/CaseDefOpsImpl.scala index 8c643cafc11b..020a40dfcc15 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/CaseDefOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/CaseDefOpsImpl.scala @@ -13,4 +13,12 @@ trait CaseDefOpsImpl extends scala.tasty.reflect.CaseDefOps with CoreImpl with H def unapply(x: CaseDef): Some[(Pattern, Option[Term], Term)] = Some(x.pat, optional(x.guard), x.body) } + def TypeCaseDefDeco(caseDef: TypeCaseDef): TypeCaseDefAPI = new TypeCaseDefAPI { + def pattern(implicit ctx: Context): Pattern = caseDef.pat + def rhs(implicit ctx: Context): Term = caseDef.body + } + + object TypeCaseDef extends TypeCaseDefExtractor { + def unapply(x: TypeCaseDef): Some[(TypeTree, TypeTree)] = Some((x.pat, x.body)) + } } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala index ed6d930db227..c84e04c3653e 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/CoreImpl.scala @@ -26,6 +26,7 @@ trait CoreImpl extends scala.tasty.reflect.Core { type Term = tpd.Tree type CaseDef = tpd.CaseDef + type TypeCaseDef = tpd.CaseDef type Pattern = tpd.Tree type Value = tpd.Tree diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsOpsImpl.scala index 2c7a5cad1b6a..5edac2829ad6 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsOpsImpl.scala @@ -123,6 +123,13 @@ trait TypeOrBoundsOpsImpl extends scala.tasty.reflect.TypeOrBoundsOps with CoreI } } + object MatchType extends MatchTypeExtractor { + def unapply(x: TypeOrBounds)(implicit ctx: Context): Option[(Type, Type, List[Type])] = x match { + case Types.MatchType(bound, scrutinee, cases) => Some((bound, scrutinee, cases)) + case _ => None + } + } + object ByNameType extends ByNameTypeExtractor { def unapply(x: TypeOrBounds)(implicit ctx: Context): Option[Type] = x match { case Types.ExprType(resType) => Some(resType.stripTypeVar) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala index 0302ddc3e566..a4b42a86f237 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsTreesOpsImpl.scala @@ -100,6 +100,13 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w } } + object MatchType extends MatchTypeExtractor { + def unapply(x: TypeOrBoundsTree)(implicit ctx: Context): Option[(Option[TypeTree], TypeTree, List[CaseDef])] = x match { + case x: tpd.MatchTypeTree => Some((if (x.bound == tpd.EmptyTree) None else Some(x.bound), x.selector, x.cases)) + case _ => None + } + } + object ByName extends ByNameExtractor { def unapply(x: TypeTree)(implicit ctx: Context): Option[TypeTree] = x match { case x: tpd.ByNameTypeTree => Some(x.result) diff --git a/compiler/test/dotc/pos-from-tasty.blacklist b/compiler/test/dotc/pos-from-tasty.blacklist index 109261d031b6..64aff439e0f8 100644 --- a/compiler/test/dotc/pos-from-tasty.blacklist +++ b/compiler/test/dotc/pos-from-tasty.blacklist @@ -16,9 +16,6 @@ repeatedArgs213.scala # Error printing parent constructors that are blocks default-super.scala -# Need to implement printing of match types -matchtype.scala - # Did not survive addition of type ascriptions in decompiled tests i3050.scala i4006b.scala diff --git a/compiler/test/dotc/pos-recompilation.whitelist b/compiler/test/dotc/pos-recompilation.whitelist index eb4c22b9d238..b9b0793ea58d 100644 --- a/compiler/test/dotc/pos-recompilation.whitelist +++ b/compiler/test/dotc/pos-recompilation.whitelist @@ -376,7 +376,6 @@ lookupswitch macro-deprecate-dont-touch-backquotedidents Map match -matchtype matthias3 matthias4 matthias5 diff --git a/library/src/scala/tasty/reflect/CaseDefOps.scala b/library/src/scala/tasty/reflect/CaseDefOps.scala index 37732ff941a2..593fca4610a7 100644 --- a/library/src/scala/tasty/reflect/CaseDefOps.scala +++ b/library/src/scala/tasty/reflect/CaseDefOps.scala @@ -16,4 +16,15 @@ trait CaseDefOps extends Core { def unapply(x: CaseDef): Option[(Pattern, Option[Term], Term)] } + + trait TypeCaseDefAPI { + def pattern(implicit ctx: Context): TypeTree + def rhs(implicit ctx: Context): TypeTree + } + implicit def TypeCaseDefDeco(caseDef: TypeCaseDef): TypeCaseDefAPI + + val TypeCaseDef: TypeCaseDefExtractor + abstract class TypeCaseDefExtractor { + def unapply(x: TypeCaseDef): Option[(TypeTree, TypeTree)] + } } diff --git a/library/src/scala/tasty/reflect/Core.scala b/library/src/scala/tasty/reflect/Core.scala index 93cc7bbeaf67..edf0823cc35a 100644 --- a/library/src/scala/tasty/reflect/Core.scala +++ b/library/src/scala/tasty/reflect/Core.scala @@ -46,6 +46,7 @@ package scala.tasty.reflect * | +- Annotated * | +- And * | +- Or + * | +- MatchType * | +- ByName * | +- TypeLambdaTree * | +- Bind @@ -54,6 +55,7 @@ package scala.tasty.reflect * +- SyntheticBounds * * +- CaseDef + * +- TypeCaseDef * * +- Pattern --+- Value * +- Bind @@ -75,6 +77,7 @@ package scala.tasty.reflect * +- AnnotatedType * +- AndType * +- OrType + * +- MatchType * +- ByNameType * +- ParamRef * +- ThisType @@ -137,6 +140,9 @@ trait Core { /** Branch of a pattern match or catch clause */ type CaseDef + /** Branch of a type pattern match */ + type TypeCaseDef + /** Pattern tree of the pattern part of a CaseDef */ type Pattern type Value <: Pattern diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index f9442ffdffbf..a5674bf82c0a 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -192,6 +192,8 @@ trait Printers this += "TypeBoundsTree(" += lo += ", " += hi += ")" case SyntheticBounds() => this += s"SyntheticBounds()" + case TypeTree.MatchType(bound, selector, cases) => + this += "TypeTree.MatchType(" += bound += ", " += selector += ", " ++= cases += ")" } def visitCaseDef(x: CaseDef): Buffer = { @@ -199,6 +201,11 @@ trait Printers this += "CaseDef(" += pat += ", " += guard += ", " += body += ")" } + def visitTypeCaseDef(x: TypeCaseDef): Buffer = { + val TypeCaseDef(pat, body) = x + this += "TypeCaseDef(" += pat += ", " += body += ")" + } + def visitPattern(x: Pattern): Buffer = x match { case Pattern.Value(v) => this += "Pattern.Value(" += v += ")" @@ -252,6 +259,8 @@ trait Printers this += "Type.AndType(" += left += ", " += right += ")" case Type.OrType(left, right) => this += "Type.OrType(" += left += ", " += right += ")" + case Type.MatchType(bound, scrutinee, cases) => + this += "Type.MatchType(" += bound += ", " += scrutinee += ", " ++= cases += ")" case Type.ByNameType(underlying) => this += "Type.ByNameType(" += underlying += ")" case Type.ParamRef(binder, idx) => @@ -326,6 +335,11 @@ trait Printers def ++=(x: List[CaseDef]): Buffer = { visitList(x, visitCaseDef); buff } } + private implicit class TypeCaseDefOps(buff: Buffer) { + def +=(x: TypeCaseDef): Buffer = { visitTypeCaseDef(x); buff } + def ++=(x: List[TypeCaseDef]): Buffer = { visitList(x, visitTypeCaseDef); buff } + } + private implicit class PatternOps(buff: Buffer) { def +=(x: Pattern): Buffer = { visitPattern(x); buff } def ++=(x: List[Pattern]): Buffer = { visitList(x, visitPattern); buff } @@ -871,6 +885,19 @@ trait Printers this } + def printTypes(trees: List[Type], sep: String): Buffer = { + def printSeparated(list: List[Type]): Unit = list match { + case Nil => + case x :: Nil => printType(x) + case x :: xs => + printType(x) + this += sep + printSeparated(xs) + } + printSeparated(trees) + this + } + def printImportSelectors(selectors: List[ImportSelector]): Buffer = { def printSeparated(list: List[ImportSelector]): Unit = list match { case Nil => @@ -898,6 +925,19 @@ trait Printers this } + def printTypeCases(cases: List[TypeCaseDef], sep: String): Buffer = { + def printSeparated(list: List[TypeCaseDef]): Unit = list match { + case Nil => + case x :: Nil => printTypeCaseDef(x) + case x :: xs => + printTypeCaseDef(x) + this += sep + printSeparated(xs) + } + printSeparated(cases) + this + } + def printPatterns(cases: List[Pattern], sep: String): Buffer = { def printSeparated(list: List[Pattern]): Unit = list match { case Nil => @@ -976,6 +1016,12 @@ trait Printers } inSquare(printSeparated(tparams)) if (isMember) { + body match { + case TypeTree.MatchType(Some(bound), _, _) => + this += " <: " + printTypeTree(bound) + case _ => + } this += " = " printTypeOrBoundsTree(body) } @@ -1067,6 +1113,14 @@ trait Printers this } + def printTypeCaseDef(caseDef: TypeCaseDef): Buffer = { + this += highlightValDef("case ", color) + printTypeTree(caseDef.pattern) + this += highlightValDef(" => ", color) + printTypeTree(caseDef.rhs) + this + } + def printPattern(pattern: Pattern): Buffer = pattern match { case Pattern.Value(v) => v match { @@ -1201,6 +1255,11 @@ trait Printers this += highlightTypeDef(" | ", color) printTypeTree(right) + case TypeTree.MatchType(bound, selector, cases) => + printTypeTree(selector) + this += highlightKeyword(" match ", color) + inBlock(printTypeCases(cases, lineBreak())) + case TypeTree.ByName(result) => this += highlightTypeDef("=> ", color) printTypeTree(result) @@ -1300,6 +1359,11 @@ trait Printers this += highlightTypeDef(" | ", color) printType(right) + case Type.MatchType(bound, scrutinee, cases) => + printType(scrutinee) + this += highlightKeyword(" match ", color) + inBlock(printTypes(cases, lineBreak())) + case Type.ByNameType(tp) => this += highlightTypeDef(" => ", color) printType(tp) @@ -1553,7 +1617,7 @@ trait Printers } } - // TODO Provide some of these in scala.tasty.Reflect.scala and implement them using checks on symbols for performance + // TODO Provide some of these in scala.tasty.Reflection.scala and implement them using checks on symbols for performance private object Types { object JavaLangObject { diff --git a/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala b/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala index 1942c99eeb97..3b0fbec6d09f 100644 --- a/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala +++ b/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala @@ -92,6 +92,11 @@ trait TypeOrBoundsOps extends Core { def unapply(typeOrBounds: TypeOrBounds)(implicit ctx: Context): Option[(Type, Type)] } + val MatchType: MatchTypeExtractor + abstract class MatchTypeExtractor { + def unapply(typeOrBounds: TypeOrBounds)(implicit ctx: Context): Option[(Type, Type, List[Type])] + } + val ByNameType: ByNameTypeExtractor abstract class ByNameTypeExtractor { def unapply(typeOrBounds: TypeOrBounds)(implicit ctx: Context): Option[Type] diff --git a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala index 6851f455d38e..e7c6112d6d30 100644 --- a/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala +++ b/library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala @@ -77,6 +77,11 @@ trait TypeOrBoundsTreeOps extends Core { def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] } + val MatchType: MatchTypeExtractor + abstract class MatchTypeExtractor { + def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(Option[TypeTree], TypeTree, List[TypeCaseDef])] + } + val ByName: ByNameExtractor abstract class ByNameExtractor { def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[TypeTree]