Skip to content

Commit e8e3635

Browse files
committed
Check validity of infix operations
1 parent 40c143e commit e8e3635

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._
@@ -664,6 +667,24 @@ trait Checking {
664667
i"Use of implicit conversion ${conv.showLocated}", NoSymbol, posd.sourcePos)
665668
}
666669

670+
/** Check that `tree` is a valid infix operation. That is, if the
671+
* operator is alphanumeric, it must be declared `@infix`.
672+
*/
673+
def checkValidInfix(tree: untpd.InfixOp, app: Tree)(implicit ctx: Context): Unit =
674+
tree.op match {
675+
case Ident(name: SimpleName)
676+
if !name.exists(isOperatorPart) && !app.symbol.hasAnnotation(defn.InfixAnnot) && false =>
677+
ctx.deprecationWarning(
678+
i"""alphanumeric method $name is not declared @infix; should not be used as infix operator.
679+
|The operation can be rewritten automatically under -migration -rewrite""",
680+
tree.op.sourcePos)
681+
if (ctx.scala2Mode) {
682+
patch(Span(tree.op.span.start, tree.op.span.start), "`")
683+
patch(Span(tree.op.span.end, tree.op.span.end), "`")
684+
}
685+
case _ =>
686+
}
687+
667688
/** Issue a feature warning if feature is not enabled */
668689
def checkFeature(name: TermName,
669690
description: => String,
@@ -1053,5 +1074,6 @@ trait NoChecking extends ReChecking {
10531074
override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = ()
10541075
override def checkMembersOK(tp: Type, pos: SourcePosition)(implicit ctx: Context): Type = tp
10551076
override def checkInInlineContext(what: String, posd: Positioned)(implicit ctx: Context): Unit = ()
1077+
override def checkValidInfix(tree: untpd.InfixOp, app: Tree)(implicit ctx: Context): Unit = ()
10561078
override def checkFeature(name: TermName, description: => String, featureUseSite: Symbol, pos: SourcePosition)(implicit ctx: Context): Unit = ()
10571079
}

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

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

0 commit comments

Comments
 (0)