Skip to content

Commit 3dc65c6

Browse files
committed
Reorganise typedSelectWithAdapt
Prior to the next commit, I broke up the logic into internal methods, so some can be reused, consuming then in a big Tree#orElse chain. I also took the opportunity to rename the method, to more easily distinguish it from the other typedSelect. [Cherry-picked c477cea][modified]
1 parent e2b18ff commit 3dc65c6

File tree

1 file changed

+84
-60
lines changed

1 file changed

+84
-60
lines changed

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

Lines changed: 84 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -686,72 +686,96 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
686686
val tree = cpy.Select(tree0)(qual, selName)
687687
val superAccess = qual.isInstanceOf[Super]
688688
val rawType = selectionType(tree, qual)
689-
val checkedType = accessibleType(rawType, superAccess)
690-
691-
def finish(tree: untpd.Select, qual: Tree, checkedType: Type): Tree =
692-
val select = toNotNullTermRef(assignType(tree, checkedType), pt)
693-
if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, "type prefix")
694-
checkLegalValue(select, pt)
695-
ConstFold(select)
696-
697-
if checkedType.exists then
698-
finish(tree, qual, checkedType)
699-
else if selName == nme.apply && qual.tpe.widen.isInstanceOf[MethodType] then
700-
// Simplify `m.apply(...)` to `m(...)`
701-
qual
702-
else if couldInstantiateTypeVar(qual.tpe.widen) then
703-
// there's a simply visible type variable in the result; try again with a more defined qualifier type
704-
// There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
705-
// but that is done only after we search for extension methods or conversions.
706-
typedSelectWithAdapt(tree, pt, qual)
707-
else if qual.tpe.isSmallGenericTuple then
708-
val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil)
709-
typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
710-
else
711-
val tree1 = tryExtensionOrConversion(
712-
tree, pt, IgnoredProto(pt), qual, ctx.typerState.ownedVars, this, inSelect = true)
713-
.orElse {
714-
if ctx.gadt.isNarrowing then
715-
// try GADT approximation if we're trying to select a member
716-
// Member lookup cannot take GADTs into account b/c of cache, so we
717-
// approximate types based on GADT constraints instead. For an example,
718-
// see MemberHealing in gadt-approximation-interaction.scala.
719-
val wtp = qual.tpe.widen
720-
gadts.println(i"Trying to heal member selection by GADT-approximating $wtp")
721-
val gadtApprox = Inferencing.approximateGADT(wtp)
722-
gadts.println(i"GADT-approximated $wtp ~~ $gadtApprox")
723-
val qual1 = qual.cast(gadtApprox)
724-
val tree1 = cpy.Select(tree0)(qual1, selName)
725-
val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false)
726-
if checkedType1.exists then
727-
gadts.println(i"Member selection healed by GADT approximation")
728-
finish(tree1, qual1, checkedType1)
729-
else if qual1.tpe.isSmallGenericTuple then
730-
gadts.println(i"Tuple member selection healed by GADT approximation")
731-
typedSelectWithAdapt(tree, pt, qual1)
732-
else
733-
tryExtensionOrConversion(tree1, pt, IgnoredProto(pt), qual1, ctx.typerState.ownedVars, this, inSelect = true)
734-
else EmptyTree
735-
}
736-
if !tree1.isEmpty then
737-
tree1
738-
else if canDefineFurther(qual.tpe.widen) then
689+
690+
def tryType(tree: untpd.Select, qual: Tree, rawType: Type) =
691+
val checkedType = accessibleType(rawType, superAccess)
692+
// If regular selection is typeable, we are done
693+
if checkedType.exists then
694+
val select = toNotNullTermRef(assignType(tree, checkedType), pt)
695+
if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, "type prefix")
696+
checkLegalValue(select, pt)
697+
ConstFold(select)
698+
else EmptyTree
699+
700+
def trySimplifyApply() =
701+
if selName == nme.apply && qual.tpe.widen.isInstanceOf[MethodType] then
702+
// Simplify `m.apply(...)` to `m(...)`
703+
qual
704+
else EmptyTree
705+
706+
def tryInstantiateTypeVar() =
707+
if couldInstantiateTypeVar(qual.tpe.widen) then
708+
// there's a simply visible type variable in the result; try again with a more defined qualifier type
709+
// There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
710+
// but that is done only after we search for extension methods or conversions.
739711
typedSelectWithAdapt(tree, pt, qual)
740-
else if qual.tpe.derivesFrom(defn.DynamicClass)
741-
&& selName.isTermName && !isDynamicExpansion(tree)
742-
then
712+
else EmptyTree
713+
714+
def trySmallGenericTuple(qual: Tree, withCast: Boolean) =
715+
if qual.tpe.isSmallGenericTuple then
716+
if withCast then
717+
val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil)
718+
typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
719+
else
720+
typedSelectWithAdapt(tree, pt, qual)
721+
else EmptyTree
722+
723+
def tryExt(tree: untpd.Select, qual: Tree) =
724+
tryExtensionOrConversion(
725+
tree, pt, IgnoredProto(pt), qual, ctx.typerState.ownedVars, this, inSelect = true
726+
)
727+
728+
def tryGadt() =
729+
if ctx.gadt.isNarrowing then
730+
// try GADT approximation if we're trying to select a member
731+
// Member lookup cannot take GADTs into account b/c of cache, so we
732+
// approximate types based on GADT constraints instead. For an example,
733+
// see MemberHealing in gadt-approximation-interaction.scala.
734+
val wtp = qual.tpe.widen
735+
gadts.println(i"Trying to heal member selection by GADT-approximating $wtp")
736+
val gadtApprox = Inferencing.approximateGADT(wtp)
737+
gadts.println(i"GADT-approximated $wtp ~~ $gadtApprox")
738+
val qual1 = qual.cast(gadtApprox)
739+
val tree1 = cpy.Select(tree0)(qual1, selName)
740+
tryType(tree1, qual1, selectionType(tree1, qual1))
741+
.orElse(trySmallGenericTuple(qual1, withCast = false))
742+
.orElse(tryExt(tree1, qual1))
743+
else EmptyTree
744+
745+
def tryDefineFurther() =
746+
if canDefineFurther(qual.tpe.widen) then
747+
typedSelectWithAdapt(tree, pt, qual)
748+
else EmptyTree
749+
750+
def dynamicSelect(pt: Type) =
743751
val tree2 = cpy.Select(tree0)(untpd.TypedSplice(qual), selName)
744752
if pt.isInstanceOf[FunOrPolyProto] || pt == AssignProto then
745753
assignType(tree2, TryDynamicCallType)
746754
else
747755
typedDynamicSelect(tree2, Nil, pt)
748-
else
749-
assignType(tree,
750-
rawType match
751-
case rawType: NamedType =>
752-
inaccessibleErrorType(rawType, superAccess, tree.srcPos)
753-
case _ =>
754-
notAMemberErrorType(tree, qual, pt))
756+
757+
def tryDynamic() =
758+
if qual.tpe.derivesFrom(defn.DynamicClass) && selName.isTermName && !isDynamicExpansion(tree) then
759+
dynamicSelect(pt)
760+
else EmptyTree
761+
762+
def reportAnError() =
763+
assignType(tree,
764+
rawType match
765+
case rawType: NamedType =>
766+
inaccessibleErrorType(rawType, superAccess, tree.srcPos)
767+
case _ =>
768+
notAMemberErrorType(tree, qual, pt))
769+
770+
tryType(tree, qual, rawType)
771+
.orElse(trySimplifyApply())
772+
.orElse(tryInstantiateTypeVar())
773+
.orElse(trySmallGenericTuple(qual, withCast = true))
774+
.orElse(tryExt(tree, qual))
775+
.orElse(tryGadt())
776+
.orElse(tryDefineFurther())
777+
.orElse(tryDynamic())
778+
.orElse(reportAnError())
755779
end typedSelectWithAdapt
756780

757781
def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = {

0 commit comments

Comments
 (0)