@@ -724,137 +724,158 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
724724 then
725725 report.error(StableIdentPattern (tree, pt), tree.srcPos)
726726
727- def typedSelect (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
727+ def typedSelectWithAdapt (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
728728 val selName = tree0.name
729729 val tree = cpy.Select (tree0)(qual, selName)
730730 val superAccess = qual.isInstanceOf [Super ]
731731 val rawType = selectionType(tree, qual)
732- val checkedType = accessibleType(rawType, superAccess)
733732
734- def finish (tree : untpd.Select , qual : Tree , checkedType : Type ): Tree =
735- val select = toNotNullTermRef(assignType(tree, checkedType), pt )
736- if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, " type prefix " )
737- checkLegalValue(select, pt)
738- ConstFold ( select)
739-
740- // If regular selection is typeable, we are done
741- if checkedType.exists then
742- return finish(tree, qual, checkedType)
733+ def tryType (tree : untpd.Select , qual : Tree , rawType : Type ) =
734+ val checkedType = accessibleType(rawType, superAccess )
735+ // If regular selection is typeable, we are done
736+ if checkedType.exists then
737+ val select = toNotNullTermRef(assignType(tree, checkedType), pt )
738+ if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, " type prefix " )
739+ checkLegalValue(select, pt)
740+ ConstFold (select)
741+ else EmptyTree
743742
744743 // Otherwise, simplify `m.apply(...)` to `m(...)`
745- if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
746- return qual
744+ def trySimplifyApply () =
745+ if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
746+ qual
747+ else EmptyTree
747748
748749 // Otherwise, if there's a simply visible type variable in the result, try again
749750 // with a more defined qualifier type. There's a second trial where we try to instantiate
750751 // all type variables in `qual.tpe.widen`, but that is done only after we search for
751752 // extension methods or conversions.
752- if couldInstantiateTypeVar(qual.tpe.widen) then
753- // there's a simply visible type variable in the result; try again with a more defined qualifier type
754- // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
755- // but that is done only after we search for extension methods or conversions.
756- return typedSelect(tree, pt, qual)
753+ def tryInstantiateTypeVar () =
754+ if couldInstantiateTypeVar(qual.tpe.widen) then
755+ // there's a simply visible type variable in the result; try again with a more defined qualifier type
756+ // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
757+ // but that is done only after we search for extension methods or conversions.
758+ typedSelectWithAdapt(tree, pt, qual)
759+ else EmptyTree
757760
758761 // Otherwise, try to expand a named tuple selection
759- val namedTupleElems = qual.tpe.widenDealias.namedTupleElementTypes
760- val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
761- if nameIdx >= 0 && Feature .enabled(Feature .namedTuples) then
762- return typed(
763- untpd.Apply (
764- untpd.Select (untpd.TypedSplice (qual), nme.apply),
765- untpd.Literal (Constant (nameIdx))),
766- pt)
762+ def tryNamedTupleSelection () =
763+ val namedTupleElems = qual.tpe.widenDealias.namedTupleElementTypes
764+ val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
765+ if nameIdx >= 0 && Feature .enabled(Feature .namedTuples) then
766+ typed(
767+ untpd.Apply (
768+ untpd.Select (untpd.TypedSplice (qual), nme.apply),
769+ untpd.Literal (Constant (nameIdx))),
770+ pt)
771+ else EmptyTree
767772
768773 // Otherwise, map combinations of A *: B *: .... EmptyTuple with nesting levels <= 22
769774 // to the Tuple class of the right arity and select from that one
770- if qual.tpe.isSmallGenericTuple then
771- val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
772- return typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
775+ def trySmallGenericTuple (qual : Tree , withCast : Boolean ) =
776+ if qual.tpe.isSmallGenericTuple then
777+ if withCast then
778+ val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
779+ typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
780+ else
781+ typedSelectWithAdapt(tree, pt, qual)
782+ else EmptyTree
773783
774784 // Otherwise try an extension or conversion
775- if selName.isTermName then
776- val tree1 = tryExtensionOrConversion(
785+ def tryExt ( tree : untpd. Select , qual : Tree ) =
786+ tryExtensionOrConversion(
777787 tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
778- if ! tree1.isEmpty then
779- return tree1
780788
781789 // Otherwise, try a GADT approximation if we're trying to select a member
782- // Member lookup cannot take GADTs into account b/c of cache, so we
783- // approximate types based on GADT constraints instead. For an example,
784- // see MemberHealing in gadt-approximation-interaction.scala.
785- if ctx.gadt.isNarrowing then
786- val wtp = qual.tpe.widen
787- gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
788- val gadtApprox = Inferencing .approximateGADT(wtp)
789- gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
790- val qual1 = qual.cast(gadtApprox)
791- val tree1 = cpy.Select (tree0)(qual1, selName)
792- val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false )
793- if checkedType1.exists then
794- gadts.println(i " Member selection healed by GADT approximation " )
795- return finish(tree1, qual1, checkedType1)
796-
797- if qual1.tpe.isSmallGenericTuple then
798- gadts.println(i " Tuple member selection healed by GADT approximation " )
799- return typedSelect(tree, pt, qual1)
800-
801- val tree2 = tryExtensionOrConversion(tree1, pt, IgnoredProto (pt), qual1, ctx.typerState.ownedVars, this , inSelect = true )
802- if ! tree2.isEmpty then
803- return tree2
790+ def tryGadt (tree : untpd.Select ) =
791+ if ctx.gadt.isNarrowing then
792+ // Member lookup cannot take GADTs into account b/c of cache, so we
793+ // approximate types based on GADT constraints instead. For an example,
794+ // see MemberHealing in gadt-approximation-interaction.scala.
795+ val wtp = qual.tpe.widen
796+ gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
797+ val gadtApprox = Inferencing .approximateGADT(wtp)
798+ gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
799+ val qual1 = qual.cast(gadtApprox)
800+ val tree1 = cpy.Select (tree0)(qual1, selName)
801+ tryType(tree1, qual1, selectionType(tree1, qual1))
802+ .orElse(trySmallGenericTuple(qual1, withCast = false ))
803+ .orElse(tryExt(tree1, qual1))
804+ else EmptyTree
804805
805806 // Otherwise, if there are uninstantiated type variables in the qualifier type,
806807 // instantiate them and try again
807- if canDefineFurther(qual.tpe.widen) then
808- return typedSelect(tree, pt, qual)
808+ def tryDefineFurther () =
809+ if canDefineFurther(qual.tpe.widen) then
810+ typedSelectWithAdapt(tree, pt, qual)
811+ else EmptyTree
809812
810813 def dynamicSelect (pt : Type ) =
811- val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
812- if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
813- assignType(tree2, TryDynamicCallType )
814- else
815- typedDynamicSelect(tree2, Nil , pt)
814+ val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
815+ if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
816+ assignType(tree2, TryDynamicCallType )
817+ else
818+ typedDynamicSelect(tree2, Nil , pt)
816819
817820 // Otherwise, if the qualifier derives from class Dynamic, expand to a
818821 // dynamic dispatch using selectDynamic or applyDynamic
819- if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
820- return dynamicSelect(pt)
822+ def tryDynamic () =
823+ if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
824+ dynamicSelect(pt)
825+ else EmptyTree
821826
822827 // Otherwise, if the qualifier derives from class Selectable,
823828 // and the selector name matches one of the element of the `Fields` type member,
824829 // and the selector is not assigned to,
825830 // expand to a typed dynamic dispatch using selectDynamic wrapped in a cast
826- if qual.tpe.derivesFrom(defn.SelectableClass ) && ! isDynamicExpansion(tree)
827- && pt != LhsProto
828- then
829- val pre = if ! TypeOps .isLegalPrefix(qual.tpe) then SkolemType (qual.tpe) else qual.tpe
830- val fieldsType = pre.select(tpnme.Fields ).dealias.simplified
831- val fields = fieldsType.namedTupleElementTypes
832- typr.println(i " try dyn select $qual, $selName, $fields" )
833- fields.find(_._1 == selName) match
834- case Some ((_, fieldType)) =>
835- val dynSelected = dynamicSelect(fieldType)
836- dynSelected match
837- case Apply (sel : Select , _) if ! sel.denot.symbol.exists =>
838- // Reject corner case where selectDynamic needs annother selectDynamic to be called. E.g. as in neg/unselectable-fields.scala.
839- report.error(i " Cannot use selectDynamic here since it needs another selectDynamic to be invoked " , tree.srcPos)
840- case _ =>
841- return dynSelected.ensureConforms(fieldType)
842- case _ =>
831+ def trySelectable () =
832+ if qual.tpe.derivesFrom(defn.SelectableClass ) && ! isDynamicExpansion(tree)
833+ && pt != LhsProto
834+ then
835+ val pre = if ! TypeOps .isLegalPrefix(qual.tpe) then SkolemType (qual.tpe) else qual.tpe
836+ val fieldsType = pre.select(tpnme.Fields ).dealias.simplified
837+ val fields = fieldsType.namedTupleElementTypes
838+ typr.println(i " try dyn select $qual, $selName, $fields" )
839+ fields.find(_._1 == selName) match
840+ case Some ((_, fieldType)) =>
841+ val dynSelected = dynamicSelect(fieldType)
842+ dynSelected match
843+ case Apply (sel : Select , _) if ! sel.denot.symbol.exists =>
844+ // Reject corner case where selectDynamic needs annother selectDynamic to be called. E.g. as in neg/unselectable-fields.scala.
845+ report.error(i " Cannot use selectDynamic here since it needs another selectDynamic to be invoked " , tree.srcPos)
846+ case _ =>
847+ dynSelected.ensureConforms(fieldType)
848+ case _ => EmptyTree
849+ else EmptyTree
843850
844851 // Otherwise, if the qualifier is a context bound companion, handle
845852 // by selecting a witness in typedCBSelect
846- if qual.tpe.typeSymbol == defn.CBCompanion then
847- val witnessSelection = typedCBSelect(tree0, pt, qual)
848- if ! witnessSelection.isEmpty then return witnessSelection
853+ def tryCBCompanion () =
854+ if qual.tpe.typeSymbol == defn.CBCompanion then
855+ val witnessSelection = typedCBSelect(tree0, pt, qual)
856+ if ! witnessSelection.isEmpty then return witnessSelection
849857
850858 // Otherwise, report an error
851- assignType(tree,
852- rawType match
853- case rawType : NamedType =>
854- inaccessibleErrorType(rawType, superAccess, tree.srcPos)
855- case _ =>
856- notAMemberErrorType(tree, qual, pt))
857- end typedSelect
859+ def reportAnError () =
860+ assignType(tree,
861+ rawType match
862+ case rawType : NamedType =>
863+ inaccessibleErrorType(rawType, superAccess, tree.srcPos)
864+ case _ =>
865+ notAMemberErrorType(tree, qual, pt))
866+
867+ tryType(tree, qual, rawType)
868+ .orElse(trySimplifyApply())
869+ .orElse(tryInstantiateTypeVar())
870+ .orElse(tryNamedTupleSelection())
871+ .orElse(trySmallGenericTuple(qual, withCast = true ))
872+ .orElse(tryExt(tree, qual))
873+ .orElse(tryGadt(tree))
874+ .orElse(tryDefineFurther())
875+ .orElse(tryDynamic())
876+ .orElse(tryCBCompanion())
877+ .orElse(reportAnError())
878+ end typedSelectWithAdapt
858879
859880 /** Expand a selection A.m on a context bound companion A with type
860881 * `<context-bound-companion>[ref_1 | ... | ref_N]` as described by
@@ -938,7 +959,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
938959 if ctx.isJava then
939960 javaSelection(qual)
940961 else
941- typedSelect (tree, pt, qual).withSpan(tree.span).computeNullable()
962+ typedSelectWithAdapt (tree, pt, qual).withSpan(tree.span).computeNullable()
942963
943964 def javaSelection (qual : Tree )(using Context ) =
944965 val tree1 = assignType(cpy.Select (tree)(qual, tree.name), qual)
@@ -3879,7 +3900,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38793900 if isExtension then return found
38803901 else
38813902 checkImplicitConversionUseOK(found, selProto)
3882- return withoutMode(Mode .ImplicitsEnabled )(typedSelect (tree, pt, found))
3903+ return withoutMode(Mode .ImplicitsEnabled )(typedSelectWithAdapt (tree, pt, found))
38833904 case failure : SearchFailure =>
38843905 if failure.isAmbiguous then
38853906 return
0 commit comments