@@ -683,85 +683,104 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
683
683
then
684
684
report.error(StableIdentPattern (tree, pt), tree.srcPos)
685
685
686
- def typedSelect (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
686
+ def typedSelectWithAdapt (tree0 : untpd.Select , pt : Type , qual : Tree )(using Context ): Tree =
687
687
val selName = tree0.name
688
688
val tree = cpy.Select (tree0)(qual, selName)
689
689
val superAccess = qual.isInstanceOf [Super ]
690
690
val rawType = selectionType(tree, qual)
691
- val checkedType = accessibleType(rawType, superAccess)
692
-
693
- def finish (tree : untpd.Select , qual : Tree , checkedType : Type ): Tree =
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
-
699
- if checkedType.exists then
700
- finish(tree, qual, checkedType)
701
- else if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
702
- // Simplify `m.apply(...)` to `m(...)`
703
- qual
704
- else if couldInstantiateTypeVar(qual.tpe.widen) then
705
- // there's a simply visible type variable in the result; try again with a more defined qualifier type
706
- // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
707
- // but that is done only after we search for extension methods or conversions.
708
- typedSelect(tree, pt, qual)
709
- else if qual.tpe.isSmallGenericTuple then
710
- val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
711
- typedSelect(tree, pt, qual.cast(defn.tupleType(elems)))
712
- else
713
- val tree1 = tryExtensionOrConversion(
714
- tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
715
- .orElse {
716
- if ctx.gadt.isNarrowing then
717
- // try GADT approximation if we're trying to select a member
718
- // Member lookup cannot take GADTs into account b/c of cache, so we
719
- // approximate types based on GADT constraints instead. For an example,
720
- // see MemberHealing in gadt-approximation-interaction.scala.
721
- val wtp = qual.tpe.widen
722
- gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
723
- val gadtApprox = Inferencing .approximateGADT(wtp)
724
- gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
725
- val qual1 = qual.cast(gadtApprox)
726
- val tree1 = cpy.Select (tree0)(qual1, selName)
727
- val checkedType1 = accessibleType(selectionType(tree1, qual1), superAccess = false )
728
- if checkedType1.exists then
729
- gadts.println(i " Member selection healed by GADT approximation " )
730
- finish(tree1, qual1, checkedType1)
731
- else if qual1.tpe.isSmallGenericTuple then
732
- gadts.println(i " Tuple member selection healed by GADT approximation " )
733
- typedSelect(tree, pt, qual1)
734
- else
735
- tryExtensionOrConversion(tree1, pt, IgnoredProto (pt), qual1, ctx.typerState.ownedVars, this , inSelect = true )
736
- else EmptyTree
737
- }
738
- if ! tree1.isEmpty then
739
- tree1
740
- else if canDefineFurther(qual.tpe.widen) then
741
- typedSelect(tree, pt, qual)
742
- else if qual.tpe.derivesFrom(defn.DynamicClass )
691
+
692
+ def tryType (tree : untpd.Select , qual : Tree , rawType : Type ) =
693
+ val checkedType = accessibleType(rawType, superAccess)
694
+ if checkedType.exists then
695
+ val select = toNotNullTermRef(assignType(tree, checkedType), pt)
696
+ if selName.isTypeName then checkStable(qual.tpe, qual.srcPos, " type prefix" )
697
+ checkLegalValue(select, pt)
698
+ ConstFold (select)
699
+ else EmptyTree
700
+
701
+ def trySimplifyApply () =
702
+ if selName == nme.apply && qual.tpe.widen.isInstanceOf [MethodType ] then
703
+ // Simplify `m.apply(...)` to `m(...)`
704
+ qual
705
+ else EmptyTree
706
+
707
+ def tryInstantiateTypeVar () =
708
+ if couldInstantiateTypeVar(qual.tpe.widen) then
709
+ // there's a simply visible type variable in the result; try again with a more defined qualifier type
710
+ // There's a second trial where we try to instantiate all type variables in `qual.tpe.widen`,
711
+ // but that is done only after we search for extension methods or conversions.
712
+ typedSelectWithAdapt(tree, pt, qual)
713
+ else EmptyTree
714
+
715
+ def trySmallGenericTuple (tree : untpd.Select , qual : Tree , withCast : Boolean ) =
716
+ if qual.tpe.isSmallGenericTuple then
717
+ if withCast then
718
+ val elems = qual.tpe.widenTermRefExpr.tupleElementTypes.getOrElse(Nil )
719
+ typedSelectWithAdapt(tree, pt, qual.cast(defn.tupleType(elems)))
720
+ else
721
+ typedSelectWithAdapt(tree, pt, qual)
722
+ else EmptyTree
723
+
724
+ def tryExt (tree : untpd.Select , qual : Tree ) =
725
+ tryExtensionOrConversion(
726
+ tree, pt, IgnoredProto (pt), qual, ctx.typerState.ownedVars, this , inSelect = true )
727
+
728
+ def tryGadt (tree : untpd.Select ) =
729
+ if ctx.gadt.isNarrowing then
730
+ // try GADT approximation if we're trying to select a member
731
+ // Member lookup cannot take GADTs into account b/c of cache, so we
732
+ // approximate types based on GADT constraints instead. For an example,
733
+ // see MemberHealing in gadt-approximation-interaction.scala.
734
+ val wtp = qual.tpe.widen
735
+ gadts.println(i " Trying to heal member selection by GADT-approximating $wtp" )
736
+ val gadtApprox = Inferencing .approximateGADT(wtp)
737
+ gadts.println(i " GADT-approximated $wtp ~~ $gadtApprox" )
738
+ val qual1 = qual.cast(gadtApprox)
739
+ val tree1 = cpy.Select (tree0)(qual1, selName)
740
+ tryType(tree1, qual1, selectionType(tree1, qual1))
741
+ .orElse(trySmallGenericTuple(tree, qual1, withCast = false ))
742
+ .orElse(tryExt(tree1, qual1))
743
+ else EmptyTree
744
+
745
+ def tryDefineFurther () =
746
+ if canDefineFurther(qual.tpe.widen) then
747
+ typedSelectWithAdapt(tree, pt, qual)
748
+ else EmptyTree
749
+
750
+ def tryDynamic () =
751
+ if qual.tpe.derivesFrom(defn.DynamicClass )
743
752
&& selName.isTermName && ! isDynamicExpansion(tree)
744
753
then
745
754
val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
746
755
if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
747
756
assignType(tree2, TryDynamicCallType )
748
757
else
749
758
typedDynamicSelect(tree2, Nil , pt)
750
- else
759
+ else EmptyTree
760
+
761
+ tryType(tree, qual, rawType)
762
+ .orElse(trySimplifyApply())
763
+ .orElse(tryInstantiateTypeVar())
764
+ .orElse(trySmallGenericTuple(tree, qual, withCast = true ))
765
+ .orElse(tryExt(tree, qual))
766
+ .orElse(tryGadt(tree))
767
+ .orElse(tryDefineFurther())
768
+ .orElse(tryDynamic())
769
+ .orElse:
751
770
assignType(tree,
752
771
rawType match
753
772
case rawType : NamedType =>
754
773
inaccessibleErrorType(rawType, superAccess, tree.srcPos)
755
774
case _ =>
756
775
notAMemberErrorType(tree, qual, pt))
757
- end typedSelect
776
+ end typedSelectWithAdapt
758
777
759
778
def typedSelect (tree : untpd.Select , pt : Type )(using Context ): Tree = {
760
779
record(" typedSelect" )
761
780
762
781
def typeSelectOnTerm (using Context ): Tree =
763
782
val qual = typedExpr(tree.qualifier, shallowSelectionProto(tree.name, pt, this , tree.nameSpan))
764
- typedSelect (tree, pt, qual).withSpan(tree.span).computeNullable()
783
+ typedSelectWithAdapt (tree, pt, qual).withSpan(tree.span).computeNullable()
765
784
766
785
def javaSelectOnType (qual : Tree )(using Context ) =
767
786
// semantic name conversion for `O$` in java code
@@ -3619,7 +3638,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3619
3638
if isExtension then return found
3620
3639
else
3621
3640
checkImplicitConversionUseOK(found, selProto)
3622
- return withoutMode(Mode .ImplicitsEnabled )(typedSelect (tree, pt, found))
3641
+ return withoutMode(Mode .ImplicitsEnabled )(typedSelectWithAdapt (tree, pt, found))
3623
3642
case failure : SearchFailure =>
3624
3643
if failure.isAmbiguous then
3625
3644
return
0 commit comments