@@ -683,71 +683,90 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
683683 then
684684 report.error(StableIdentPattern (tree, pt), tree.srcPos)
685685
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 =
687687 val selName = tree0.name
688688 val tree = cpy.Select (tree0)(qual, selName)
689689 val superAccess = qual.isInstanceOf [Super ]
690690 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 )
743752 && selName.isTermName && ! isDynamicExpansion(tree)
744753 then
745754 val tree2 = cpy.Select (tree0)(untpd.TypedSplice (qual), selName)
746755 if pt.isInstanceOf [FunOrPolyProto ] || pt == LhsProto then
747756 assignType(tree2, TryDynamicCallType )
748757 else
749758 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:
751770 assignType(tree,
752771 rawType match
753772 case rawType : NamedType =>
@@ -761,7 +780,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
761780
762781 def typeSelectOnTerm (using Context ): Tree =
763782 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()
765784
766785 def javaSelectOnType (qual : Tree )(using Context ) =
767786 // semantic name conversion for `O$` in java code
@@ -3619,7 +3638,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
36193638 if isExtension then return found
36203639 else
36213640 checkImplicitConversionUseOK(found, selProto)
3622- return withoutMode(Mode .ImplicitsEnabled )(typedSelect (tree, pt, found))
3641+ return withoutMode(Mode .ImplicitsEnabled )(typedSelectWithAdapt (tree, pt, found))
36233642 case failure : SearchFailure =>
36243643 if failure.isAmbiguous then
36253644 return
0 commit comments