diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala index d28b90503a5d..ce2ac50fad10 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala @@ -538,7 +538,7 @@ object TastyImpl extends scala.tasty.Tasty { object Synthetic extends SyntheticExtractor { def unapply(x: TypeTree)(implicit ctx: Context): Boolean = x match { - case Trees.TypeTree() => true + case x @ Trees.TypeTree() => !x.tpe.isInstanceOf[Types.TypeBounds] case _ => false } } @@ -610,10 +610,10 @@ object TastyImpl extends scala.tasty.Tasty { // ----- TypeBoundsTrees ------------------------------------------------ - type TypeBoundsTree = tpd.TypeBoundsTree + type TypeBoundsTree = tpd.Tree def TypeBoundsTreeDeco(x: TypeBoundsTree): TypeBoundsTreeAPI = new TypeBoundsTreeAPI { - def tpe(implicit ctx: Context): TypeBounds = x.tpe.bounds + def tpe(implicit ctx: Context): TypeBounds = x.tpe.asInstanceOf[Types.TypeBounds] } def typeBoundsTreeClassTag: ClassTag[TypeBoundsTree] = implicitly[ClassTag[TypeBoundsTree]] @@ -625,6 +625,13 @@ object TastyImpl extends scala.tasty.Tasty { } } + object SyntheticBounds extends SyntheticBoundsExtractor { + def unapply(x: TypeBoundsTree)(implicit ctx: Context): Boolean = x match { + case x @ Trees.TypeTree() => x.tpe.isInstanceOf[Types.TypeBounds] + case _ => false + } + } + // ===== Types ==================================================== type TypeOrBounds = Types.Type diff --git a/library/src/scala/tasty/Tasty.scala b/library/src/scala/tasty/Tasty.scala index 783a12ab2c9c..63c23bf9e2f4 100644 --- a/library/src/scala/tasty/Tasty.scala +++ b/library/src/scala/tasty/Tasty.scala @@ -388,8 +388,10 @@ abstract class Tasty { tasty => def unapply(x: TypeTree)(implicit ctx: Context): Boolean + /** TypeTree containing an inferred type */ val Synthetic: SyntheticExtractor abstract class SyntheticExtractor { + /** Matches a TypeTree containing an inferred type */ def unapply(x: TypeTree)(implicit ctx: Context): Boolean } @@ -456,6 +458,13 @@ abstract class Tasty { tasty => def unapply(x: TypeBoundsTree)(implicit ctx: Context): Option[(TypeTree, TypeTree)] } + /** TypeBoundsTree containing an inferred type bounds */ + val SyntheticBounds: SyntheticBoundsExtractor + abstract class SyntheticBoundsExtractor { + /** Matches a TypeBoundsTree containing inferred type bounds */ + def unapply(x: TypeBoundsTree)(implicit ctx: Context): Boolean + } + // ===== Types ==================================================== type TypeOrBounds diff --git a/library/src/scala/tasty/util/ShowExtractors.scala b/library/src/scala/tasty/util/ShowExtractors.scala index c8594565a32c..c3b391ba38ed 100644 --- a/library/src/scala/tasty/util/ShowExtractors.scala +++ b/library/src/scala/tasty/util/ShowExtractors.scala @@ -112,6 +112,8 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += "TypeTree.Annotated(" += arg += ", " += annot += ")" case TypeBoundsTree(lo, hi) => this += "TypeBoundsTree(" += lo += ", " += hi += ")" + case SyntheticBounds() => + this += s"SyntheticBounds()" } def visitCaseDef(x: CaseDef): Buffer = { @@ -188,7 +190,8 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case Type.PolyType(argNames, argBounds, resType) => this += "Type.PolyType(" ++= argNames += ", " ++= argBounds += ", " += resType += ")" case Type.TypeLambda(argNames, argBounds, resType) => - this += "Type.TypeLambda(" ++= argNames += ", " ++= argBounds += ", " += resType += ")" + // resType is not printed to avoid cycles + this += "Type.TypeLambda(" ++= argNames += ", " ++= argBounds += ", _)" case TypeBounds(lo, hi) => this += "TypeBounds(" += lo += ", " += hi += ")" case NoPrefix() => diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index 28882b9dc478..b8e1420be7ca 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -486,9 +486,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += " <: " printTypeTree(hi) } - case tpt@TypeTree() => + case rhs @ SyntheticBounds() => + printTypeOrBound(rhs.tpe) + case rhs @ TypeTree() => this += " = " - printTypeTree(tpt) + printTypeTree(rhs) } } @@ -604,6 +606,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty printTypeTree(lo) this += " <: " printTypeTree(hi) + case tpt @ SyntheticBounds() => + printTypeOrBound(tpt.tpe) case tpt @ TypeTree() => printTypeTree(tpt) } @@ -611,6 +615,10 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty def printTypeTree(tree: TypeTree): Buffer = tree match { case TypeTree.Synthetic() => printType(tree.tpe) + tree.tpe match { + case tpe @ Type.TypeRef(name, _) if name.endsWith("$") => this += ".type" + case tpe => this + } case TypeTree.TypeIdent(name) => printType(tree.tpe) @@ -709,9 +717,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case Type.TypeRef(name, prefix) => prefix match { case NoPrefix() | Type.ThisType(Types.EmptyPackage()) => - case prefix@Type() => - printType(prefix) - this += "." + case prefix@Type() => printType(prefix) += "." } this += name.stripSuffix("$") diff --git a/tests/pos/i2104b.decompiled b/tests/pos/i2104b.decompiled new file mode 100644 index 000000000000..221efc384b5a --- /dev/null +++ b/tests/pos/i2104b.decompiled @@ -0,0 +1,43 @@ +/** Decompiled from out/posTestFromTasty/pos/i2104b/Cons.class */ +class Cons[H, T]() extends java.lang.Object +object Cons { + def apply[H, T](h: H, t: T): Cons[H, T] = scala.Predef.??? + def unapply[H, T](t: Cons[H, T]): scala.Option[Pair[H, T]] = scala.Predef.??? +} +/** Decompiled from out/posTestFromTasty/pos/i2104b/Pair.class */ +case class Pair[A, B](_1: A, _2: B) { + override def hashCode(): scala.Int = { + var acc: scala.Int = 2479866 + acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(Pair.this._1)) + acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(Pair.this._2)) + scala.runtime.Statics.finalizeHash(acc, 2) + } + override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match { + case x$0: Pair[Pair.this.A, Pair.this.B] => + this._1.==(x$0._1).&&(this._2.==(x$0._2)) + case _ => + false + }) + override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this) + override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B]] + override def productArity: scala.Int = 2 + override def productPrefix: java.lang.String = "Pair" + override def productElement(n: scala.Int): scala.Any = n match { + case 0 => + this._1 + case 1 => + this._2 + case _ => + throw new java.lang.IndexOutOfBoundsException(n.toString()) + } +} +object Pair extends scala.AnyRef +/** Decompiled from out/posTestFromTasty/pos/i2104b/Test.class */ +object Test { + def main(args: scala.Array[scala.Predef.String]): scala.Unit = { + Cons.apply[scala.Option[scala.Int], scala.None.type](scala.Option.apply[scala.Int](1), scala.None) match { + case Cons(scala.Some(i), scala.None) => + () + } + } +} diff --git a/tests/pos/i2104b.scala b/tests/pos/i2104b.scala new file mode 100644 index 000000000000..3effa25f1fbf --- /dev/null +++ b/tests/pos/i2104b.scala @@ -0,0 +1,16 @@ +case class Pair[A, B](_1: A, _2: B) + +trait Cons[+H, +T] + +object Cons { + def apply[H, T](h: H, t: T): Cons[H, T] = ??? + def unapply[H, T](t: Cons[H, T]): Option[Pair[H, T]] = ??? +} + +object Test { + def main(args: Array[String]): Unit = { + Cons(Option(1), None) match { + case Cons(Some(i), None) => + } + } +} diff --git a/tests/pos/tasty/definitions.scala b/tests/pos/tasty/definitions.scala index 20d2ec89bfcf..fa40a48a5f15 100644 --- a/tests/pos/tasty/definitions.scala +++ b/tests/pos/tasty/definitions.scala @@ -102,11 +102,16 @@ object definitions { case ByName(tpt: TypeTree) } - /** Trees denoting type bounds*/ + /** Trees denoting type bounds */ case class TypeBoundsTree(loBound: TypeTree, hiBound: TypeTree) extends Tree { def tpe: Type.TypeBounds = ??? } + /** Trees denoting type infered bounds */ + case class SyntheticBounds() extends Tree { + def tpe: Type.TypeBounds = ??? + } + /** Trees denoting patterns */ enum Pattern extends Positioned { def tpe: Type = ??? diff --git a/tests/run/tasty-extractors-owners.check b/tests/run/tasty-extractors-owners.check index 2bc84f66c081..a7c3a8e3b31b 100644 --- a/tests/run/tasty-extractors-owners.check +++ b/tests/run/tasty-extractors-owners.check @@ -17,11 +17,11 @@ baz2 ValDef("foo2", TypeTree.Synthetic(), None) -ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Synthetic()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None))) +ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", SyntheticBounds()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None))) b -ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Synthetic()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None))) +ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", SyntheticBounds()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None))) b2 -ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", TypeTree.Synthetic()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None))) +ClassDef("A", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(TypeDef("B", SyntheticBounds()), DefDef("b", Nil, Nil, TypeTree.Synthetic(), None), ValDef("b2", TypeTree.Synthetic(), None)))