Skip to content

Commit 931b350

Browse files
committed
Imply @infix annotation for dotless extension methods
If an alphanumeric extension method is defined without a `.`, add an @infix annotation.
1 parent 1681e2d commit 931b350

File tree

4 files changed

+32
-11
lines changed

4 files changed

+32
-11
lines changed

compiler/src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ object NameOps {
7373
def isAnonymousFunctionName: Boolean = name.startsWith(str.ANON_FUN)
7474
def isUnapplyName: Boolean = name == nme.unapply || name == nme.unapplySeq
7575

76+
def isOperatorName: Boolean = name match
77+
case name: SimpleName => name.exists(isOperatorPart)
78+
case _ => false
79+
7680
/** Is name a variable name? */
7781
def isVariableName: Boolean = testSimple { n =>
7882
n.length > 0 && {

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3197,24 +3197,32 @@ object Parsers {
31973197
makeConstructor(Nil, vparamss, rhs).withMods(mods).setComment(in.getDocComment(start))
31983198
}
31993199
else {
3200+
var mods1 = addFlag(mods, Method)
3201+
var isInfix = false
32003202
def extParamss() =
32013203
try paramClause(0, prefix = true) :: Nil
32023204
finally
3205+
mods1 = addFlag(mods, Extension)
32033206
if in.token == DOT then in.nextToken()
3204-
else newLineOpt()
3205-
val (leadingTparams, leadingVparamss, flags) =
3207+
else
3208+
isInfix = true
3209+
newLineOpt()
3210+
val (leadingTparams, leadingVparamss) =
32063211
if in.token == LBRACKET then
3207-
(typeParamClause(ParamOwner.Def), extParamss(), Method | Extension)
3212+
(typeParamClause(ParamOwner.Def), extParamss())
32083213
else if in.token == LPAREN then
3209-
(Nil, extParamss(), Method | Extension)
3214+
(Nil, extParamss())
32103215
else
3211-
(Nil, Nil, Method)
3212-
val mods1 = addFlag(mods, flags)
3216+
(Nil, Nil)
32133217
val ident = termIdent()
32143218
val name = ident.name.asTermName
3219+
if isInfix && !name.isOperatorName then
3220+
val infixAnnot = Apply(wrapNew(ref(defn.InfixAnnot.typeRef)), Nil)
3221+
.withSpan(Span(start, start))
3222+
mods1 = mods1.withAddedAnnotation(infixAnnot)
32153223
val tparams =
32163224
if in.token == LBRACKET then
3217-
if flags.is(Extension) then
3225+
if mods1.is(Extension) then
32183226
if leadingTparams.isEmpty then
32193227
deprecationWarning("type parameters in extension methods should be written after `def`")
32203228
else

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ object Checking {
277277
def checkValidOperator(sym: Symbol)(implicit ctx: Context): Unit =
278278
sym.name.toTermName match {
279279
case name: SimpleName
280-
if name.exists(isOperatorPart)
280+
if name.isOperatorName
281281
&& !name.isSetterName
282282
&& !name.isConstructorName
283283
&& !sym.getAnnotation(defn.AlphaAnnot).isDefined
@@ -754,7 +754,7 @@ trait Checking {
754754
name.toTermName match {
755755
case name: SimpleName
756756
if !untpd.isBackquoted(id) &&
757-
!name.exists(isOperatorPart) &&
757+
!name.isOperatorName &&
758758
!isInfix(meth) &&
759759
!meth.maybeOwner.is(Scala2x) &&
760760
!infixOKSinceFollowedBy(tree.right) &&

tests/neg-custom-args/infix.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
// Compile with -strict -Xfatal-warnings -deprecation
22
import scala.annotation.infix
3-
class C {
3+
class C:
44
@infix def op(x: Int): Int = ???
55
def meth(x: Int): Int = ???
66
def matching(x: Int => Int) = ???
77
def +(x: Int): Int = ???
8-
}
8+
9+
object C:
10+
given AnyRef:
11+
def (x: C) iop (y: Int) = ???
12+
def (x: C).mop (y: Int) = ???
13+
def (x: C) ++ (y: Int) = ???
914

1015
val c = C()
1116
def test() = {
1217
c op 2
18+
c iop 2
1319
c.meth(2)
20+
c ++ 2
1421

1522
c.op(2)
23+
c.iop(2)
24+
c mop 2 // error: should not be used as infix operator
1625
c meth 2 // error: should not be used as infix operator
1726
c `meth` 2 // OK, sincd `meth` is backquoted
1827
c + 3 // OK, since `+` is symbolic

0 commit comments

Comments
 (0)