Skip to content

Commit 467b360

Browse files
committed
Reorganise (& rename) 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.
1 parent b1cc33a commit 467b360

File tree

1 file changed

+76
-57
lines changed

1 file changed

+76
-57
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Typer.scala

+76-57
Original file line numberDiff line numberDiff line change
@@ -683,85 +683,104 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
683683
then
684684
report.error(StableIdentPattern(tree, pt), tree.srcPos)
685685

686-
def typedSelect(tree0: untpd.Select, pt: Type, qual: Tree)(using Context): Tree =
686+
def typedSelectWithAdapt(tree0: untpd.Select, pt: Type, qual: Tree)(using Context): Tree =
687687
val selName = tree0.name
688688
val tree = cpy.Select(tree0)(qual, selName)
689689
val superAccess = qual.isInstanceOf[Super]
690690
val rawType = selectionType(tree, qual)
691-
val checkedType = accessibleType(rawType, superAccess)
692-
693-
def finish(tree: untpd.Select, qual: Tree, checkedType: Type): Tree =
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-
699-
if checkedType.exists then
700-
finish(tree, qual, checkedType)
701-
else if selName == nme.apply && qual.tpe.widen.isInstanceOf[MethodType] then
702-
// Simplify `m.apply(...)` to `m(...)`
703-
qual
704-
else if couldInstantiateTypeVar(qual.tpe.widen) then
705-
// there's a simply visible type variable in the result; try again with a more defined qualifier type
706-
// There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
707-
// but that is done only after we search for extension methods or conversions.
708-
typedSelect(tree, pt, qual)
709-
else if qual.tpe.isSmallGenericTuple then
710-
val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil)
711-
typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
712-
else
713-
val tree1 = tryExtensionOrConversion(
714-
tree, pt, IgnoredProto(pt), qual, ctx.typerState.ownedVars, this, inSelect = true)
715-
.orElse {
716-
if ctx.gadt.isNarrowing then
717-
// try GADT approximation if we're trying to select a member
718-
// Member lookup cannot take GADTs into account b/c of cache, so we
719-
// approximate types based on GADT constraints instead. For an example,
720-
// see MemberHealing in gadt-approximation-interaction.scala.
721-
val wtp = qual.tpe.widen
722-
gadts.println(i"Trying to heal member selection by GADT-approximating $wtp")
723-
val gadtApprox = Inferencing.approximateGADT(wtp)
724-
gadts.println(i"GADT-approximated $wtp ~~ $gadtApprox")
725-
val qual1 = qual.cast(gadtApprox)
726-
val tree1 = cpy.Select(tree0)(qual1, selName)
727-
val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false)
728-
if checkedType1.exists then
729-
gadts.println(i"Member selection healed by GADT approximation")
730-
finish(tree1, qual1, checkedType1)
731-
else if qual1.tpe.isSmallGenericTuple then
732-
gadts.println(i"Tuple member selection healed by GADT approximation")
733-
typedSelect(tree, pt, qual1)
734-
else
735-
tryExtensionOrConversion(tree1, pt, IgnoredProto(pt), qual1, ctx.typerState.ownedVars, this, inSelect = true)
736-
else EmptyTree
737-
}
738-
if !tree1.isEmpty then
739-
tree1
740-
else if canDefineFurther(qual.tpe.widen) then
741-
typedSelect(tree, pt, qual)
742-
else if qual.tpe.derivesFrom(defn.DynamicClass)
691+
692+
def tryType(tree: untpd.Select, qual: Tree, rawType: Type) =
693+
val checkedType = accessibleType(rawType, superAccess)
694+
if checkedType.exists then
695+
val select = toNotNullTermRef(assignType(tree, checkedType), pt)
696+
if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, "type prefix")
697+
checkLegalValue(select, pt)
698+
ConstFold(select)
699+
else EmptyTree
700+
701+
def trySimplifyApply() =
702+
if selName == nme.apply && qual.tpe.widen.isInstanceOf[MethodType] then
703+
// Simplify `m.apply(...)` to `m(...)`
704+
qual
705+
else EmptyTree
706+
707+
def tryInstantiateTypeVar() =
708+
if couldInstantiateTypeVar(qual.tpe.widen) then
709+
// there's a simply visible type variable in the result; try again with a more defined qualifier type
710+
// There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
711+
// but that is done only after we search for extension methods or conversions.
712+
typedSelectWithAdapt(tree, pt, qual)
713+
else EmptyTree
714+
715+
def trySmallGenericTuple(tree: untpd.Select, qual: Tree, withCast: Boolean) =
716+
if qual.tpe.isSmallGenericTuple then
717+
if withCast then
718+
val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil)
719+
typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
720+
else
721+
typedSelectWithAdapt(tree, pt, qual)
722+
else EmptyTree
723+
724+
def tryExt(tree: untpd.Select, qual: Tree) =
725+
tryExtensionOrConversion(
726+
tree, pt, IgnoredProto(pt), qual, ctx.typerState.ownedVars, this, inSelect = true)
727+
728+
def tryGadt(tree: untpd.Select) =
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(tree, 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 tryDynamic() =
751+
if qual.tpe.derivesFrom(defn.DynamicClass)
743752
&& selName.isTermName && !isDynamicExpansion(tree)
744753
then
745754
val tree2 = cpy.Select(tree0)(untpd.TypedSplice(qual), selName)
746755
if pt.isInstanceOf[FunOrPolyProto] || pt == LhsProto then
747756
assignType(tree2, TryDynamicCallType)
748757
else
749758
typedDynamicSelect(tree2, Nil, pt)
750-
else
759+
else EmptyTree
760+
761+
tryType(tree, qual, rawType)
762+
.orElse(trySimplifyApply())
763+
.orElse(tryInstantiateTypeVar())
764+
.orElse(trySmallGenericTuple(tree, qual, withCast = true))
765+
.orElse(tryExt(tree, qual))
766+
.orElse(tryGadt(tree))
767+
.orElse(tryDefineFurther())
768+
.orElse(tryDynamic())
769+
.orElse:
751770
assignType(tree,
752771
rawType match
753772
case rawType: NamedType =>
754773
inaccessibleErrorType(rawType, superAccess, tree.srcPos)
755774
case _ =>
756775
notAMemberErrorType(tree, qual, pt))
757-
end typedSelect
776+
end typedSelectWithAdapt
758777

759778
def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = {
760779
record("typedSelect")
761780

762781
def typeSelectOnTerm(using Context): Tree =
763782
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this, tree.nameSpan))
764-
typedSelect(tree, pt, qual).withSpan(tree.span).computeNullable()
783+
typedSelectWithAdapt(tree, pt, qual).withSpan(tree.span).computeNullable()
765784

766785
def javaSelectOnType(qual: Tree)(using Context) =
767786
// semantic name conversion for `O$` in java code
@@ -3619,7 +3638,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
36193638
if isExtension then return found
36203639
else
36213640
checkImplicitConversionUseOK(found, selProto)
3622-
return withoutMode(Mode.ImplicitsEnabled)(typedSelect(tree, pt, found))
3641+
return withoutMode(Mode.ImplicitsEnabled)(typedSelectWithAdapt(tree, pt, found))
36233642
case failure: SearchFailure =>
36243643
if failure.isAmbiguous then
36253644
return

0 commit comments

Comments
 (0)