From 64d248d12db10cd64bfbc3c96618e855b6753b78 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 19 Jun 2018 09:57:01 +0200 Subject: [PATCH 1/2] Fix type of Tasty.Type.TypeSelect.prefix Previously we did not support type trees as prefixes --- .../src/dotty/tools/dotc/tastyreflect/TastyImpl.scala | 2 +- library/src/scala/tasty/Tasty.scala | 2 +- library/src/scala/tasty/util/ShowExtractors.scala | 7 ++++++- library/src/scala/tasty/util/ShowSourceCode.scala | 7 +++---- library/src/scala/tasty/util/TreeAccumulator.scala | 3 ++- tests/pos/simpleTypeSelect.decompiled | 8 ++++++++ tests/pos/simpleTypeSelect.scala | 5 +++++ tests/pos/tasty/definitions.scala | 2 +- 8 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 tests/pos/simpleTypeSelect.decompiled create mode 100644 tests/pos/simpleTypeSelect.scala diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala index 7d33317a9eef..73961f5e380f 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala @@ -555,7 +555,7 @@ object TastyImpl extends scala.tasty.Tasty { } object TypeSelect extends TypeSelectExtractor { - def unapply(x: TypeTree)(implicit ctx: Context): Option[(Term, String)] = x match { + def unapply(x: TypeTree)(implicit ctx: Context): Option[(Parent, String)] = x match { case x: tpd.Select @unchecked if x.isType => Some(x.qualifier, x.name.toString) case _ => None } diff --git a/library/src/scala/tasty/Tasty.scala b/library/src/scala/tasty/Tasty.scala index e66f4fe76fc4..9658b970fba5 100644 --- a/library/src/scala/tasty/Tasty.scala +++ b/library/src/scala/tasty/Tasty.scala @@ -435,7 +435,7 @@ abstract class Tasty { tasty => val TypeSelect: TypeSelectExtractor abstract class TypeSelectExtractor { - def unapply(x: TypeTree)(implicit ctx: Context): Option[(Term, String)] + def unapply(x: TypeTree)(implicit ctx: Context): Option[(Parent, String)] } val Singleton: SingletonExtractor diff --git a/library/src/scala/tasty/util/ShowExtractors.scala b/library/src/scala/tasty/util/ShowExtractors.scala index 6f2b0e83c313..92dd91966989 100644 --- a/library/src/scala/tasty/util/ShowExtractors.scala +++ b/library/src/scala/tasty/util/ShowExtractors.scala @@ -95,7 +95,12 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case TypeTree.TypeIdent(name) => this += "TypeTree.TypeIdent(\"" += name += "\")" case TypeTree.TypeSelect(qualifier, name) => - this += "TypeTree.TypeSelect(" += qualifier += ", \"" += name += "\")" + this += "TypeTree.TypeSelect(" + qualifier match { + case qualifier @ Term() => this += qualifier + case qualifier @ TypeTree() => this += qualifier + } + this += ", \"" += name += "\")" case TypeTree.Singleton(ref) => this += "TypeTree.Singleton(" += ref += ")" case TypeTree.And(left, right) => diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index 86a1b629bc75..abd655c4ace5 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -702,11 +702,10 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty printType(tree.tpe) case TypeTree.TypeSelect(qual, name) => - (qual: Any) match { - case qual @ TypeTree.TypeIdent(_) => printTypeTree(qual) // FIXME: qual is of type Tree buy we are getting a TypeTree qualifier - case _ => printTree(qual) + qual match { + case qual @ Term() => printTree(qual) += "." += name + case qual @ TypeTree() => printTypeTree(qual) += "#" += name } - this += "." += name case TypeTree.Singleton(ref) => printTree(ref) diff --git a/library/src/scala/tasty/util/TreeAccumulator.scala b/library/src/scala/tasty/util/TreeAccumulator.scala index e147340715c4..98e839e021c7 100644 --- a/library/src/scala/tasty/util/TreeAccumulator.scala +++ b/library/src/scala/tasty/util/TreeAccumulator.scala @@ -81,7 +81,8 @@ abstract class TreeAccumulator[X, T <: Tasty with Singleton](val tasty: T) { def foldOverTypeTree(x: X, tree: TypeOrBoundsTree)(implicit ctx: Context): X = tree match { case TypeTree.Synthetic() => x case TypeTree.TypeIdent(_) => x - case TypeTree.TypeSelect(qualifier, _) => foldTree(x, qualifier) + case TypeTree.TypeSelect(qualifier @ Term(), _) => foldTree(x, qualifier) + case TypeTree.TypeSelect(qualifier @ TypeTree(), _) => foldTypeTree(x, qualifier) case TypeTree.Singleton(ref) => foldTree(x, ref) case TypeTree.And(left, right) => foldTypeTree(foldTypeTree(x, left), right) case TypeTree.Or(left, right) => foldTypeTree(foldTypeTree(x, left), right) diff --git a/tests/pos/simpleTypeSelect.decompiled b/tests/pos/simpleTypeSelect.decompiled new file mode 100644 index 000000000000..4619340bb43b --- /dev/null +++ b/tests/pos/simpleTypeSelect.decompiled @@ -0,0 +1,8 @@ +/** Decompiled from out/posTestFromTasty/pos/simpleTypeSelect/Foo.class */ +trait Foo() extends java.lang.Object { + type Bar +} +/** Decompiled from out/posTestFromTasty/pos/simpleTypeSelect/Test.class */ +object Test { + val x: Foo#Bar = scala.Predef.??? +} diff --git a/tests/pos/simpleTypeSelect.scala b/tests/pos/simpleTypeSelect.scala new file mode 100644 index 000000000000..2aa4d3e913e1 --- /dev/null +++ b/tests/pos/simpleTypeSelect.scala @@ -0,0 +1,5 @@ + +trait Foo { type Bar } +object Test { + val x: Foo#Bar = ??? +} diff --git a/tests/pos/tasty/definitions.scala b/tests/pos/tasty/definitions.scala index a90e6912e7c3..147b7886b411 100644 --- a/tests/pos/tasty/definitions.scala +++ b/tests/pos/tasty/definitions.scala @@ -92,7 +92,7 @@ object definitions { def tpe: Type = ??? case Synthetic() case Ident(name: String, override val tpe: Type) - case Select(prefix: Term, name: String) + case Select(prefix: Term | TypeTree, name: String) case Singleton(ref: Term) case Refined(underlying: TypeTree, refinements: List[Definition]) case Applied(tycon: TypeTree, args: List[TypeTree | TypeBoundsTree]) From a3b24869303d26636bde1c87318d5ad430ed6b32 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 19 Jun 2018 10:09:35 +0200 Subject: [PATCH 2/2] Split TypeSelect into TypeSelect and TermSelect To make it easier to consume the API. --- .../src/dotty/tools/dotc/tastyreflect/TastyImpl.scala | 11 +++++++++-- library/src/scala/tasty/Tasty.scala | 7 ++++++- library/src/scala/tasty/util/ShowExtractors.scala | 9 +++------ library/src/scala/tasty/util/ShowSourceCode.scala | 10 +++++----- library/src/scala/tasty/util/TreeAccumulator.scala | 4 ++-- tests/pos/tasty/definitions.scala | 3 ++- tests/run/tasty-extractors-2.check | 4 ++-- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala index 73961f5e380f..c1981f6c6edd 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/TastyImpl.scala @@ -554,9 +554,16 @@ object TastyImpl extends scala.tasty.Tasty { } } + object TermSelect extends TermSelectExtractor { + def unapply(x: TypeTree)(implicit ctx: Context): Option[(Term, String)] = x match { + case x: tpd.Select @unchecked if x.isType && x.qualifier.isTerm => Some(x.qualifier, x.name.toString) + case _ => None + } + } + object TypeSelect extends TypeSelectExtractor { - def unapply(x: TypeTree)(implicit ctx: Context): Option[(Parent, String)] = x match { - case x: tpd.Select @unchecked if x.isType => Some(x.qualifier, x.name.toString) + def unapply(x: TypeTree)(implicit ctx: Context): Option[(TypeTree, String)] = x match { + case x: tpd.Select @unchecked if x.isType && x.qualifier.isType => Some(x.qualifier, x.name.toString) case _ => None } } diff --git a/library/src/scala/tasty/Tasty.scala b/library/src/scala/tasty/Tasty.scala index 9658b970fba5..4c6f11350f8e 100644 --- a/library/src/scala/tasty/Tasty.scala +++ b/library/src/scala/tasty/Tasty.scala @@ -433,9 +433,14 @@ abstract class Tasty { tasty => def unapply(x: TypeTree)(implicit ctx: Context): Option[String] } + val TermSelect: TermSelectExtractor + abstract class TermSelectExtractor { + def unapply(x: TypeTree)(implicit ctx: Context): Option[(Term, String)] + } + val TypeSelect: TypeSelectExtractor abstract class TypeSelectExtractor { - def unapply(x: TypeTree)(implicit ctx: Context): Option[(Parent, String)] + def unapply(x: TypeTree)(implicit ctx: Context): Option[(TypeTree, String)] } val Singleton: SingletonExtractor diff --git a/library/src/scala/tasty/util/ShowExtractors.scala b/library/src/scala/tasty/util/ShowExtractors.scala index 92dd91966989..72c143c41db6 100644 --- a/library/src/scala/tasty/util/ShowExtractors.scala +++ b/library/src/scala/tasty/util/ShowExtractors.scala @@ -94,13 +94,10 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty this += "TypeTree.Synthetic()" case TypeTree.TypeIdent(name) => this += "TypeTree.TypeIdent(\"" += name += "\")" + case TypeTree.TermSelect(qualifier, name) => + this += "TypeTree.TermSelect(" += qualifier += ", \"" += name += "\")" case TypeTree.TypeSelect(qualifier, name) => - this += "TypeTree.TypeSelect(" - qualifier match { - case qualifier @ Term() => this += qualifier - case qualifier @ TypeTree() => this += qualifier - } - this += ", \"" += name += "\")" + this += "TypeTree.TypeSelect(" += qualifier += ", \"" += name += "\")" case TypeTree.Singleton(ref) => this += "TypeTree.Singleton(" += ref += ")" case TypeTree.And(left, right) => diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index abd655c4ace5..b128ebe8d4ec 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -85,7 +85,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty val parents1 = parents.filter { case Term.Apply(Term.Select(Term.New(tpt), _, _), _) => !Types.JavaLangObject.unapply(tpt.tpe) - case TypeTree.TypeSelect(Term.Select(Term.Ident("_root_"), "scala", _), "Product") => false + case TypeTree.TermSelect(Term.Select(Term.Ident("_root_"), "scala", _), "Product") => false case _ => true } if (parents1.nonEmpty) { @@ -701,11 +701,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case TypeTree.TypeIdent(name) => printType(tree.tpe) + case TypeTree.TermSelect(qual, name) => + printTree(qual) += "." += name + case TypeTree.TypeSelect(qual, name) => - qual match { - case qual @ Term() => printTree(qual) += "." += name - case qual @ TypeTree() => printTypeTree(qual) += "#" += name - } + printTypeTree(qual) += "#" += name case TypeTree.Singleton(ref) => printTree(ref) diff --git a/library/src/scala/tasty/util/TreeAccumulator.scala b/library/src/scala/tasty/util/TreeAccumulator.scala index 98e839e021c7..c2da959397b9 100644 --- a/library/src/scala/tasty/util/TreeAccumulator.scala +++ b/library/src/scala/tasty/util/TreeAccumulator.scala @@ -81,8 +81,8 @@ abstract class TreeAccumulator[X, T <: Tasty with Singleton](val tasty: T) { def foldOverTypeTree(x: X, tree: TypeOrBoundsTree)(implicit ctx: Context): X = tree match { case TypeTree.Synthetic() => x case TypeTree.TypeIdent(_) => x - case TypeTree.TypeSelect(qualifier @ Term(), _) => foldTree(x, qualifier) - case TypeTree.TypeSelect(qualifier @ TypeTree(), _) => foldTypeTree(x, qualifier) + case TypeTree.TermSelect(qualifier, _) => foldTree(x, qualifier) + case TypeTree.TypeSelect(qualifier, _) => foldTypeTree(x, qualifier) case TypeTree.Singleton(ref) => foldTree(x, ref) case TypeTree.And(left, right) => foldTypeTree(foldTypeTree(x, left), right) case TypeTree.Or(left, right) => foldTypeTree(foldTypeTree(x, left), right) diff --git a/tests/pos/tasty/definitions.scala b/tests/pos/tasty/definitions.scala index 147b7886b411..7d1568824afa 100644 --- a/tests/pos/tasty/definitions.scala +++ b/tests/pos/tasty/definitions.scala @@ -92,7 +92,8 @@ object definitions { def tpe: Type = ??? case Synthetic() case Ident(name: String, override val tpe: Type) - case Select(prefix: Term | TypeTree, name: String) + case TermSelect(prefix: Term, name: String) + case TypeSelect(prefix: TypeTree, name: String) case Singleton(ref: Term) case Refined(underlying: TypeTree, refinements: List[Definition]) case Applied(tycon: TypeTree, args: List[TypeTree | TypeBoundsTree]) diff --git a/tests/run/tasty-extractors-2.check b/tests/run/tasty-extractors-2.check index 3247ffb7a635..2baf5ba3e382 100644 --- a/tests/run/tasty-extractors-2.check +++ b/tests/run/tasty-extractors-2.check @@ -100,10 +100,10 @@ Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef(" Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(List(ValDef("i", TypeTree.TypeIdent("Int"), None))), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(ValDef("i", TypeTree.Synthetic(), None))), ClassDef("Bar", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.TypeIdent("Foo")), "", Some(Signature(List(scala.Int), Test$._$Foo))), List(Term.Literal(Constant.Int(1))))), None, Nil)), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) -Term.Block(List(ClassDef("Foo", 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("X", TypeTree.TypeIdent("Int")))), DefDef("f", Nil, List(List(ValDef("a", TypeTree.TypeIdent("Foo"), None))), TypeTree.TypeSelect(Term.Ident("a"), "X"), Some(Term.Ident("???")))), Term.Literal(Constant.Unit())) +Term.Block(List(ClassDef("Foo", 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("X", TypeTree.TypeIdent("Int")))), DefDef("f", Nil, List(List(ValDef("a", TypeTree.TypeIdent("Foo"), None))), TypeTree.TermSelect(Term.Ident("a"), "X"), Some(Term.Ident("???")))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) -Term.Block(List(ClassDef("Foo", 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("X", TypeBoundsTree(TypeTree.Synthetic(), TypeTree.Synthetic())))), DefDef("f", Nil, List(List(ValDef("a", TypeTree.Refined(TypeTree.TypeIdent("Foo"), List(TypeDef("X", TypeTree.TypeIdent("Int")))), None))), TypeTree.TypeSelect(Term.Ident("a"), "X"), Some(Term.Ident("???")))), Term.Literal(Constant.Unit())) +Term.Block(List(ClassDef("Foo", 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("X", TypeBoundsTree(TypeTree.Synthetic(), TypeTree.Synthetic())))), DefDef("f", Nil, List(List(ValDef("a", TypeTree.Refined(TypeTree.TypeIdent("Foo"), List(TypeDef("X", TypeTree.TypeIdent("Int")))), None))), TypeTree.TermSelect(Term.Ident("a"), "X"), Some(Term.Ident("???")))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) Term.Block(List(ValDef("lambda", TypeTree.Applied(TypeTree.Synthetic(), List(TypeTree.TypeIdent("Int"), TypeTree.TypeIdent("Int"))), Some(Term.Block(List(DefDef("$anonfun", Nil, List(List(ValDef("x", TypeTree.Synthetic(), None))), TypeTree.Synthetic(), Some(Term.Ident("x")))), Term.Lambda(Term.Ident("$anonfun"), None))))), Term.Literal(Constant.Unit()))