@@ -721,86 +721,109 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
721
721
checkLegalValue(select, pt)
722
722
ConstFold (select)
723
723
724
+ // If regular selection is typeable, we are done
724
725
if checkedType.exists then
725
- finish(tree, qual, checkedType)
726
- else if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
727
- // Simplify `m.apply(...)` to `m(...)`
728
- qual
729
- else if couldInstantiateTypeVar(qual.tpe.widen) then
726
+ return finish(tree, qual, checkedType)
727
+
728
+ // Otherwise, simplify `m.apply(...)` to `m(...)`
729
+ if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
730
+ return qual
731
+
732
+ // Otherwise, if there's a simply visible type variable in the result, try again
733
+ // with a more defined qualifier type. There's a second trial where we try to instantiate
734
+ // all type variables in `qual.tpe.widen`, but that is done only after we search for
735
+ // extension methods or conversions.
736
+ if couldInstantiateTypeVar(qual.tpe.widen) then
730
737
// there's a simply visible type variable in the result; try again with a more defined qualifier type
731
738
// There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
732
739
// but that is done only after we search for extension methods or conversions.
733
- typedSelect(tree, pt, qual)
734
- else
735
- val namedTupleElems = qual.tpe.widen.namedTupleElementTypes
736
- val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
737
- if nameIdx >= 0 && Feature .enabled(Feature .namedTuples) then
738
- typed(
739
- untpd.Apply (
740
- untpd.Select (untpd.TypedSplice (qual), nme.apply),
741
- untpd.Literal (Constant (nameIdx))),
742
- pt)
743
- else if qual.tpe.isSmallGenericTuple then
744
- val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
745
- typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
740
+ return typedSelect(tree, pt, qual)
741
+
742
+ // Otherwise, try to expand a named tuple selection
743
+ val namedTupleElems = qual.tpe.widen.namedTupleElementTypes
744
+ val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
745
+ if nameIdx >= 0 && Feature .enabled(Feature .namedTuples) then
746
+ return typed(
747
+ untpd.Apply (
748
+ untpd.Select (untpd.TypedSplice (qual), nme.apply),
749
+ untpd.Literal (Constant (nameIdx))),
750
+ pt)
751
+
752
+ // Otherwise, map combinations of A *: B *: .... EmptyTuple with nesting levels <= 22
753
+ // to the Tuple class of the right arity and select from that one
754
+ if qual.tpe.isSmallGenericTuple then
755
+ val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
756
+ return typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
757
+
758
+ // Otherwise try an extension or conversion
759
+ val tree1 = tryExtensionOrConversion(
760
+ tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
761
+ if ! tree1.isEmpty then
762
+ return tree1
763
+
764
+ // Otherwise, try a GADT approximation if we're trying to select a member
765
+ // Member lookup cannot take GADTs into account b/c of cache, so we
766
+ // approximate types based on GADT constraints instead. For an example,
767
+ // see MemberHealing in gadt-approximation-interaction.scala.
768
+ if ctx.gadt.isNarrowing then
769
+ val wtp = qual.tpe.widen
770
+ gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
771
+ val gadtApprox = Inferencing .approximateGADT(wtp)
772
+ gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
773
+ val qual1 = qual.cast(gadtApprox)
774
+ val tree1 = cpy.Select (tree0)(qual1, selName)
775
+ val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false )
776
+ if checkedType1.exists then
777
+ gadts.println(i " Member selection healed by GADT approximation " )
778
+ return finish(tree1, qual1, checkedType1)
779
+
780
+ if qual1.tpe.isSmallGenericTuple then
781
+ gadts.println(i " Tuple member selection healed by GADT approximation " )
782
+ return typedSelect(tree, pt, qual1)
783
+
784
+ val tree2 = tryExtensionOrConversion(tree1, pt, IgnoredProto (pt), qual1, ctx.typerState.ownedVars, this , inSelect = true )
785
+ if ! tree2.isEmpty then
786
+ return tree2
787
+
788
+ // Otherwise, if there are uninstantiated type variables in the qualifier type,
789
+ // instantiate them and try again
790
+ if canDefineFurther(qual.tpe.widen) then
791
+ return typedSelect(tree, pt, qual)
792
+
793
+ def dynamicSelect =
794
+ val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
795
+ if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
796
+ assignType(tree2, TryDynamicCallType )
746
797
else
747
- val tree1 = tryExtensionOrConversion(
748
- tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
749
- .orElse {
750
- if ctx.gadt.isNarrowing then
751
- // try GADT approximation if we're trying to select a member
752
- // Member lookup cannot take GADTs into account b/c of cache, so we
753
- // approximate types based on GADT constraints instead. For an example,
754
- // see MemberHealing in gadt-approximation-interaction.scala.
755
- val wtp = qual.tpe.widen
756
- gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
757
- val gadtApprox = Inferencing .approximateGADT(wtp)
758
- gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
759
- val qual1 = qual.cast(gadtApprox)
760
- val tree1 = cpy.Select (tree0)(qual1, selName)
761
- val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false )
762
- if checkedType1.exists then
763
- gadts.println(i " Member selection healed by GADT approximation " )
764
- finish(tree1, qual1, checkedType1)
765
- else if qual1.tpe.isSmallGenericTuple then
766
- gadts.println(i " Tuple member selection healed by GADT approximation " )
767
- typedSelect(tree, pt, qual1)
768
- else
769
- tryExtensionOrConversion(tree1, pt, IgnoredProto (pt), qual1, ctx.typerState.ownedVars, this , inSelect = true )
770
- else EmptyTree
771
- }
772
- if ! tree1.isEmpty then
773
- tree1
774
- else if canDefineFurther(qual.tpe.widen) then
775
- typedSelect(tree, pt, qual)
776
- else if qual.tpe.derivesFrom(defn.DynamicClass )
777
- && selName.isTermName && ! isDynamicExpansion(tree)
778
- then
779
- val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
780
- if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
781
- assignType(tree2, TryDynamicCallType )
782
- else
783
- typedDynamicSelect(tree2, Nil , pt)
784
- else
785
- if qual.tpe.derivesFrom(defn.SelectableClass )
786
- && selName.isTermName && ! isDynamicExpansion(tree)
787
- && ! pt.isInstanceOf [FunOrPolyProto ] && pt != LhsProto
788
- then
789
- val fieldsType = qual.tpe.select(tpnme.Fields ).dealias.simplified
790
- val fields = fieldsType.namedTupleElementTypes
791
- typr.println(i " try dyn select $qual, $selName, $fields" )
792
- fields.find(_._1 == selName) match
793
- case Some ((fieldName, fieldType)) =>
794
- val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
795
- val sel = typedDynamicSelect(tree2, Nil , pt)
796
- return sel.cast(fieldType)
797
- case _ =>
798
- assignType(tree,
799
- rawType match
800
- case rawType : NamedType =>
801
- inaccessibleErrorType(rawType, superAccess, tree.srcPos)
802
- case _ =>
803
- notAMemberErrorType(tree, qual, pt))
798
+ typedDynamicSelect(tree2, Nil , pt)
799
+
800
+ // Otherwise, if the qualifier derives from class Dynamic, expand to a
801
+ // dynamic dispatch using selectDynamic or applyDynamic
802
+ if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
803
+ return dynamicSelect
804
+
805
+ // Otherwise, if the qualifier derives from class Selectable,
806
+ // and the selector name matches one of the element of the `Fields` type member,
807
+ // and the selector is neither applied nor assigned to,
808
+ // expand to a typed dynamic dispatch using selectDynamic wrapped in a cast
809
+ if qual.tpe.derivesFrom(defn.SelectableClass ) && ! isDynamicExpansion(tree)
810
+ && ! pt.isInstanceOf [FunOrPolyProto ] && pt != LhsProto
811
+ then
812
+ val fieldsType = qual.tpe.select(tpnme.Fields ).dealias.simplified
813
+ val fields = fieldsType.namedTupleElementTypes
814
+ typr.println(i " try dyn select $qual, $selName, $fields" )
815
+ fields.find(_._1 == selName) match
816
+ case Some ((_, fieldType)) =>
817
+ return dynamicSelect.cast(fieldType)
818
+ case _ =>
819
+
820
+ // Otherwise, report an error
821
+ assignType(tree,
822
+ rawType match
823
+ case rawType : NamedType =>
824
+ inaccessibleErrorType(rawType, superAccess, tree.srcPos)
825
+ case _ =>
826
+ notAMemberErrorType(tree, qual, pt))
804
827
end typedSelect
805
828
806
829
def typedSelect (tree : untpd.Select , pt : Type )(using Context ): Tree = {
0 commit comments