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