Skip to content

Commit 2cfa9b9

Browse files
committed
Defend against AliasingBounds
In refchecks for extension methods, obtain a TypeRef of the receiver parameter type, so that it is correctly dealiased. The prior idiom produced a TypeAlias.
1 parent 91351e3 commit 2cfa9b9

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

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

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,16 +1158,11 @@ object RefChecks {
11581158
*/
11591159
def checkExtensionMethods(sym: Symbol)(using Context): Unit =
11601160
if sym.is(Extension) then atPhase(typerPhase):
1161-
extension (tp: Type)
1162-
def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true)
1163-
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
1164-
def isParamLess = tp.stripPoly match { case mt: MethodType => false case _ => true }
1161+
extension (tp: Type) def explicit = Applications.stripImplicit(tp.widen, wildcardOnly = false)
11651162
val explicitInfo = sym.info.explicit // consider explicit value params
11661163
def memberHidesMethod(member: Denotation): Boolean =
1167-
val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter
1168-
if methTp.isParamLess then
1169-
return true // extension without parens is always hidden by a member of same name
1170-
val memberIsImplicit = member.info.hasImplicitParams
1164+
val methTp = explicitInfo.stripPoly.resultType // skip leading implicits and the "receiver" parameter
1165+
val memberIsImplicit = member.info.isImplicitMethod
11711166
inline def paramsCorrespond =
11721167
val paramTps =
11731168
if memberIsImplicit then methTp.stripPoly.firstParamTypes
@@ -1176,11 +1171,13 @@ object RefChecks {
11761171
memberParamTps.corresponds(paramTps): (m, x) =>
11771172
m.typeSymbol.denot.isOpaqueAlias == x.typeSymbol.denot.isOpaqueAlias
11781173
&& (x frozen_<:< m)
1179-
memberIsImplicit && !methTp.hasImplicitParams || paramsCorrespond
1174+
1175+
methTp.isParameterless // extension without parens is always hidden by a member of same name
1176+
|| memberIsImplicit && !methTp.isImplicitMethod // see above
1177+
|| paramsCorrespond // match by type and opacity
11801178
def targetOfHiddenExtension: Symbol =
1181-
val target =
1182-
val target0 = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver
1183-
target0.dealiasKeepOpaques.typeSymbol.info
1179+
val target = explicitInfo.firstParamTypes.head // required for extension method; the nominal receiver
1180+
.typeSymbol.typeRef.dealiasKeepOpaques
11841181
val member = target.nonPrivateMember(sym.name)
11851182
.filterWithPredicate: member =>
11861183
member.symbol.isPublic && memberHidesMethod(member)

tests/warn/i23666.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
type Tuple = scala.Tuple
3+
4+
infix type =:= [A, B] = A => B
5+
6+
object `=:=` :
7+
given [A] => A =:= A = a => a
8+
9+
extension [T <: Tuple] (tuple: T)
10+
11+
def reverse[A, B](using ev: T =:= (A, B)): (B, A) = // warn
12+
val ab = ev(tuple)
13+
(ab._2, ab._1)
14+
15+
def toList: List[Nothing] = Nil // warn

0 commit comments

Comments
 (0)