@@ -729,131 +729,155 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
729
729
val tree = cpy.Select (tree0)(qual, selName)
730
730
val superAccess = qual.isInstanceOf [Super ]
731
731
val rawType = selectionType(tree, qual)
732
- val checkedType = accessibleType(rawType, superAccess)
733
732
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
743
742
744
743
// 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
747
748
748
749
// Otherwise, if there's a simply visible type variable in the result, try again
749
750
// with a more defined qualifier type. There's a second trial where we try to instantiate
750
751
// all type variables in `qual.tpe.widen`, but that is done only after we search for
751
752
// 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
757
760
758
761
// 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
767
772
768
773
// Otherwise, map combinations of A *: B *: .... EmptyTuple with nesting levels <= 22
769
774
// 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
773
783
774
784
// 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
780
790
781
791
// 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
804
807
805
808
// Otherwise, if there are uninstantiated type variables in the qualifier type,
806
809
// 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
809
814
810
815
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)
816
821
817
822
// Otherwise, if the qualifier derives from class Dynamic, expand to a
818
823
// 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
821
828
822
829
// Otherwise, if the qualifier derives from class Selectable,
823
830
// and the selector name matches one of the element of the `Fields` type member,
824
831
// and the selector is not assigned to,
825
832
// 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
843
852
844
853
// Otherwise, if the qualifier is a context bound companion, handle
845
854
// 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
849
859
850
860
// 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())
857
881
end typedSelectWithAdapt
858
882
859
883
/** Expand a selection A.m on a context bound companion A with type
0 commit comments