Skip to content

Commit 32f5200

Browse files
EugeneFlesselleWojciechMazur
authored andcommitted
Prefer extensions over conversions and implicits for member selection
Before the changes, if `isAsGoodValueType` was called with an extension and a given conversion, it would prefer the conversion over the extension, because only the former yielded true in `isGiven`. Which contradicted the logic from searchImplicit which preferred extension over conversions for member selection.
1 parent d03d2f8 commit 32f5200

File tree

2 files changed

+8
-9
lines changed

2 files changed

+8
-9
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,10 +1816,8 @@ trait Applications extends Compatibility {
18161816
isAsGood(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2)
18171817
}
18181818
case _ => // (3)
1819-
def isGiven(alt: TermRef) =
1820-
alt1.symbol.is(Given) && alt.symbol != defn.NotGivenClass
18211819
def compareValues(tp1: Type, tp2: Type)(using Context) =
1822-
isAsGoodValueType(tp1, tp2, isGiven(alt1), isGiven(alt2))
1820+
isAsGoodValueType(tp1, tp2, alt1.symbol.is(Implicit), alt2.symbol.is(Implicit))
18231821
tp2 match
18241822
case tp2: MethodType => true // (3a)
18251823
case tp2: PolyType if tp2.resultType.isInstanceOf[MethodType] => true // (3a)
@@ -1856,15 +1854,15 @@ trait Applications extends Compatibility {
18561854
* for overloading resolution (when `preferGeneral is false), and the opposite relation
18571855
* `U <: T` or `U convertible to `T` for implicit disambiguation between givens
18581856
* (when `preferGeneral` is true). For old-style implicit values, the 3.4 behavior is kept.
1859-
* If one of the alternatives is a given and the other is an implicit, the given wins.
1857+
* If one of the alternatives is an implicit and the other is a given (or an extension), the implicit loses.
18601858
*
18611859
* - In Scala 3.5 and Scala 3.6-migration, we issue a warning if the result under
18621860
* Scala 3.6 differ wrt to the old behavior up to 3.5.
18631861
*
18641862
* Also and only for given resolution: If a compared type refers to a given or its module class, use
18651863
* the intersection of its parent classes instead.
18661864
*/
1867-
def isAsGoodValueType(tp1: Type, tp2: Type, alt1isGiven: Boolean, alt2isGiven: Boolean)(using Context): Boolean =
1865+
def isAsGoodValueType(tp1: Type, tp2: Type, alt1IsImplicit: Boolean, alt2IsImplicit: Boolean)(using Context): Boolean =
18681866
val oldResolution = ctx.mode.is(Mode.OldImplicitResolution)
18691867
if !preferGeneral || Feature.migrateTo3 && oldResolution then
18701868
// Normal specificity test for overloading resolution (where `preferGeneral` is false)
@@ -1882,7 +1880,7 @@ trait Applications extends Compatibility {
18821880

18831881
if Feature.sourceVersion.isAtMost(SourceVersion.`3.4`)
18841882
|| oldResolution
1885-
|| !alt1isGiven && !alt2isGiven
1883+
|| alt1IsImplicit && alt2IsImplicit
18861884
then
18871885
// Intermediate rules: better means specialize, but map all type arguments downwards
18881886
// These are enabled for 3.0-3.5, and for all comparisons between old-style implicits,
@@ -1897,8 +1895,8 @@ trait Applications extends Compatibility {
18971895
case _ => mapOver(t)
18981896
(flip(tp1p) relaxed_<:< flip(tp2p)) || viewExists(tp1, tp2)
18991897
else
1900-
// New rules: better means generalize, givens always beat implicits
1901-
if alt1isGiven != alt2isGiven then alt1isGiven
1898+
// New rules: better means generalize, givens (and extensions) always beat implicits
1899+
if alt1IsImplicit != alt2IsImplicit then alt2IsImplicit
19021900
else (tp2p relaxed_<:< tp1p) || viewExists(tp2, tp1)
19031901
end isAsGoodValueType
19041902

tests/pos/i19715.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ class NT(t: Tup):
66
object NT:
77
extension (x: NT)
88
def app(n: Int): Boolean = true
9-
given Conversion[NT, Tup] = _.toTup
9+
given c1: Conversion[NT, Tup] = _.toTup
10+
implicit def c2(t: NT): Tup = c1(t)
1011

1112
def test =
1213
val nt = new NT(Tup())

0 commit comments

Comments
 (0)