@@ -681,85 +681,133 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
681
681
then
682
682
report.error(StableIdentPattern (tree, pt), tree.srcPos)
683
683
684
- def typedSelect (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
684
+ def typedSelectWithAdapt (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
685
685
val selName = tree0.name
686
686
val tree = cpy.Select (tree0)(qual, selName)
687
687
val superAccess = qual.isInstanceOf [Super ]
688
688
val rawType = selectionType(tree, qual)
689
- val checkedType = accessibleType(rawType, superAccess)
690
-
691
- def finish (tree : untpd.Select , qual : Tree , checkedType : Type ): Tree =
692
- val select = toNotNullTermRef(assignType(tree, checkedType), pt)
693
- if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, " type prefix" )
694
- checkLegalValue(select, pt)
695
- ConstFold (select)
696
-
697
- if checkedType.exists then
698
- finish(tree, qual, checkedType)
699
- else if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
700
- // Simplify `m.apply(...)` to `m(...)`
701
- qual
702
- else if couldInstantiateTypeVar(qual.tpe.widen) then
703
- // there's a simply visible type variable in the result; try again with a more defined qualifier type
704
- // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
705
- // but that is done only after we search for extension methods or conversions.
706
- typedSelect(tree, pt, qual)
707
- else if qual.tpe.isSmallGenericTuple then
708
- val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
709
- typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
710
- else
711
- val tree1 = tryExtensionOrConversion(
712
- tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
713
- .orElse {
714
- if ctx.gadt.isNarrowing then
715
- // try GADT approximation if we're trying to select a member
716
- // Member lookup cannot take GADTs into account b/c of cache, so we
717
- // approximate types based on GADT constraints instead. For an example,
718
- // see MemberHealing in gadt-approximation-interaction.scala.
719
- val wtp = qual.tpe.widen
720
- gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
721
- val gadtApprox = Inferencing .approximateGADT(wtp)
722
- gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
723
- val qual1 = qual.cast(gadtApprox)
724
- val tree1 = cpy.Select (tree0)(qual1, selName)
725
- val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false )
726
- if checkedType1.exists then
727
- gadts.println(i " Member selection healed by GADT approximation " )
728
- finish(tree1, qual1, checkedType1)
729
- else if qual1.tpe.isSmallGenericTuple then
730
- gadts.println(i " Tuple member selection healed by GADT approximation " )
731
- typedSelect(tree, pt, qual1)
732
- else
733
- tryExtensionOrConversion(tree1, pt, IgnoredProto (pt), qual1, ctx.typerState.ownedVars, this , inSelect = true )
734
- else EmptyTree
735
- }
736
- if ! tree1.isEmpty then
737
- tree1
738
- else if canDefineFurther(qual.tpe.widen) then
739
- typedSelect(tree, pt, qual)
740
- else if qual.tpe.derivesFrom(defn.DynamicClass )
741
- && selName.isTermName && ! isDynamicExpansion(tree)
742
- then
689
+
690
+ def tryType (tree : untpd.Select , qual : Tree , rawType : Type ) =
691
+ val checkedType = accessibleType(rawType, superAccess)
692
+ // If regular selection is typeable, we are done
693
+ if checkedType.exists then
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
+ else EmptyTree
699
+
700
+ // Otherwise, simplify `m.apply(...)` to `m(...)`
701
+ def trySimplifyApply () =
702
+ if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
703
+ qual
704
+ else EmptyTree
705
+
706
+ // Otherwise, if there's a simply visible type variable in the result, try again
707
+ // with a more defined qualifier type. There's a second trial where we try to instantiate
708
+ // all type variables in `qual.tpe.widen`, but that is done only after we search for
709
+ // extension methods or conversions.
710
+ def tryInstantiateTypeVar () =
711
+ if couldInstantiateTypeVar(qual.tpe.widen) then
712
+ // there's a simply visible type variable in the result; try again with a more defined qualifier type
713
+ // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
714
+ // but that is done only after we search for extension methods or conversions.
715
+ typedSelectWithAdapt(tree, pt, qual)
716
+ else EmptyTree
717
+
718
+ // Otherwise, heal member selection on an opaque reference,
719
+ // reusing the logic in TypeComparer.
720
+ def tryLiftToThis () =
721
+ val wtp = qual.tpe.widen
722
+ val liftedTp = comparing(_.liftToThis(wtp))
723
+ if liftedTp ne wtp then
724
+ val qual1 = qual.cast(liftedTp)
725
+ val tree1 = cpy.Select (tree0)(qual1, selName)
726
+ val rawType1 = selectionType(tree1, qual1)
727
+ tryType(tree1, qual1, rawType1)
728
+ else EmptyTree
729
+
730
+ // Otherwise, map combinations of A *: B *: .... EmptyTuple with nesting levels <= 22
731
+ // to the Tuple class of the right arity and select from that one
732
+ def trySmallGenericTuple (qual : Tree , withCast : Boolean ) =
733
+ if qual.tpe.isSmallGenericTuple then
734
+ if withCast then
735
+ val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
736
+ typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
737
+ else
738
+ typedSelectWithAdapt(tree, pt, qual)
739
+ else EmptyTree
740
+
741
+ // Otherwise try an extension or conversion
742
+ def tryExt (tree : untpd.Select , qual : Tree ) =
743
+ tryExtensionOrConversion(
744
+ tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true
745
+ )
746
+
747
+ // Otherwise, try a GADT approximation if we're trying to select a member
748
+ def tryGadt () =
749
+ if ctx.gadt.isNarrowing then
750
+ // Member lookup cannot take GADTs into account b/c of cache, so we
751
+ // approximate types based on GADT constraints instead. For an example,
752
+ // see MemberHealing in gadt-approximation-interaction.scala.
753
+ val wtp = qual.tpe.widen
754
+ gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
755
+ val gadtApprox = Inferencing .approximateGADT(wtp)
756
+ gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
757
+ val qual1 = qual.cast(gadtApprox)
758
+ val tree1 = cpy.Select (tree0)(qual1, selName)
759
+ tryType(tree1, qual1, selectionType(tree1, qual1))
760
+ .orElse(trySmallGenericTuple(qual1, withCast = false ))
761
+ .orElse(tryExt(tree1, qual1))
762
+ else EmptyTree
763
+
764
+ // Otherwise, if there are uninstantiated type variables in the qualifier type,
765
+ // instantiate them and try again
766
+ def tryDefineFurther () =
767
+ if canDefineFurther(qual.tpe.widen) then
768
+ typedSelectWithAdapt(tree, pt, qual)
769
+ else EmptyTree
770
+
771
+ def dynamicSelect (pt : Type ) =
743
772
val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
744
773
if pt.isInstanceOf [FunOrPolyProto ] || pt == AssignProto then
745
774
assignType(tree2, TryDynamicCallType )
746
775
else
747
776
typedDynamicSelect(tree2, Nil , pt)
748
- else
749
- assignType(tree,
750
- rawType match
751
- case rawType : NamedType =>
752
- inaccessibleErrorType(rawType, superAccess, tree.srcPos)
753
- case _ =>
754
- notAMemberErrorType(tree, qual, pt))
755
- end typedSelect
777
+
778
+ // Otherwise, if the qualifier derives from class Dynamic, expand to a
779
+ // dynamic dispatch using selectDynamic or applyDynamic
780
+ def tryDynamic () =
781
+ if qual.tpe.derivesFrom(defn.DynamicClass ) && selName.isTermName && ! isDynamicExpansion(tree) then
782
+ dynamicSelect(pt)
783
+ else EmptyTree
784
+
785
+ def reportAnError () =
786
+ assignType(tree,
787
+ rawType match
788
+ case rawType : NamedType =>
789
+ inaccessibleErrorType(rawType, superAccess, tree.srcPos)
790
+ case _ =>
791
+ notAMemberErrorType(tree, qual, pt))
792
+
793
+ tryType(tree, qual, rawType)
794
+ .orElse(trySimplifyApply())
795
+ .orElse(tryInstantiateTypeVar())
796
+ .orElse(tryLiftToThis())
797
+ .orElse(trySmallGenericTuple(qual, withCast = true ))
798
+ .orElse(tryExt(tree, qual))
799
+ .orElse(tryGadt())
800
+ .orElse(tryDefineFurther())
801
+ .orElse(tryDynamic())
802
+ .orElse(reportAnError())
803
+ end typedSelectWithAdapt
756
804
757
805
def typedSelect (tree : untpd.Select , pt : Type )(using Context ): Tree = {
758
806
record(" typedSelect" )
759
807
760
808
def typeSelectOnTerm (using Context ): Tree =
761
809
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this , tree.nameSpan))
762
- typedSelect (tree, pt, qual).withSpan(tree.span).computeNullable()
810
+ typedSelectWithAdapt (tree, pt, qual).withSpan(tree.span).computeNullable()
763
811
764
812
def javaSelectOnType (qual : Tree )(using Context ) =
765
813
// semantic name conversion for `O$` in java code
@@ -3563,7 +3611,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3563
3611
if isExtension then return found
3564
3612
else
3565
3613
checkImplicitConversionUseOK(found, selProto)
3566
- return withoutMode(Mode .ImplicitsEnabled )(typedSelect (tree, pt, found))
3614
+ return withoutMode(Mode .ImplicitsEnabled )(typedSelectWithAdapt (tree, pt, found))
3567
3615
case failure : SearchFailure =>
3568
3616
if failure.isAmbiguous then
3569
3617
return
0 commit comments