@@ -16,6 +16,7 @@ import transform.TypeUtils._
16
16
import transform .SyntheticMembers ._
17
17
import util .Property
18
18
import annotation .{tailrec , constructorOnly }
19
+ import collection .mutable
19
20
20
21
/** Synthesize terms for special classes */
21
22
class Synthesizer (typer : Typer )(using @ constructorOnly c : Context ):
@@ -375,14 +376,120 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
375
376
synthesizedSumMirror(formal, span)
376
377
case _ => EmptyTree
377
378
379
+ private def escapeJavaArray (elemTp : Type )(using Context ): Type = elemTp match
380
+ case JavaArrayType (elemTp1) => defn.ArrayOf (escapeJavaArray(elemTp1))
381
+ case _ => elemTp
382
+
383
+ private enum ManifestKind :
384
+ case Full , Opt , Clss
385
+
386
+ /** The kind that should be used for an array element, if we are `OptManifest` then this
387
+ * prevents wildcards arguments of Arrays being converted to `NoManifest`
388
+ */
389
+ def arrayElem = if this == Full then this else Clss
390
+
391
+ end ManifestKind
392
+
393
+ /** Manifest factory that does enough to satisfy the equality semantics for
394
+ * - `scala.reflect.OptManifest` (only runtime class is recorded)
395
+ * - `scala.reflect.Manifest` (runtime class of arguments are recorded, with wildcard upper bounds wrapped)
396
+ * however,`toString` may be different.
397
+ *
398
+ * There are some differences to `ClassTag`,
399
+ * e.g. in Scala 2 `manifest[Int @unchecked]` will fail, but `classTag[Int @unchecked]` succeeds.
400
+ */
401
+ private def manifestFactoryOf (kind : ManifestKind ): SpecialHandler = (formal, span) =>
402
+ import ManifestKind .*
403
+
404
+ /* Creates a tree that calls the factory method called constructor in object scala.reflect.Manifest */
405
+ def factoryManifest (constructor : TermName , tparg : Type , args : Tree * ): Tree =
406
+ if args.contains(EmptyTree ) then
407
+ EmptyTree
408
+ else
409
+ val factory = if kind == Full then defn.ManifestFactoryModule else defn.ClassManifestFactoryModule
410
+ applyOverloaded(ref(factory), constructor, args.toList, tparg :: Nil , Types .WildcardType ).withSpan(span)
411
+
412
+ /* Creates a tree representing one of the singleton manifests.*/
413
+ def singletonManifest (name : TermName ) =
414
+ ref(defn.ManifestFactoryModule ).select(name).ensureApplied.withSpan(span)
415
+
416
+ def synthArrayManifest (elemTp : Type , kind : ManifestKind , topLevel : Boolean ): Tree =
417
+ factoryManifest(nme.arrayType, elemTp, synthesize(elemTp, kind.arrayElem, topLevel))
418
+
419
+ /** manifests generated from wildcards can not equal Int,Long,Any,AnyRef,AnyVal etc,
420
+ * so we wrap their upper bound.
421
+ */
422
+ def synthWildcardManifest (tp : Manifestable , hi : Type , topLevel : Boolean ): Tree =
423
+ factoryManifest(nme.wildcardType, tp, singletonManifest(nme.Nothing ), synthesize(hi, Full , topLevel))
424
+
425
+ /** `Nil` if not full manifest */
426
+ def synthArgManifests (tp : Manifestable ): List [Tree ] = tp match
427
+ case AppliedType (_, args) if kind == Full && tp.typeSymbol.isClass =>
428
+ args.map(synthesize(_, Full , topLevel = false ))
429
+ case _ =>
430
+ Nil
431
+
432
+ /** This type contains all top-level types supported by Scala 2's algorithm */
433
+ type Manifestable =
434
+ ThisType | TermRef | ConstantType | TypeRef | AppliedType | TypeBounds | RecType | RefinedType | AndType
435
+
436
+ /** adapted from `syntheticClassTag` */
437
+ def synthManifest (tp : Manifestable , kind : ManifestKind , topLevel : Boolean ) = tp match
438
+ case defn.ArrayOf (elemTp) => synthArrayManifest(elemTp, kind, topLevel)
439
+ case TypeBounds (_, hi) if kind == Full => synthWildcardManifest(tp, hi, topLevel)
440
+
441
+ case tp
442
+ if hasStableErasure(tp)
443
+ && ! tp.typeSymbol.isOpaqueAlias // if we support opaques we would need to fully dealias first
444
+ && ! (topLevel && defn.isBottomClassAfterErasure(tp.typeSymbol)) =>
445
+ val sym = tp.typeSymbol
446
+ if sym.isPrimitiveValueClass || defn.SpecialManifestClasses .contains(sym) then
447
+ singletonManifest(sym.name.toTermName)
448
+ else
449
+ erasure(tp) match
450
+ case JavaArrayType (elemTp) =>
451
+ synthArrayManifest(escapeJavaArray(elemTp), kind, topLevel)
452
+
453
+ case etp =>
454
+ val clsArg = clsOf(etp).asInstance(defn.ClassType (tp)) // cast needed to resolve overloading
455
+ factoryManifest(nme.classType, tp, (clsArg :: synthArgManifests(tp))* )
456
+
457
+ case _ =>
458
+ EmptyTree
459
+
460
+ end synthManifest
461
+
462
+ def manifestOfType (tp0 : Type , kind : ManifestKind , topLevel : Boolean ): Tree = tp0.dealiasKeepAnnots match
463
+ case tp1 : Manifestable => synthManifest(tp1, kind, topLevel)
464
+ case tp1 => EmptyTree
465
+
466
+ def synthesize (tp : Type , kind : ManifestKind , topLevel : Boolean ): Tree =
467
+ manifestOfType(tp, kind, topLevel) match
468
+ case EmptyTree if kind == Opt => ref(defn.NoManifestModule )
469
+ case result => result
470
+
471
+ formal.argInfos match
472
+ case arg :: Nil =>
473
+ synthesize(fullyDefinedType(arg, " Manifest argument" , span), kind, topLevel = true )
474
+ case _ =>
475
+ EmptyTree
476
+
477
+ end manifestFactoryOf
478
+
479
+ val synthesizedManifest : SpecialHandler = manifestFactoryOf(ManifestKind .Full )
480
+ val synthesizedOptManifest : SpecialHandler = manifestFactoryOf(ManifestKind .Opt )
481
+
378
482
val specialHandlers = List (
379
483
defn.ClassTagClass -> synthesizedClassTag,
380
484
defn.TypeTestClass -> synthesizedTypeTest,
381
485
defn.CanEqualClass -> synthesizedCanEqual,
382
486
defn.ValueOfClass -> synthesizedValueOf,
383
487
defn.Mirror_ProductClass -> synthesizedProductMirror,
384
488
defn.Mirror_SumClass -> synthesizedSumMirror,
385
- defn.MirrorClass -> synthesizedMirror)
489
+ defn.MirrorClass -> synthesizedMirror,
490
+ defn.ManifestClass -> synthesizedManifest,
491
+ defn.OptManifestClass -> synthesizedOptManifest,
492
+ )
386
493
387
494
def tryAll (formal : Type , span : Span )(using Context ): Tree =
388
495
def recur (handlers : SpecialHandlers ): Tree = handlers match
0 commit comments