Skip to content

Commit 184bdc2

Browse files
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 2facda0 commit 184bdc2

File tree

2 files changed

+8
-9
lines changed

2 files changed

+8
-9
lines changed

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

+6-8
Original file line numberDiff line numberDiff line change
@@ -1821,10 +1821,8 @@ trait Applications extends Compatibility {
18211821
isAsGood(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2)
18221822
}
18231823
case _ => // (3)
1824-
def isGiven(alt: TermRef) =
1825-
alt.symbol.is(Given) && alt.symbol != defn.NotGivenClass
18261824
def compareValues(tp1: Type, tp2: Type)(using Context) =
1827-
isAsGoodValueType(tp1, tp2, isGiven(alt1), isGiven(alt2))
1825+
isAsGoodValueType(tp1, tp2, alt1.symbol.is(Implicit), alt2.symbol.is(Implicit))
18281826
tp2 match
18291827
case tp2: MethodType => true // (3a)
18301828
case tp2: PolyType if tp2.resultType.isInstanceOf[MethodType] => true // (3a)
@@ -1861,15 +1859,15 @@ trait Applications extends Compatibility {
18611859
* for overloading resolution (when `preferGeneral is false), and the opposite relation
18621860
* `U <: T` or `U convertible to `T` for implicit disambiguation between givens
18631861
* (when `preferGeneral` is true). For old-style implicit values, the 3.4 behavior is kept.
1864-
* If one of the alternatives is a given and the other is an implicit, the given wins.
1862+
* If one of the alternatives is an implicit and the other is a given (or an extension), the implicit loses.
18651863
*
18661864
* - In Scala 3.5 and Scala 3.6-migration, we issue a warning if the result under
18671865
* Scala 3.6 differ wrt to the old behavior up to 3.5.
18681866
*
18691867
* Also and only for given resolution: If a compared type refers to a given or its module class, use
18701868
* the intersection of its parent classes instead.
18711869
*/
1872-
def isAsGoodValueType(tp1: Type, tp2: Type, alt1isGiven: Boolean, alt2isGiven: Boolean)(using Context): Boolean =
1870+
def isAsGoodValueType(tp1: Type, tp2: Type, alt1IsImplicit: Boolean, alt2IsImplicit: Boolean)(using Context): Boolean =
18731871
val oldResolution = ctx.mode.is(Mode.OldImplicitResolution)
18741872
if !preferGeneral || Feature.migrateTo3 && oldResolution then
18751873
// Normal specificity test for overloading resolution (where `preferGeneral` is false)
@@ -1887,7 +1885,7 @@ trait Applications extends Compatibility {
18871885

18881886
if Feature.sourceVersion.isAtMost(SourceVersion.`3.4`)
18891887
|| oldResolution
1890-
|| !alt1isGiven && !alt2isGiven
1888+
|| alt1IsImplicit && alt2IsImplicit
18911889
then
18921890
// Intermediate rules: better means specialize, but map all type arguments downwards
18931891
// These are enabled for 3.0-3.5, and for all comparisons between old-style implicits,
@@ -1902,8 +1900,8 @@ trait Applications extends Compatibility {
19021900
case _ => mapOver(t)
19031901
(flip(tp1p) relaxed_<:< flip(tp2p)) || viewExists(tp1, tp2)
19041902
else
1905-
// New rules: better means generalize, givens always beat implicits
1906-
if alt1isGiven != alt2isGiven then alt1isGiven
1903+
// New rules: better means generalize, givens (and extensions) always beat implicits
1904+
if alt1IsImplicit != alt2IsImplicit then alt2IsImplicit
19071905
else (tp2p relaxed_<:< tp1p) || viewExists(tp2, tp1)
19081906
end isAsGoodValueType
19091907

tests/pos/i19715.scala

+2-1
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)