Skip to content

Fix #9482: implement reflect.Manifest summoning #13129

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
53 changes: 49 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ package core

import scala.annotation.{threadUnsafe => tu}
import Types._, Contexts._, Symbols._, SymDenotations._, StdNames._, Names._, Phases._
import Flags._, Scopes._, Decorators._, NameOps._, Periods._, NullOpsDecorator._
import unpickleScala2.Scala2Unpickler.ensureConstructor
import Flags._, Scopes._, Decorators._, NameOps._, Periods._, NullOpsDecorator._, Annotations.Annotation
import unpickleScala2.Scala2Unpickler, Scala2Unpickler.ensureConstructor
import scala.collection.mutable
import collection.mutable
import Denotations.SingleDenotation
Expand Down Expand Up @@ -764,7 +764,50 @@ class Definitions {
@tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable")
@tu lazy val WithoutPreciseParameterTypesClass: Symbol = requiredClass("scala.Selectable.WithoutPreciseParameterTypes")

@tu lazy val ReflectPackageClass: Symbol = requiredPackage("scala.reflect.package").moduleClass
@tu lazy val TypeTagType: Type = {
val optTypeTagsClass = getClassIfDefined("scala.reflect.api.TypeTags") // in scala-reflect module
if optTypeTagsClass ne NoSymbol then
TypeRef(optTypeTagsClass.typeRef, optTypeTagsClass.requiredClass("TypeTag"))
else
NoType
}
@tu lazy val ReflectRuntimePackageObject_universe: Symbol = {
val runtimePkg = getModuleIfDefined("scala.reflect.runtime.package")
if runtimePkg.exists then
runtimePkg.requiredValue("universe")
else
NoSymbol
}
@tu lazy val ClassManifestAlias: Symbol = ReflectPackageClass.requiredType("ClassManifest")
@tu lazy val ManifestClass: ClassSymbol = requiredClass("scala.reflect.Manifest")
@tu lazy val ManifestFactoryModule: Symbol = requiredModule("scala.reflect.ManifestFactory")
@tu lazy val ClassManifestFactoryModule: Symbol = requiredModule("scala.reflect.ClassManifestFactory")
@tu lazy val OptManifestClass: ClassSymbol = requiredClass("scala.reflect.OptManifest")
@tu lazy val NoManifestModule: Symbol = requiredModule("scala.reflect.NoManifest")

@tu lazy val ReflectPackageClass: Symbol = {

def adjustClassManifest(module: Symbol)(using Context): Unit =
// `scala.reflect.ClassManifest` is a type alias to `scala.reflect.ClassTag`,
// however we need to prevent it from being dealiased for the purpose of summoning of
// a `ClassManifest`, which has a different result in Scala 2.
// With this solution values of `ClassManifest` and `ClassTag` are still interchangeable.
val classManifest = module.moduleClass.requiredType("ClassManifest")
classManifest.infoOrCompleter match
case TypeAlias(HKTypeLambda(params, ref)) =>
val unchecked = Annotation(UncheckedAnnot) // could be any annotation really
classManifest.info = HKTypeLambda.fromParams(params, TypeBounds(ref, AnnotatedType(ref, unchecked)))
end adjustClassManifest

val module = requiredPackage("scala.reflect.package")
module.infoOrCompleter match
case completer: ModuleCompleter =>
module.info = new ModuleCompleter(completer.moduleClass):
override def complete(root: SymDenotation)(using Context): Unit =
completer.complete(root)
adjustClassManifest(module)
module.moduleClass
}
@tu lazy val ClassTagClass: ClassSymbol = requiredClass("scala.reflect.ClassTag")
@tu lazy val ClassTagModule: Symbol = ClassTagClass.companionModule
@tu lazy val ClassTagModule_apply: Symbol = ClassTagModule.requiredMethod(nme.apply)
Expand Down Expand Up @@ -1200,6 +1243,8 @@ class Definitions {

@tu lazy val untestableClasses: Set[Symbol] = Set(NothingClass, NullClass, SingletonClass)

@tu lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)

@tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)
val AbstractFunctionClassPerRun: PerRun[Array[Symbol]] = new PerRun(AbstractFunctionType.map(_.symbol.asClass))
def AbstractFunctionClass(n: Int)(using Context): Symbol = AbstractFunctionClassPerRun()(using ctx)(n)
Expand Down Expand Up @@ -1774,7 +1819,7 @@ class Definitions {
this.initCtx = ctx
if (!isInitialized) {
// force initialization of every symbol that is synthesized or hijacked by the compiler
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() :+ JavaEnumClass
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() :+ JavaEnumClass :+ ReflectPackageClass

isInitialized = true
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,6 @@ object StdNames {
val EnumValue: N = "EnumValue"
val ExistentialTypeTree: N = "ExistentialTypeTree"
val Flag : N = "Flag"
val floatHash: N = "floatHash"
val Ident: N = "Ident"
val Import: N = "Import"
val Literal: N = "Literal"
Expand Down Expand Up @@ -414,6 +413,7 @@ object StdNames {
val argv : N = "argv"
val arrayClass: N = "arrayClass"
val arrayElementClass: N = "arrayElementClass"
val arrayType: N = "arrayType"
val arrayValue: N = "arrayValue"
val array_apply : N = "array_apply"
val array_clone : N = "array_clone"
Expand All @@ -440,6 +440,7 @@ object StdNames {
val checkInitialized: N = "checkInitialized"
val ClassManifestFactory: N = "ClassManifestFactory"
val classOf: N = "classOf"
val classType: N = "classType"
val clone_ : N = "clone"
val common: N = "common"
val compiletime : N = "compiletime"
Expand Down Expand Up @@ -481,6 +482,7 @@ object StdNames {
val find_ : N = "find"
val flagsFromBits : N = "flagsFromBits"
val flatMap: N = "flatMap"
val floatHash: N = "floatHash"
val foreach: N = "foreach"
val format: N = "format"
val fromDigits: N = "fromDigits"
Expand All @@ -489,6 +491,7 @@ object StdNames {
val genericClass: N = "genericClass"
val get: N = "get"
val getClass_ : N = "getClass"
val getClassLoader: N = "getClassLoader"
val getOrElse: N = "getOrElse"
val hasNext: N = "hasNext"
val hashCode_ : N = "hashCode"
Expand All @@ -497,6 +500,7 @@ object StdNames {
val head: N = "head"
val higherKinds: N = "higherKinds"
val identity: N = "identity"
val intersectionType: N = "intersectionType"
val implicitConversions: N = "implicitConversions"
val implicitly: N = "implicitly"
val in: N = "in"
Expand Down Expand Up @@ -588,6 +592,7 @@ object StdNames {
val setSymbol: N = "setSymbol"
val setType: N = "setType"
val setTypeSignature: N = "setTypeSignature"
val singleType: N = "singleType"
val standardInterpolator: N = "standardInterpolator"
val staticClass : N = "staticClass"
val staticModule : N = "staticModule"
Expand Down Expand Up @@ -626,6 +631,7 @@ object StdNames {
val values: N = "values"
val view_ : N = "view"
val wait_ : N = "wait"
val wildcardType: N = "wildcardType"
val withFilter: N = "withFilter"
val withFilterIfRefutable: N = "withFilterIfRefutable$"
val WorksheetWrapper: N = "WorksheetWrapper"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
case tp: AndOrType =>
// scalajs.js.|.UnionOps has a type parameter upper-bounded by `_ | _`
tp.derivedAndOrType(mapArg(tp.tp1).bounds.hi, mapArg(tp.tp2).bounds.hi)
case tp @ AnnotatedType(inner, annot) =>
// added to support hijacking of `scala.reflect.ClassManifest`,
// we set its info to `[T] >: ClassTag[T] <: ClassTag[T] @unchecked`
val inner1 = elim(inner)
tp.derivedAnnotatedType(inner1, annot)
case _ =>
tp
}
Expand Down
Loading