Skip to content

Commit 5eff3d0

Browse files
authored
Merge pull request #13328 from dotty-staging/fix-13282
Allow prefix operators on the LHS of assignments
2 parents c0efe5f + 1010692 commit 5eff3d0

File tree

6 files changed

+38
-11
lines changed

6 files changed

+38
-11
lines changed

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -1886,6 +1886,7 @@ object Parsers {
18861886
* | `return' [Expr]
18871887
* | ForExpr
18881888
* | [SimpleExpr `.'] id `=' Expr
1889+
* | PrefixOperator SimpleExpr `=' Expr
18891890
* | SimpleExpr1 ArgumentExprs `=' Expr
18901891
* | PostfixExpr [Ascription]
18911892
* | ‘inline’ InfixExpr MatchClause
@@ -2045,7 +2046,7 @@ object Parsers {
20452046
def expr1Rest(t: Tree, location: Location): Tree = in.token match
20462047
case EQUALS =>
20472048
t match
2048-
case Ident(_) | Select(_, _) | Apply(_, _) =>
2049+
case Ident(_) | Select(_, _) | Apply(_, _) | PrefixOp(_, _) =>
20492050
atSpan(startOffset(t), in.skipToken()) {
20502051
val loc = if location.inArgs then location else Location.ElseWhere
20512052
Assign(t, subPart(() => expr(loc)))
@@ -2206,8 +2207,9 @@ object Parsers {
22062207
isOperator = !(location.inArgs && followingIsVararg()),
22072208
maybePostfix = true)
22082209

2209-
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
2210-
*/
2210+
/** PrefixExpr ::= [PrefixOperator'] SimpleExpr
2211+
* PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’
2212+
*/
22112213
val prefixExpr: Location => Tree = location =>
22122214
if isIdent && nme.raw.isUnary(in.name)
22132215
&& in.canStartExprTokens.contains(in.lookahead.token)

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ object RefChecks {
10391039
val what =
10401040
if tpe.paramNames.isEmpty then "empty parameter list.\n\nPossible fix: remove the `()` arguments."
10411041
else "parameters"
1042-
report.warning(s"Unary method cannot take $what", sym.sourcePos)
1042+
report.warning(s"unary_<op> method cannot take $what", sym.sourcePos)
10431043
case tpe: PolyType =>
10441044
checkParameters(tpe.resType)
10451045
case _ =>
@@ -1057,7 +1057,13 @@ object RefChecks {
10571057
case tpe: PolyType =>
10581058
checkExtensionParameters(tpe.resType)
10591059

1060-
if sym.name.startsWith(nme.UNARY_PREFIX.toString) then
1060+
def isUnaryPrefixName(name: Name) = name match
1061+
case name: SimpleName =>
1062+
name.startsWith("unary_") && nme.raw.isUnary(name.drop(6))
1063+
case _ =>
1064+
false
1065+
1066+
if isUnaryPrefixName(sym.name) then
10611067
if sym.is(Extension) || sym.name.is(ExtMethName) then
10621068
// if is method from `extension` or value class
10631069
checkExtensionParameters(sym.info)

docs/docs/internals/syntax.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
223223
| ‘return’ [Expr] Return(expr?)
224224
| ForExpr
225225
| [SimpleExpr ‘.’] id ‘=’ Expr Assign(expr, expr)
226-
| SimpleExpr1 ArgumentExprs ‘=’ Expr Assign(expr, expr)
226+
| PrefixOperator SimpleExpr ‘=’ Expr Assign(expr, expr)
227+
| SimpleExpr ArgumentExprs ‘=’ Expr Assign(expr, expr)
227228
| PostfixExpr [Ascription]
228229
| ‘inline’ InfixExpr MatchClause
229230
Ascription ::= ‘:’ InfixType Typed(expr, tp)
@@ -235,7 +236,8 @@ InfixExpr ::= PrefixExpr
235236
| InfixExpr id ‘:’ IndentedExpr
236237
| InfixExpr MatchClause
237238
MatchClause ::= ‘match’ <<< CaseClauses >>> Match(expr, cases)
238-
PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op)
239+
PrefixExpr ::= [PrefixOperator] SimpleExpr PrefixOp(expr, op)
240+
PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’
239241
SimpleExpr ::= SimpleRef
240242
| Literal
241243
| ‘_’
@@ -250,8 +252,8 @@ SimpleExpr ::= SimpleRef
250252
| SimpleExpr ‘.’ MatchClause
251253
| SimpleExpr TypeArgs TypeApply(expr, args)
252254
| SimpleExpr ArgumentExprs Apply(expr, args)
253-
| SimpleExpr1 ‘:’ IndentedExpr -- under language.experimental.fewerBraces
254-
| SimpleExpr1 FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces
255+
| SimpleExpr ‘:’ IndentedExpr -- under language.experimental.fewerBraces
256+
| SimpleExpr FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces
255257
| SimpleExpr ‘_’ PostfixOp(expr, _) (to be dropped)
256258
| XmlExpr -- to be dropped
257259
IndentedExpr ::= indent CaseClauses | Block outdent

docs/docs/reference/syntax.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
221221
| ‘return’ [Expr]
222222
| ForExpr
223223
| [SimpleExpr ‘.’] id ‘=’ Expr
224-
| SimpleExpr1 ArgumentExprs ‘=’ Expr
224+
| PrefixOperator SimpleExpr ‘=’ Expr
225+
| SimpleExpr ArgumentExprs ‘=’ Expr
225226
| PostfixExpr [Ascription]
226227
| ‘inline’ InfixExpr MatchClause
227228
Ascription ::= ‘:’ InfixType
@@ -232,7 +233,8 @@ InfixExpr ::= PrefixExpr
232233
| InfixExpr id [nl] InfixExpr
233234
| InfixExpr MatchClause
234235
MatchClause ::= ‘match’ <<< CaseClauses >>>
235-
PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr
236+
PrefixExpr ::= [PrefixOperator] SimpleExpr
237+
PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’
236238
SimpleExpr ::= SimpleRef
237239
| Literal
238240
| ‘_’

tests/pos/i13282.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Ptr[T](var value: T):
2+
def `unary_!` : T = value
3+
def `unary_!_=`(value: T): Unit = this.value = value
4+
end Ptr
5+
6+
def test =
7+
val x = Ptr(9)
8+
!x = 10
9+
println(!x)

tests/pos/unary-eq.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
final class Baz private (val x: Int) extends AnyVal {
2+
def `unary_!_=`() : Baz = ??? // parses ok, but will not be usable
3+
def `unary_~_=`() : Baz = ??? // parses ok, but will not be usable
4+
def `unary_+_=`() : Baz = ??? // parses ok, but will not be usable
5+
def `unary_-_=`() : Baz = ??? // parses ok, but will not be usable
6+
}

0 commit comments

Comments
 (0)