@@ -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,200 @@ 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
+ /** Creates a tree that calls the relevant factory method in object
412
+ * scala.reflect.Manifest for type 'tp'. An EmptyTree is returned if
413
+ * no manifest is found. todo: make this instantiate take type params as well?
414
+ */
415
+ private def manifestOfFactory (flavor : Symbol ): SpecialHandler = (formal, span) =>
416
+
417
+ def materializeImplicit (formal : Type , span : Span )(using Context ): Tree =
418
+ val arg = typer.inferImplicitArg(formal, span)
419
+ if arg.tpe.isError then
420
+ EmptyTree
421
+ else
422
+ arg
423
+
424
+ def inner (tp : Type , flavour : Symbol ): Tree =
425
+
426
+ val full = flavor == defn.ManifestClass
427
+ val opt = flavor == defn.OptManifestClass
428
+
429
+ /* Creates a tree that calls the factory method called constructor in object scala.reflect.Manifest */
430
+ def manifestFactoryCall (constructor : TermName , tparg : Type , args : Tree * ): Tree =
431
+ if args contains EmptyTree then
432
+ EmptyTree
433
+ else
434
+ val factory = if full then defn.ManifestFactoryModule else defn.ClassManifestFactoryModule
435
+ applyOverloaded(ref(factory), constructor, args.toList, tparg :: Nil , Types .WildcardType )
436
+ .withSpan(span)
437
+
438
+ /* Creates a tree representing one of the singleton manifests.*/
439
+ def findSingletonManifest (name : TermName ) =
440
+ ref(defn.ManifestFactoryModule )
441
+ .select(name)
442
+ .ensureApplied
443
+ .withSpan(span)
444
+
445
+ /** Re-wraps a type in a manifest before calling inferImplicit on the result
446
+ *
447
+ * TODO: in scala 2 if not full the default is `reflect.ClassManifest`,
448
+ * not `reflect.ClassTag`, which is treated differently.
449
+ */
450
+ def findManifest (tp : Type , manifestClass : Symbol = if full then defn.ManifestClass else NoSymbol ) =
451
+ if manifestClass.exists then
452
+ materializeImplicit(manifestClass.typeRef.appliedTo(tp), span)
453
+ else
454
+ inner(tp, NoSymbol ) // workaround so that a `ClassManifest` will be generated
455
+
456
+ def findSubManifest (tp : Type ) =
457
+ findManifest(tp, if (full) defn.ManifestClass else defn.OptManifestClass )
458
+
459
+ def inferTypeTag (tp : Type ) =
460
+ if defn.TypeTagType .exists then
461
+ typer.inferImplicit(defn.TypeTagType .appliedTo(tp), EmptyTree , span) match
462
+ case SearchSuccess (tagInScope, _, _, _) => Some (tagInScope)
463
+ case _ => None
464
+ else
465
+ None
466
+
467
+ def interopTypeTag (tp : Type , tagInScope : Tree ) =
468
+ materializeImplicit(defn.ClassTagClass .typeRef.appliedTo(tp), span) match
469
+ case EmptyTree =>
470
+ report.error(i """ To create a Manifest here, it is necessary to interoperate with the
471
+ |TypeTag ` $tagInScope` in scope. However TypeTag to Manifest conversion requires a
472
+ |ClassTag for the corresponding type to be present.
473
+ |To proceed add a ClassTag for the type ` $tp` (e.g. by introducing a context bound)
474
+ |and recompile. """ .stripMargin, ctx.source.atSpan(span))
475
+ EmptyTree
476
+ case clsTag =>
477
+ // if TypeTag is available, assume scala.reflect.runtime.universe is also
478
+ val ru = ref(defn.ReflectRuntimePackageObject_universe )
479
+ val optEnclosing = ctx.owner.enclosingClass
480
+ if optEnclosing.exists then
481
+ val enclosing = ref(defn.Predef_classOf ).appliedToType(optEnclosing.typeRef)
482
+ val currentMirror = ru.select(nme.runtimeMirror).appliedTo(enclosing.select(nme.getClassLoader))
483
+ ru.select(nme.internal).select(nme.typeTagToManifest)
484
+ .appliedToType(tp)
485
+ .appliedTo(currentMirror, tagInScope)
486
+ .appliedTo(clsTag)
487
+ .withSpan(span)
488
+ else
489
+ EmptyTree
490
+
491
+ def manifestOfType (tp0 : Type ): Tree =
492
+
493
+ val tp1 = tp0.dealiasKeepAnnots
494
+
495
+ extension [T ](xs : List [T ]) def isSingleton = xs.lengthCompare(1 ) == 0
496
+
497
+ def classManifest (clsRef : Type , args : List [Type ]): Tree =
498
+ val classarg = ref(defn.Predef_classOf ).appliedToType(tp1)
499
+ val suffix0 = classarg :: (args map findSubManifest)
500
+ val pre = clsRef.normalizedPrefix
501
+ val ignorePrefix = (pre eq NoPrefix ) || pre.typeSymbol.isStaticOwner
502
+ val suffix = if ignorePrefix then suffix0 else findSubManifest(pre) :: suffix0
503
+ manifestFactoryCall(nme.classType, tp, suffix* )
504
+
505
+ tp1 match
506
+ case ThisType (_) | TermRef (_,_) => manifestFactoryCall(nme.singleType, tp, singleton(tp1))
507
+ case ConstantType (c) => inner(c.tpe, defn.ManifestClass )
508
+
509
+ case tp1 @ TypeRef (pre, desig) =>
510
+ val tpSym = tp1.typeSymbol
511
+ if tpSym.isPrimitiveValueClass || defn.isPhantomClass(tpSym) then
512
+ findSingletonManifest(tpSym.name.toTermName)
513
+ else if tpSym == defn.ObjectClass || tpSym == defn.AnyRefAlias then
514
+ findSingletonManifest(nme.Object )
515
+ else if tpSym.isClass then
516
+ classManifest(tp1, Nil )
517
+ else
518
+ EmptyTree
519
+
520
+ case tp1 @ AppliedType (tycon, args) =>
521
+ val tpSym = tycon.typeSymbol
522
+ if tpSym == defn.RepeatedParamClass then
523
+ EmptyTree
524
+ else if tpSym == defn.ArrayClass && args.isSingleton then
525
+ manifestFactoryCall(nme.arrayType, args.head, findManifest(args.head))
526
+ else if tpSym.isClass then
527
+ classManifest(tycon, args)
528
+ else
529
+ EmptyTree
530
+
531
+ case TypeBounds (lo, hi) if full =>
532
+ manifestFactoryCall(nme.wildcardType, tp, findManifest(lo), findManifest(hi))
533
+
534
+ case Scala2RefinedType (parents) =>
535
+ if parents.isSingleton then findManifest(parents.head)
536
+ else if full then manifestFactoryCall(nme.intersectionType, tp, (parents map findSubManifest)* )
537
+ else manifestOfType(Scala2Erasure .intersectionDominator(parents))
538
+
539
+ case _ =>
540
+ EmptyTree
541
+ end manifestOfType
542
+
543
+ if full then
544
+ inferTypeTag(tp) match
545
+ case Some (tagInScope) => interopTypeTag(tp, tagInScope)
546
+ case _ => manifestOfType(tp)
547
+ else
548
+ manifestOfType(tp) match
549
+ case EmptyTree if opt => ref(defn.NoManifestModule )
550
+ case result => result
551
+
552
+ end inner
553
+
554
+ formal.argInfos match
555
+ case arg :: Nil =>
556
+ inner(fullyDefinedType(arg, " Manifest argument" , span), flavor)
557
+ case _ =>
558
+ EmptyTree
559
+ end manifestOfFactory
560
+
561
+ val synthesizedManifest : SpecialHandler = manifestOfFactory(defn.ManifestClass )
562
+ val synthesizedOptManifest : SpecialHandler = manifestOfFactory(defn.OptManifestClass )
563
+
378
564
val specialHandlers = List (
379
565
defn.ClassTagClass -> synthesizedClassTag,
380
566
defn.TypeTestClass -> synthesizedTypeTest,
381
567
defn.CanEqualClass -> synthesizedCanEqual,
382
568
defn.ValueOfClass -> synthesizedValueOf,
383
569
defn.Mirror_ProductClass -> synthesizedProductMirror,
384
570
defn.Mirror_SumClass -> synthesizedSumMirror,
385
- defn.MirrorClass -> synthesizedMirror)
571
+ defn.MirrorClass -> synthesizedMirror,
572
+ defn.ManifestClass -> synthesizedManifest,
573
+ defn.OptManifestClass -> synthesizedOptManifest,
574
+ )
386
575
387
576
def tryAll (formal : Type , span : Span )(using Context ): Tree =
388
577
def recur (handlers : SpecialHandlers ): Tree = handlers match
0 commit comments