Skip to content

Commit bf5666f

Browse files
committed
Migration warning for non-unary symbolic operators
Under Scala-2 mode, issue a migration warning for a symbolic method that is not unary. Also: Two more tests updated to new infix operator regime.
1 parent c9e7d16 commit bf5666f

File tree

5 files changed

+33
-5
lines changed

5 files changed

+33
-5
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ object NameOps {
8787
}
8888
}
8989

90-
def isOpName = name match {
91-
case name: SimpleName => NameTransformer.encode(name) != name
90+
/** Is name an operator name that does not start with a letter or `_` or `$`? */
91+
def isSymbolic = name match {
92+
case name: SimpleName =>
93+
!Chars.isIdentifierStart(name.head) && NameTransformer.encode(name) != name
9294
case _ => false
9395
}
9496

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,29 @@ trait Checking {
850850
checkEnumCaseRefsLegal(stat, enumContext)
851851
stats
852852
}
853+
854+
/** `tp` refers to a method with exactly one parameter in its first parameter list.
855+
* If `tp` is overloaded, all alternatives are unary in that sense.
856+
*/
857+
def isUnary(tp: Type)(implicit ctx: Context): Boolean = tp match {
858+
case tp: MethodicType =>
859+
tp.firstParamTypes match {
860+
case ptype :: Nil => !ptype.isRepeatedParam
861+
case _ => false
862+
}
863+
case tp: TermRef =>
864+
tp.denot.alternatives.forall(alt => isUnary(alt.info))
865+
case _ =>
866+
false
867+
}
868+
869+
/** Under Scala-2 mode, issue a migration warning for a symbolic method that is
870+
* not unary.
871+
*/
872+
def checkSymbolicUnary(sym: Symbol)(implicit ctx: Context): Unit =
873+
if (sym.name.isSymbolic && !isUnary(sym.info) && ctx.scala2Mode)
874+
ctx.migrationWarning(i"""symbolic operator `${sym.name}` should take exactly one parameter,
875+
|otherwise it cannot be used in infix position.""", sym.pos)
853876
}
854877

855878
trait ReChecking extends Checking {
@@ -877,4 +900,5 @@ trait NoChecking extends ReChecking {
877900
override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context) = ()
878901
override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = ()
879902
override def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = tp
903+
override def checkSymbolicUnary(sym: Symbol)(implicit ctx: Context): Unit = ()
880904
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,8 @@ class Typer extends Namer
14341434
for (param <- tparams1 ::: vparamss1.flatten)
14351435
checkRefsLegal(param, sym.owner, (name, sym) => sym.is(TypeParam), "secondary constructor")
14361436

1437+
checkSymbolicUnary(sym)
1438+
14371439
assignType(cpy.DefDef(ddef)(name, tparams1, vparamss1, tpt1, rhs1), sym)
14381440
//todo: make sure dependent method types do not depend on implicits or by-name params
14391441
}

tests/pos/Map.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ object Map extends ImmutableMapFactory[Map] {
176176
else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4)
177177
else if (key == key3) new Map4(key1, value1, key2, value2, key3, value, key4, value4)
178178
else if (key == key4) new Map4(key1, value1, key2, value2, key3, value3, key4, value)
179-
else new HashMap + ((key1, value1), (key2, value2), (key3, value3), (key4, value4), (key, value))
179+
else HashMap((key1, value1), (key2, value2), (key3, value3), (key4, value4), (key, value))
180180
def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2)
181181
def - (key: A): Map[A, B] =
182182
if (key == key1) new Map3(key2, value2, key3, value3, key4, value4)

tests/run/iterators.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ object Test {
5757
def check_drop: Int = {
5858
val it1 = Iterator.from(0)
5959
val it2 = it1 map { 2 * _ }
60-
val n1 = it1 drop 2 next()
61-
val n2 = it2 drop 2 next();
60+
val n1 = (it1 drop 2) .next()
61+
val n2 = (it2 drop 2) .next();
6262
n1 + n2
6363
}
6464

0 commit comments

Comments
 (0)