diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala index ce2ac50fad10..0a193c5a9578 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala @@ -606,6 +606,12 @@ object TastyImpl extends scala.tasty.Tasty { } } + object TypeLambdaTree extends TypeLambdaTreeExtractor { + def unapply(x: TypeTree)(implicit ctx: Context): Option[(List[TypeDef], TypeOrBoundsTree)] = x match { + case Trees.LambdaTypeTree(tparams, body) => Some((tparams, body)) + case _ => None + } + } } // ----- TypeBoundsTrees ------------------------------------------------ diff --git a/library/src/scala/tasty/Tasty.scala b/library/src/scala/tasty/Tasty.scala index 63c23bf9e2f4..d5c67a1ff65f 100644 --- a/library/src/scala/tasty/Tasty.scala +++ b/library/src/scala/tasty/Tasty.scala @@ -440,6 +440,10 @@ abstract class Tasty { tasty => def unapply(x: TypeTree)(implicit ctx: Context): Option[TypeTree] } + val TypeLambdaTree: TypeLambdaTreeExtractor + abstract class TypeLambdaTreeExtractor { + def unapply(x: TypeTree)(implicit ctx: Context): Option[(List[TypeDef], TypeOrBoundsTree)] + } } // ----- TypeBoundsTrees ------------------------------------------------ diff --git a/library/src/scala/tasty/util/ShowExtractors.scala b/library/src/scala/tasty/util/ShowExtractors.scala index c3b391ba38ed..030c6ccc33fd 100644 --- a/library/src/scala/tasty/util/ShowExtractors.scala +++ b/library/src/scala/tasty/util/ShowExtractors.scala @@ -110,6 +110,8 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += "TypeTree.ByName(" += result += ")" case TypeTree.Annotated(arg, annot) => this += "TypeTree.Annotated(" += arg += ", " += annot += ")" + case TypeTree.TypeLambdaTree(tparams, body) => + this += "LambdaTypeTree(" ++= tparams += ", " += body += ")" case TypeBoundsTree(lo, hi) => this += "TypeBoundsTree(" += lo += ", " += hi += ")" case SyntheticBounds() => @@ -185,6 +187,8 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += "Type.ThisType(" += tp += ")" case Type.RecursiveThis(binder) => this += "Type.RecursiveThis(" += binder += ")" + case Type.RecursiveType(underlying) => + this += "Type.RecursiveType(" += underlying += ")" case Type.MethodType(argNames, argTypes, resType) => this += "Type.MethodType(" ++= argNames += ", " ++= argTypes += ", " += resType += ")" case Type.PolyType(argNames, argBounds, resType) => diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index e651ca485a07..50576d433cde 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -148,7 +148,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case tdef@TypeDef(name, rhs) => this += "type " - printTargDef(tdef) + printTargDef(tdef, isMember = true) case vdef@ValDef(name, tpt, rhs) => val flags = vdef.flags @@ -469,7 +469,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty } } - def printTargDef(arg: TypeDef): Buffer = { + def printTargDef(arg: TypeDef, isMember: Boolean = false): Buffer = { val TypeDef(name, rhs) = arg this += name rhs match { @@ -488,6 +488,28 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty } case rhs @ SyntheticBounds() => printTypeOrBound(rhs.tpe) + case rhs @ TypeTree.TypeLambdaTree(tparams, body) => + def printSeparated(list: List[TypeDef]): Unit = list match { + case Nil => + case x :: Nil => + val TypeDef(name, trhs) = x + this += name + printTypeOrBoundsTree(trhs) + case x :: xs => + val TypeDef(name, trhs) = x + this += name + printTypeOrBoundsTree(trhs) + this += ", " + printSeparated(xs) + } + this += "[" + printSeparated(tparams) + this += "]" + if (isMember) { + this += " = " + printTypeOrBoundsTree(body) + } + else this case rhs @ TypeTree() => this += " = " printTypeTree(rhs) @@ -672,6 +694,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += "=> " printTypeTree(result) + case TypeTree.TypeLambdaTree(tparams, body) => + printTargsDefs(tparams) + this += " => " + printTypeOrBoundsTree(body) + case _ => throw new MatchError(tree.show) @@ -757,6 +784,30 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case _ => this } + case Type.TypeLambda(paramNames, tparams, body) => + this += "[" + def printSeparated(list: List[(String, TypeBounds)]): Unit = list match { + case Nil => + case (name, bounds) :: Nil => + this += name + printTypeOrBound(bounds) + case (name, bounds) :: xs => + this += name + printTypeOrBound(bounds) + this += ", " + printSeparated(xs) + } + printSeparated(paramNames.zip(tparams)) + this += "] => " + printTypeOrBound(body) + + case Type.ParamRef(lambda, idx) => + lambda match { + case Type.MethodType(params, _, _) => this += params(idx) + case Type.PolyType(params, _, _) => this += params(idx) + case Type.TypeLambda(params, _, _) => this += params(idx) + } + case _ => throw new MatchError(tpe.show) } diff --git a/tests/pos/i1181.decompiled b/tests/pos/i1181.decompiled new file mode 100644 index 000000000000..a88d47e927ff --- /dev/null +++ b/tests/pos/i1181.decompiled @@ -0,0 +1,8 @@ +/** Decompiled from out/posTestFromTasty/pos/i1181/Test.class */ +object Test { + def foo[M[_$1 >: scala.Nothing <: scala.Any]](x: M[scala.Int]): M[scala.Int] = x + type Alias[A >: scala.Nothing <: scala.Any] = scala.Tuple2[A, A] + val x: Test.Alias[scala.Int] = scala.Tuple2.apply[scala.Int, scala.Int](1, 2) + Test.foo[Test.Alias](Test.x) + Test.foo[[A >: scala.Nothing <: scala.Any] => scala.Tuple2[A, A]](Test.x) +} diff --git a/tests/pos/tasty/definitions.scala b/tests/pos/tasty/definitions.scala index fa40a48a5f15..edc266448b22 100644 --- a/tests/pos/tasty/definitions.scala +++ b/tests/pos/tasty/definitions.scala @@ -100,6 +100,7 @@ object definitions { case And(left: TypeTree, right: TypeTree) case Or(left: TypeTree, right: TypeTree) case ByName(tpt: TypeTree) + case TypeLambda(tparams: List[TypeDef], body: Type | TypeBoundsTree) } /** Trees denoting type bounds */