Skip to content

Commit b26f555

Browse files
committed
Mirrors can now be materialized with additional type member refinements.
Any additional type members will contribute to the implicit scope of any searches involving the type of the summoned Mirror. Typically such types will be the singleton types of objects containing implicit extension methods for the Mirror, or other related implicit definitions. Pass through all extra refinements
1 parent 516f35e commit b26f555

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -884,14 +884,38 @@ trait Implicits { self: Typer =>
884884
*
885885
* <parent> {
886886
* MirroredMonoType = <monoType>
887-
* MirroredTypeConstrictor = <tycon>
888-
* MirroredLabel = <label> }
887+
* MirroredType = <mirroredType>
888+
* MirroredLabel = <label>
889+
* Scope = <scope> // if scope ne NoType
890+
* }
889891
*/
890-
private def mirrorCore(parentClass: ClassSymbol, monoType: Type, mirroredType: Type, label: Name)(implicit ctx: Context) = {
891-
parentClass.typeRef
892+
private def mirrorCore(parentClass: ClassSymbol, monoType: Type, mirroredType: Type, label: Name, extras: List[(Name, Type)])(implicit ctx: Context) = {
893+
val m = parentClass.typeRef
892894
.refinedWith(tpnme.MirroredMonoType, TypeAlias(monoType))
893895
.refinedWith(tpnme.MirroredType, TypeAlias(mirroredType))
894896
.refinedWith(tpnme.MirroredLabel, TypeAlias(ConstantType(Constant(label.toString))))
897+
898+
extras.foldLeft(m) { case (m, (tpnme, tpe)) => m.refinedWith(tpnme, tpe) }
899+
}
900+
901+
private def extraRefinements(formal: Type)(implicit ctx: Context): List[(Name, Type)] = {
902+
def isMirrorMember(nme: Name): Boolean =
903+
nme == tpnme.MirroredType ||
904+
nme == tpnme.MirroredMonoType ||
905+
nme == tpnme.MirroredLabel ||
906+
nme == tpnme.MirroredElemTypes ||
907+
nme == tpnme.MirroredElemLabels
908+
909+
@tailrec
910+
def loop(tp: Type, acc: List[(Name, Type)]): List[(Name, Type)] = tp match {
911+
case RefinedType(parent, nme, rhs) if !isMirrorMember(nme) =>
912+
loop(parent, (nme, rhs) :: acc)
913+
case RefinedType(parent, nme, rhs) =>
914+
loop(parent, acc)
915+
case other =>
916+
acc
917+
}
918+
loop(formal, Nil)
895919
}
896920

897921
/** A path referencing the companion of class type `clsType` */
@@ -916,12 +940,12 @@ trait Implicits { self: Typer =>
916940
val module = mirroredType.termSymbol
917941
val modulePath = pathFor(mirroredType).withSpan(span)
918942
if (module.info.classSymbol.is(Scala2x)) {
919-
val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, module.name)
943+
val mirrorType = mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, module.name, extraRefinements(formal))
920944
val mirrorRef = New(defn.Mirror_SingletonProxyClass.typeRef, modulePath :: Nil)
921945
mirrorRef.cast(mirrorType)
922946
}
923947
else {
924-
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name)
948+
val mirrorType = mirrorCore(defn.Mirror_SingletonClass, mirroredType, mirroredType, module.name, extraRefinements(formal))
925949
modulePath.cast(mirrorType)
926950
}
927951
}
@@ -943,7 +967,7 @@ trait Implicits { self: Typer =>
943967
(mirroredType, elems)
944968
}
945969
val mirrorType =
946-
mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name)
970+
mirrorCore(defn.Mirror_ProductClass, monoType, mirroredType, cls.name, extraRefinements(formal))
947971
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
948972
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
949973
val mirrorRef =
@@ -1024,7 +1048,7 @@ trait Implicits { self: Typer =>
10241048
}
10251049

10261050
val mirrorType =
1027-
mirrorCore(defn.Mirror_SumClass, monoType, mirroredType, cls.name)
1051+
mirrorCore(defn.Mirror_SumClass, monoType, mirroredType, cls.name, extraRefinements(formal))
10281052
.refinedWith(tpnme.MirroredElemTypes, TypeAlias(elemsType))
10291053
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
10301054
val mirrorRef =

tests/pos/mirror-implicit-scope.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.deriving._
2+
3+
object Test {
4+
object K0 {
5+
type Generic[T] = Mirror { type Scope = K0.type ; type MirroredType = T ; type MirroredElemTypes }
6+
given Ops {
7+
inline def (gen: Generic[T]) toRepr[T <: Product](t: T): gen.MirroredElemTypes = Tuple.fromProduct(t).asInstanceOf
8+
}
9+
}
10+
11+
object K1 {
12+
type Generic[F[_]] = Mirror { type Scope = K1.type ; type MirroredType = F ; type MirroredElemTypes[_] }
13+
given Ops {
14+
inline def (gen: Generic[F]) toRepr[F[_] <: Product, T](t: F[T]): gen.MirroredElemTypes[T] = Tuple.fromProduct(t).asInstanceOf
15+
}
16+
}
17+
18+
case class ISB(i: Int, s: String, b: Boolean)
19+
val v0 = the[K0.Generic[ISB]]
20+
val v1 = v0.toRepr(ISB(23, "foo", true))
21+
val v2: (Int, String, Boolean) = v1
22+
23+
case class Box[T](t: T)
24+
val v3 = the[K1.Generic[Box]]
25+
val v4 = v3.toRepr(Box(23))
26+
val v5: Tuple1[Int] = v4
27+
}

0 commit comments

Comments
 (0)