@@ -4,18 +4,21 @@ package typer
4
4
5
5
import core ._
6
6
import util .Spans .Span
7
+ import unpickleScala2 .Scala2Erasure
7
8
import Contexts ._
8
9
import Types ._ , Flags ._ , Symbols ._ , Types ._ , Names ._ , StdNames ._ , Constants ._
9
10
import TypeErasure .{erasure , hasStableErasure }
10
11
import Decorators ._
11
12
import ProtoTypes ._
12
13
import Inferencing .{fullyDefinedType , isFullyDefined }
14
+ import Implicits .SearchSuccess
13
15
import ast .untpd
14
16
import transform .SymUtils ._
15
17
import transform .TypeUtils ._
16
18
import transform .SyntheticMembers ._
17
19
import util .Property
18
20
import annotation .{tailrec , constructorOnly }
21
+ import collection .mutable
19
22
20
23
/** Synthesize terms for special classes */
21
24
class Synthesizer (typer : Typer )(using @ constructorOnly c : Context ):
@@ -375,14 +378,204 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
375
378
synthesizedSumMirror(formal, span)
376
379
case _ => EmptyTree
377
380
381
+ private type Scala2RefinedType = RecType | RefinedType | AndType
382
+
383
+ /** @see dotty.tools.dotc.core.unpickleScala2.Scala2Erasure.flattenedParents */
384
+ private object Scala2RefinedType :
385
+
386
+ def unapply (tp : Scala2RefinedType )(using Context ): Option [List [Type ]] =
387
+
388
+ def checkSupported (tp : Type ): Boolean = tp match
389
+ case AnnotatedType (_, _) => false
390
+ case tp @ TypeRef (prefix, _) => ! (! tp.symbol.exists && prefix.dealias.isInstanceOf [Scala2RefinedType ])
391
+ case ground => true
392
+
393
+ @ tailrec
394
+ def inner (explore : List [Type ], acc : mutable.ListBuffer [Type ]): Option [List [Type ]] = explore match
395
+ case tp :: rest => tp match
396
+ case tp : RecType => inner(tp.parent :: rest, acc)
397
+ case RefinedType (parent, _, _) => inner(parent :: rest, acc)
398
+ case AndType (l, r) => inner(l :: r :: rest, acc)
399
+ case tp if checkSupported(tp) => inner(rest, acc += tp)
400
+ case _ => None // we can not create a manifest for unsupported parents
401
+
402
+ case nil => Some (acc.toList)
403
+ end inner
404
+
405
+ inner(tp :: Nil , new mutable.ListBuffer ())
406
+
407
+ end unapply
408
+
409
+ end Scala2RefinedType
410
+
411
+ /** Replication of the `Implicits.ImplicitSearch.manifestOfType` algorithm found in nsc compiler.
412
+ * @see (https://github.com/scala/scala/blob/0c011547b1ccf961ca427c3d3459955e618e93d5/src/compiler/scala/tools/nsc/typechecker/Implicits.scala#L1519)
413
+ */
414
+ private def manifestOfFactory (flavor : Symbol ): SpecialHandler = (formal, span) =>
415
+
416
+ def materializeImplicit (formal : Type , span : Span )(using Context ): Tree =
417
+ val arg = typer.inferImplicitArg(formal, span)
418
+ if arg.tpe.isError then
419
+ EmptyTree
420
+ else
421
+ arg
422
+
423
+ def inner (tp : Type , flavour : Symbol ): Tree =
424
+
425
+ val full = flavor == defn.ManifestClass
426
+ val opt = flavor == defn.OptManifestClass
427
+
428
+ /* Creates a tree that calls the factory method called constructor in object scala.reflect.Manifest */
429
+ def manifestFactoryCall (constructor : TermName , tparg : Type , args : Tree * ): Tree =
430
+ if args contains EmptyTree then
431
+ EmptyTree
432
+ else
433
+ val factory = if full then defn.ManifestFactoryModule else defn.ClassManifestFactoryModule
434
+ applyOverloaded(ref(factory), constructor, args.toList, tparg :: Nil , Types .WildcardType )
435
+ .withSpan(span)
436
+
437
+ /* Creates a tree representing one of the singleton manifests.*/
438
+ def findSingletonManifest (name : TermName ) =
439
+ ref(defn.ManifestFactoryModule )
440
+ .select(name)
441
+ .ensureApplied
442
+ .withSpan(span)
443
+
444
+ /** Re-wraps a type in a manifest before calling `materializeImplicit` on the result
445
+ *
446
+ * TODO: in scala 2 if not full the default is `reflect.ClassManifest`,
447
+ * not `reflect.ClassTag`, which is treated differently.
448
+ */
449
+ def findManifest (tp : Type , manifestClass : Symbol = if full then defn.ManifestClass else NoSymbol ) =
450
+ if manifestClass.exists then
451
+ materializeImplicit(manifestClass.typeRef.appliedTo(tp), span)
452
+ else
453
+ inner(tp, NoSymbol ) // workaround so that a `ClassManifest` will be generated
454
+
455
+ def findSubManifest (tp : Type ) =
456
+ findManifest(tp, if (full) defn.ManifestClass else defn.OptManifestClass )
457
+
458
+ def inferTypeTag (tp : Type ) =
459
+ if defn.TypeTagType .exists then
460
+ typer.inferImplicit(defn.TypeTagType .appliedTo(tp), EmptyTree , span) match
461
+ case SearchSuccess (tagInScope, _, _, _) => Some (tagInScope)
462
+ case _ => None
463
+ else
464
+ None
465
+
466
+ def interopTypeTag (tp : Type , tagInScope : Tree ) =
467
+ materializeImplicit(defn.ClassTagClass .typeRef.appliedTo(tp), span) match
468
+ case EmptyTree =>
469
+ report.error(i """ To create a Manifest here, it is necessary to interoperate with the
470
+ |TypeTag ` $tagInScope` in scope. However TypeTag to Manifest conversion requires a
471
+ |ClassTag for the corresponding type to be present.
472
+ |To proceed add a ClassTag for the type ` $tp` (e.g. by introducing a context bound)
473
+ |and recompile. """ .stripMargin, ctx.source.atSpan(span))
474
+ EmptyTree
475
+ case clsTag =>
476
+ // if TypeTag is available, assume scala.reflect.runtime.universe is also
477
+ val ru = ref(defn.ReflectRuntimePackageObject_universe )
478
+ val optEnclosing = ctx.owner.enclosingClass
479
+ if optEnclosing.exists then
480
+ val enclosing = ref(defn.Predef_classOf ).appliedToType(optEnclosing.typeRef)
481
+ val classLoader = enclosing.select(nme.getClassLoader).ensureApplied
482
+ val currentMirror = ru.select(nme.runtimeMirror).appliedTo(classLoader)
483
+ ru.select(nme.internal)
484
+ .select(nme.typeTagToManifest)
485
+ .appliedToType(tp)
486
+ .appliedTo(currentMirror, tagInScope)
487
+ .appliedTo(clsTag)
488
+ .withSpan(span)
489
+ else
490
+ EmptyTree
491
+
492
+ def manifestOfType (tp0 : Type ): Tree =
493
+
494
+ val tp1 = tp0.dealiasKeepAnnots
495
+
496
+ extension [T ](xs : List [T ]) def isSingleton = xs.lengthCompare(1 ) == 0
497
+
498
+ def classManifest (clsRef : Type , args : List [Type ]): Tree =
499
+ val classarg = ref(defn.Predef_classOf ).appliedToType(tp1)
500
+ val suffix0 = classarg :: (args map findSubManifest)
501
+ val pre = clsRef.normalizedPrefix
502
+ val ignorePrefix = (pre eq NoPrefix ) || pre.typeSymbol.isStaticOwner
503
+ val suffix = if ignorePrefix then suffix0 else findSubManifest(pre) :: suffix0
504
+ manifestFactoryCall(nme.classType, tp, suffix* )
505
+
506
+ tp1 match
507
+ case ThisType (_) | TermRef (_,_) => manifestFactoryCall(nme.singleType, tp, singleton(tp1))
508
+ case ConstantType (c) => inner(c.tpe, defn.ManifestClass )
509
+
510
+ case tp1 @ TypeRef (pre, desig) =>
511
+ val tpSym = tp1.typeSymbol
512
+ if tpSym.isPrimitiveValueClass || defn.isPhantomClass(tpSym) then
513
+ if defn.isBottomClassAfterErasure(tpSym) then
514
+ EmptyTree // `Nothing`/`Null` manifests are ClassTags, lets not make a loophole for them
515
+ else
516
+ findSingletonManifest(tpSym.name.toTermName)
517
+ else if tpSym == defn.ObjectClass || tpSym == defn.AnyRefAlias then
518
+ findSingletonManifest(nme.Object )
519
+ else if tpSym.isClass then
520
+ classManifest(tp1, Nil )
521
+ else
522
+ EmptyTree
523
+
524
+ case tp1 @ AppliedType (tycon, args) =>
525
+ val tpSym = tycon.typeSymbol
526
+ if tpSym == defn.RepeatedParamClass then
527
+ EmptyTree
528
+ else if tpSym == defn.ArrayClass && args.isSingleton then
529
+ manifestFactoryCall(nme.arrayType, args.head, findManifest(args.head))
530
+ else if tpSym.isClass then
531
+ classManifest(tycon, args)
532
+ else
533
+ EmptyTree
534
+
535
+ case TypeBounds (lo, hi) if full =>
536
+ manifestFactoryCall(nme.wildcardType, tp, findManifest(lo), findManifest(hi))
537
+
538
+ case Scala2RefinedType (parents) =>
539
+ if parents.isSingleton then findManifest(parents.head)
540
+ else if full then manifestFactoryCall(nme.intersectionType, tp, (parents map findSubManifest)* )
541
+ else manifestOfType(Scala2Erasure .intersectionDominator(parents))
542
+
543
+ case _ =>
544
+ EmptyTree
545
+ end manifestOfType
546
+
547
+ if full then
548
+ inferTypeTag(tp) match
549
+ case Some (tagInScope) => interopTypeTag(tp, tagInScope)
550
+ case _ => manifestOfType(tp)
551
+ else
552
+ manifestOfType(tp) match
553
+ case EmptyTree if opt => ref(defn.NoManifestModule )
554
+ case result => result
555
+
556
+ end inner
557
+
558
+ formal.argInfos match
559
+ case arg :: Nil =>
560
+ inner(fullyDefinedType(arg, " Manifest argument" , span), flavor)
561
+ case _ =>
562
+ EmptyTree
563
+ end manifestOfFactory
564
+
565
+ val synthesizedManifest : SpecialHandler = manifestOfFactory(defn.ManifestClass )
566
+ val synthesizedOptManifest : SpecialHandler = manifestOfFactory(defn.OptManifestClass )
567
+
378
568
val specialHandlers = List (
379
569
defn.ClassTagClass -> synthesizedClassTag,
380
570
defn.TypeTestClass -> synthesizedTypeTest,
381
571
defn.CanEqualClass -> synthesizedCanEqual,
382
572
defn.ValueOfClass -> synthesizedValueOf,
383
573
defn.Mirror_ProductClass -> synthesizedProductMirror,
384
574
defn.Mirror_SumClass -> synthesizedSumMirror,
385
- defn.MirrorClass -> synthesizedMirror)
575
+ defn.MirrorClass -> synthesizedMirror,
576
+ defn.ManifestClass -> synthesizedManifest,
577
+ defn.OptManifestClass -> synthesizedOptManifest,
578
+ )
386
579
387
580
def tryAll (formal : Type , span : Span )(using Context ): Tree =
388
581
def recur (handlers : SpecialHandlers ): Tree = handlers match
0 commit comments