@@ -375,14 +375,123 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
375375 synthesizedSumMirror(formal, span)
376376 case _ => EmptyTree
377377
378+ private def escapeJavaArray (elemTp : Type )(using Context ): Type = elemTp match
379+ case JavaArrayType (elemTp1) => defn.ArrayOf (escapeJavaArray(elemTp1))
380+ case _ => elemTp
381+
382+ private enum ManifestKind :
383+ case Full , Opt , Clss
384+
385+ /** The kind that should be used for an array element, if we are `OptManifest` then this
386+ * prevents wildcards arguments of Arrays being converted to `NoManifest`
387+ */
388+ def arrayElem = if this == Full then this else Clss
389+
390+ end ManifestKind
391+
392+ /** Manifest factory that does enough to satisfy the equality semantics for
393+ * - `scala.reflect.OptManifest` (only runtime class is recorded)
394+ * - `scala.reflect.Manifest` (runtime class of arguments are recorded, with wildcard upper bounds wrapped)
395+ * however,`toString` may be different.
396+ *
397+ * There are some differences to `ClassTag`,
398+ * e.g. in Scala 2 `manifest[Int @unchecked]` will fail, but `classTag[Int @unchecked]` succeeds.
399+ */
400+ private def manifestFactoryOf (kind : ManifestKind ): SpecialHandler = (formal, span) =>
401+ import ManifestKind .*
402+
403+ /* Creates a tree that calls the factory method called constructor in object scala.reflect.Manifest */
404+ def factoryManifest (constructor : TermName , tparg : Type , args : Tree * ): Tree =
405+ if args.contains(EmptyTree ) then
406+ EmptyTree
407+ else
408+ val factory = if kind == Full then defn.ManifestFactoryModule else defn.ClassManifestFactoryModule
409+ applyOverloaded(ref(factory), constructor, args.toList, tparg :: Nil , Types .WildcardType ).withSpan(span)
410+
411+ /* Creates a tree representing one of the singleton manifests.*/
412+ def singletonManifest (name : TermName ) =
413+ ref(defn.ManifestFactoryModule ).select(name).ensureApplied.withSpan(span)
414+
415+ def synthArrayManifest (elemTp : Type , kind : ManifestKind , topLevel : Boolean ): Tree =
416+ factoryManifest(nme.arrayType, elemTp, synthesize(elemTp, kind.arrayElem, topLevel))
417+
418+ /** manifests generated from wildcards can not equal Int,Long,Any,AnyRef,AnyVal etc,
419+ * so we wrap their upper bound.
420+ */
421+ def synthWildcardManifest (tp : Manifestable , hi : Type , topLevel : Boolean ): Tree =
422+ factoryManifest(nme.wildcardType, tp, singletonManifest(nme.Nothing ), synthesize(hi, Full , topLevel))
423+
424+ /** `Nil` if not full manifest */
425+ def synthArgManifests (tp : Manifestable ): List [Tree ] = tp match
426+ case AppliedType (_, args) if kind == Full && tp.typeSymbol.isClass =>
427+ args.map(synthesize(_, Full , topLevel = false ))
428+ case _ =>
429+ Nil
430+
431+ /** This type contains all top-level types supported by Scala 2's algorithm */
432+ type Manifestable =
433+ ThisType | TermRef | ConstantType | TypeRef | AppliedType | TypeBounds | RecType | RefinedType | AndType
434+
435+ def canManifest (tp : Manifestable , topLevel : Boolean ) =
436+ val sym = tp.typeSymbol
437+ ! sym.isAbstractType
438+ && hasStableErasure(tp)
439+ && ! (topLevel && defn.isBottomClassAfterErasure(sym))
440+
441+ /** adapted from `syntheticClassTag` */
442+ def synthManifest (tp : Manifestable , kind : ManifestKind , topLevel : Boolean ) = tp match
443+ case defn.ArrayOf (elemTp) => synthArrayManifest(elemTp, kind, topLevel)
444+ case TypeBounds (_, hi) if kind == Full => synthWildcardManifest(tp, hi, topLevel)
445+
446+ case tp if canManifest(tp, topLevel) =>
447+ val sym = tp.typeSymbol
448+ if sym.isPrimitiveValueClass || defn.SpecialManifestClasses .contains(sym) then
449+ singletonManifest(sym.name.toTermName)
450+ else
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 ): 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, topLevel = true )
476+ case _ =>
477+ EmptyTree
478+
479+ end manifestFactoryOf
480+
481+ val synthesizedManifest : SpecialHandler = manifestFactoryOf(ManifestKind .Full )
482+ val synthesizedOptManifest : SpecialHandler = manifestFactoryOf(ManifestKind .Opt )
483+
378484 val specialHandlers = List (
379485 defn.ClassTagClass -> synthesizedClassTag,
380486 defn.TypeTestClass -> synthesizedTypeTest,
381487 defn.CanEqualClass -> synthesizedCanEqual,
382488 defn.ValueOfClass -> synthesizedValueOf,
383489 defn.Mirror_ProductClass -> synthesizedProductMirror,
384490 defn.Mirror_SumClass -> synthesizedSumMirror,
385- defn.MirrorClass -> synthesizedMirror)
491+ defn.MirrorClass -> synthesizedMirror,
492+ defn.ManifestClass -> synthesizedManifest,
493+ defn.OptManifestClass -> synthesizedOptManifest,
494+ )
386495
387496 def tryAll (formal : Type , span : Span )(using Context ): Tree =
388497 def recur (handlers : SpecialHandlers ): Tree = handlers match
0 commit comments