Skip to content

Commit

Permalink
Use MirrorSource.reduce result for companionPath (#20207)
Browse files Browse the repository at this point in the history
Fixes #20187
  • Loading branch information
bishabosha authored Apr 17, 2024
2 parents 63810dc + ef03fc0 commit 2176fe4
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 42 deletions.
20 changes: 0 additions & 20 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -471,26 +471,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case ConstantType(value) => Literal(value)
}

/** A path that corresponds to the given type `tp`. Error if `tp` is not a refinement
* of an addressable singleton type.
*/
def pathFor(tp: Type)(using Context): Tree = {
def recur(tp: Type): Tree = tp match {
case tp: NamedType =>
tp.info match {
case TypeAlias(alias) => recur(alias)
case _: TypeBounds => EmptyTree
case _ => singleton(tp)
}
case tp: TypeProxy => recur(tp.superType)
case _ => EmptyTree
}
recur(tp).orElse {
report.error(em"$tp is not an addressable singleton type")
TypeTree(tp)
}
}

/** A tree representing a `newXYZArray` operation of the right
* kind for the given element type in `elemTpe`. No type arguments or
* `length` arguments are given.
Expand Down
15 changes: 0 additions & 15 deletions compiler/src/dotty/tools/dotc/core/TypeUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,21 +116,6 @@ class TypeUtils {

def refinedWith(name: Name, info: Type)(using Context) = RefinedType(self, name, info)

/** The TermRef referring to the companion of the underlying class reference
* of this type, while keeping the same prefix.
*/
def mirrorCompanionRef(using Context): TermRef = self match {
case AndType(tp1, tp2) =>
val c1 = tp1.classSymbol
val c2 = tp2.classSymbol
if c1.isSubClass(c2) then tp1.mirrorCompanionRef
else tp2.mirrorCompanionRef // precondition: the parts of the AndType have already been checked to be non-overlapping
case self @ TypeRef(prefix, _) if self.symbol.isClass =>
prefix.select(self.symbol.companionModule).asInstanceOf[TermRef]
case self: TypeProxy =>
self.superType.mirrorCompanionRef
}

/** Is this type a methodic type that takes at least one parameter? */
def takesParams(using Context): Boolean = self.stripPoly match
case mt: MethodType => mt.paramNames.nonEmpty || mt.resType.takesParams
Expand Down
15 changes: 8 additions & 7 deletions compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import transform.SyntheticMembers.*
import util.Property
import ast.Trees.genericEmptyTree
import annotation.{tailrec, constructorOnly}
import ast.tpd
import ast.tpd.*
import Synthesizer.*
import sbt.ExtractDependencies.*
Expand Down Expand Up @@ -265,10 +266,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
.refinedWith(tpnme.MirroredType, TypeAlias(mirroredType))
.refinedWith(tpnme.MirroredLabel, TypeAlias(ConstantType(Constant(label.toString))))

/** A path referencing the companion of class type `clsType` */
private def companionPath(clsType: Type, span: Span)(using Context) =
val ref = pathFor(clsType.mirrorCompanionRef)
assert(ref.symbol.is(Module) && (clsType.classSymbol.is(ModuleClass) || (ref.symbol.companionClass == clsType.classSymbol)))
/** A path referencing the companion of `cls` with prefix `pre` */
private def companionPath(pre: Type, cls: Symbol, span: Span)(using Context) =
val ref = tpd.ref(TermRef(pre, cls.companionModule))
assert(ref.symbol.is(Module) && (cls.is(ModuleClass) || ref.symbol.companionClass == cls))
ref.withSpan(span)

private def checkFormal(formal: Type)(using Context): Boolean =
Expand Down Expand Up @@ -428,7 +429,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(elemsLabels))
}
val mirrorRef =
if cls.useCompanionAsProductMirror then companionPath(mirroredType, span)
if cls.useCompanionAsProductMirror then companionPath(pre, cls, span)
else if defn.isTupleClass(cls) then newTupleMirror(typeElems.size) // TODO: cls == defn.PairClass when > 22
else anonymousMirror(monoType, MirrorImpl.OfProduct(pre), span)
withNoErrors(mirrorRef.cast(mirrorType).withSpan(span))
Expand All @@ -438,7 +439,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
case Right(msrc) => msrc match
case MirrorSource.Singleton(_, tref) =>
val singleton = tref.termSymbol // prefer alias name over the orignal name
val singletonPath = pathFor(tref).withSpan(span)
val singletonPath = tpd.singleton(tref).withSpan(span)
if tref.classSymbol.is(Scala2x) then // could be Scala 3 alias of Scala 2 case object.
val mirrorType = formal.constrained_& {
mirrorCore(defn.Mirror_SingletonProxyClass, mirroredType, mirroredType, singleton.name)
Expand Down Expand Up @@ -571,7 +572,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
.refinedWith(tpnme.MirroredElemLabels, TypeAlias(labels))
}
val mirrorRef =
if cls.useCompanionAsSumMirror then companionPath(mirroredType, span)
if cls.useCompanionAsSumMirror then companionPath(pre, cls, span)
else anonymousMirror(monoType, MirrorImpl.OfSum(childPres), span)
withNoErrors(mirrorRef.cast(mirrorType))
else if acceptableMsg.nonEmpty then
Expand Down
19 changes: 19 additions & 0 deletions tests/pos/i20187/A_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import scala.deriving.Mirror

enum E:
case Foo1()
case Foo2()

class Outer:
case class Inner()
val o = new Outer

type F = E.Foo1
type G = Tuple.Head[E.Foo1 *: E.Foo2 *: EmptyTuple]
type H = Tuple.Head[o.Inner *: EmptyTuple]
type I = Tuple.Last[E *: EmptyTuple]

def local =
case class Bar()
type B = Tuple.Head[Bar *: EmptyTuple]
summon[Mirror.Of[B]]
7 changes: 7 additions & 0 deletions tests/pos/i20187/B_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.deriving.Mirror

def Test =
summon[Mirror.Of[F]] // ok
summon[Mirror.Of[G]] // was crash
summon[Mirror.Of[H]] // was crash
summon[Mirror.Of[I]] // was crash

0 comments on commit 2176fe4

Please sign in to comment.