@@ -729,131 +729,155 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
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 typedSelectWithAdapt(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 typedSelectWithAdapt(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(
777- tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
778- if ! tree1.isEmpty then
779- return tree1
785+ def tryExt ( tree : untpd. Select , qual : Tree ) =
786+ if selName.isTermName then
787+ tryExtensionOrConversion(
788+ tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
789+ else EmptyTree
780790
781791 // 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 typedSelectWithAdapt(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
792+ def tryGadt () =
793+ if ctx.gadt.isNarrowing then
794+ // Member lookup cannot take GADTs into account b/c of cache, so we
795+ // approximate types based on GADT constraints instead. For an example,
796+ // see MemberHealing in gadt-approximation-interaction.scala.
797+ val wtp = qual.tpe.widen
798+ gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
799+ val gadtApprox = Inferencing .approximateGADT(wtp)
800+ gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
801+ val qual1 = qual.cast(gadtApprox)
802+ val tree1 = cpy.Select (tree0)(qual1, selName)
803+ tryType(tree1, qual1, selectionType(tree1, qual1))
804+ .orElse(trySmallGenericTuple(qual1, withCast = false ))
805+ .orElse(tryExt(tree1, qual1))
806+ else EmptyTree
804807
805808 // Otherwise, if there are uninstantiated type variables in the qualifier type,
806809 // instantiate them and try again
807- if canDefineFurther(qual.tpe.widen) then
808- return typedSelectWithAdapt(tree, pt, qual)
810+ def tryDefineFurther () =
811+ if canDefineFurther(qual.tpe.widen) then
812+ typedSelectWithAdapt(tree, pt, qual)
813+ else EmptyTree
809814
810815 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)
816+ val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
817+ if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
818+ assignType(tree2, TryDynamicCallType )
819+ else
820+ typedDynamicSelect(tree2, Nil , pt)
816821
817822 // Otherwise, if the qualifier derives from class Dynamic, expand to a
818823 // dynamic dispatch using selectDynamic or applyDynamic
819- if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
820- return dynamicSelect(pt)
824+ def tryDynamic () =
825+ if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
826+ dynamicSelect(pt)
827+ else EmptyTree
821828
822829 // Otherwise, if the qualifier derives from class Selectable,
823830 // and the selector name matches one of the element of the `Fields` type member,
824831 // and the selector is not assigned to,
825832 // 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 _ =>
833+ def trySelectable () =
834+ if qual.tpe.derivesFrom(defn.SelectableClass ) && ! isDynamicExpansion(tree)
835+ && pt != LhsProto
836+ then
837+ val pre = if ! TypeOps .isLegalPrefix(qual.tpe) then SkolemType (qual.tpe) else qual.tpe
838+ val fieldsType = pre.select(tpnme.Fields ).dealias.simplified
839+ val fields = fieldsType.namedTupleElementTypes
840+ typr.println(i " try dyn select $qual, $selName, $fields" )
841+ fields.find(_._1 == selName) match
842+ case Some ((_, fieldType)) =>
843+ val dynSelected = dynamicSelect(fieldType)
844+ dynSelected match
845+ case Apply (sel : Select , _) if ! sel.denot.symbol.exists =>
846+ // Reject corner case where selectDynamic needs annother selectDynamic to be called. E.g. as in neg/unselectable-fields.scala.
847+ report.error(i " Cannot use selectDynamic here since it needs another selectDynamic to be invoked " , tree.srcPos)
848+ case _ =>
849+ dynSelected.ensureConforms(fieldType)
850+ case _ => EmptyTree
851+ else EmptyTree
843852
844853 // Otherwise, if the qualifier is a context bound companion, handle
845854 // 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
855+ def tryCBCompanion () =
856+ if qual.tpe.typeSymbol == defn.CBCompanion then
857+ typedCBSelect(tree0, pt, qual)
858+ else EmptyTree
849859
850860 // 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))
861+ def reportAnError () =
862+ assignType(tree,
863+ rawType match
864+ case rawType : NamedType =>
865+ inaccessibleErrorType(rawType, superAccess, tree.srcPos)
866+ case _ =>
867+ notAMemberErrorType(tree, qual, pt))
868+
869+ tryType(tree, qual, rawType)
870+ .orElse(trySimplifyApply())
871+ .orElse(tryInstantiateTypeVar())
872+ .orElse(tryNamedTupleSelection())
873+ .orElse(trySmallGenericTuple(qual, withCast = true ))
874+ .orElse(tryExt(tree, qual))
875+ .orElse(tryGadt())
876+ .orElse(tryDefineFurther())
877+ .orElse(tryDynamic())
878+ .orElse(trySelectable())
879+ .orElse(tryCBCompanion())
880+ .orElse(reportAnError())
857881 end typedSelectWithAdapt
858882
859883 /** Expand a selection A.m on a context bound companion A with type
0 commit comments