Skip to content

Commit c340b97

Browse files
committed
Check validity of infix operations
1 parent 8f2ff19 commit c340b97

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@ import CheckRealizable._
1818
import ErrorReporting.errorTree
1919

2020
import util.SourcePosition
21+
import util.Spans.Span
22+
import rewrites.Rewrites.patch
2123
import transform.SymUtils._
24+
import transform.ValueClasses._
2225
import Decorators._
2326
import ErrorReporting.{err, errorType}
2427
import config.Printers.typr
2528
import NameKinds.DefaultGetterName
29+
import SymDenotations.{NoCompleter, NoDenotation}
2630

2731
import collection.mutable
28-
import SymDenotations.{NoCompleter, NoDenotation}
29-
import dotty.tools.dotc.reporting.diagnostic.Message
30-
import dotty.tools.dotc.reporting.diagnostic.messages._
31-
import dotty.tools.dotc.transform.ValueClasses._
32+
import reporting.diagnostic.Message
33+
import reporting.diagnostic.messages._
34+
import scala.tasty.util.Chars.isOperatorPart
3235

3336
object Checking {
3437
import tpd._
@@ -657,6 +660,24 @@ trait Checking {
657660
i"Use of implicit conversion ${conv.showLocated}", NoSymbol, posd.sourcePos)
658661
}
659662

663+
/** Check that `tree` is a valid infix operation. That is, if the
664+
* operator is alphanumeric, it must be declared `@infix`.
665+
*/
666+
def checkValidInfix(tree: untpd.InfixOp, app: Tree)(implicit ctx: Context): Unit =
667+
tree.op match {
668+
case Ident(name: SimpleName)
669+
if !name.exists(isOperatorPart) && !app.symbol.hasAnnotation(defn.InfixAnnot) && false =>
670+
ctx.deprecationWarning(
671+
i"""alphanumeric method $name is not declared @infix; should not be used as infix operator.
672+
|The operation can be rewritten automatically under -migration -rewrite""",
673+
tree.op.sourcePos)
674+
if (ctx.scala2Mode) {
675+
patch(Span(tree.op.span.start, tree.op.span.start), "`")
676+
patch(Span(tree.op.span.end, tree.op.span.end), "`")
677+
}
678+
case _ =>
679+
}
680+
660681
/** Issue a feature warning if feature is not enabled */
661682
def checkFeature(base: ClassSymbol,
662683
name: TermName,
@@ -1034,5 +1055,6 @@ trait NoChecking extends ReChecking {
10341055
override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = ()
10351056
override def checkMembersOK(tp: Type, pos: SourcePosition)(implicit ctx: Context): Type = tp
10361057
override def checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = ()
1058+
override def checkValidInfix(tree: untpd.InfixOp, app: Tree)(implicit ctx: Context): Unit = ()
10371059
override def checkFeature(base: ClassSymbol, name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = ()
10381060
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,7 @@ class Typer extends Namer
18831883
def typedInfixOp(tree: untpd.InfixOp, pt: Type)(implicit ctx: Context): Tree = {
18841884
val untpd.InfixOp(l, op, r) = tree
18851885
val app = typedApply(desugar.binop(l, op, r), pt)
1886+
checkValidInfix(tree, app)
18861887
if (untpd.isLeftAssoc(op.name)) app
18871888
else {
18881889
val defs = new mutable.ListBuffer[Tree]

0 commit comments

Comments
 (0)