Skip to content

Addressed issue 8163 to add opaque alias info to Reflection API #8176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,10 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend

def TypeRef_name(self: TypeRef)(given Context): String = self.name.toString

def TypeRef_isOpaqueAlias(self: TypeRef)(given Context): Boolean = self.symbol.isOpaqueAlias

def TypeRef_opaqueAliasWrappedType(self: TypeRef)(given Context): Type = self.translucentSuperType

type NamedTermRef = Types.NamedType

def isInstanceOfNamedTermRef(given ctx: Context): IsInstanceOf[NamedTermRef] = new {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
compileFilesInDir("tests/run-staging", withStagingOptions),
compileFilesInDir("tests/run-custom-args/tasty-inspector", withTastyInspectorOptions),
compileDir("tests/run-custom-args/tasty-interpreter", withTastyInspectorOptions),
compileFile("tests/run-custom-args/i8163.scala", withTastyInspectorOptions),
).checkRuns()
}

Expand Down
2 changes: 2 additions & 0 deletions library/src/scala/tasty/Reflection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,8 @@ class Reflection(private[scala] val internal: CompilerInterface) { self =>
extension TypeRefOps on (self: TypeRef) {
def qualifier(given ctx: Context): TypeOrBounds /* Type | NoPrefix */ = internal.TypeRef_qualifier(self)
def name(given ctx: Context): String = internal.TypeRef_name(self)
def isOpaqueAlias(given ctx: Context): Boolean = internal.TypeRef_isOpaqueAlias(self)
def opaqueAliasWrappedType(given ctx: Context): Type = internal.TypeRef_opaqueAliasWrappedType(self)
}

given (given Context): IsInstanceOf[SuperType] = internal.isInstanceOfSuperType
Expand Down
2 changes: 2 additions & 0 deletions library/src/scala/tasty/reflect/CompilerInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,8 @@ trait CompilerInterface {

def TypeRef_qualifier(self: TypeRef)(given ctx: Context): TypeOrBounds
def TypeRef_name(self: TypeRef)(given Context): String
def TypeRef_isOpaqueAlias(self: TypeRef)(given Context): Boolean
def TypeRef_opaqueAliasWrappedType(self: TypeRef)(given Context): Type

/** Type of a `super` reference */
type SuperType <: Type
Expand Down
48 changes: 48 additions & 0 deletions tests/run-custom-args/i8163.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import scala.tasty.Reflection
import scala.tasty.inspector._

opaque type PhoneNumber = String

case class I8163() {
val phone: PhoneNumber = "555-555-5555".asInstanceOf[PhoneNumber]
val other: String = "not a phone"
}

object Test {
def main(args: Array[String]): Unit = {
new TestInspector().inspect("", List("I8163"))
}
}

class TestInspector() extends TastyInspector

protected def processCompilationUnit(reflect: Reflection)(root: reflect.Tree): Unit =
import reflect._
inspectClass(reflect)(root)

private def inspectClass(reflect: Reflection)(tree: reflect.Tree): Unit =
import reflect.{given,_}
tree match {
case t: reflect.PackageClause =>
t.stats.map( m => inspectClass(reflect)(m) )
case t: reflect.ClassDef if !t.name.endsWith("$") =>
val interestingVals = t.body.collect {
case v: ValDef => v
}
val shouldBePhone = interestingVals.find(_.name == "phone").get
val shouldBePhoneType = shouldBePhone.tpt.tpe match {
case tr: TypeRef => tr
case _ => throw new Exception("unexpected")
}
assert(shouldBePhoneType.isOpaqueAlias)
assert(shouldBePhoneType.opaqueAliasWrappedType.show == "scala.Predef.String")

val shouldNotBePhone = interestingVals.find(_.name == "other").get
val shouldNotBePhoneType = shouldNotBePhone.tpt.tpe match {
case tr: TypeRef => tr
case _ => throw new Exception("unexpected")
}
assert(!shouldNotBePhoneType.isOpaqueAlias)

case x =>
}