-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow prefix operators on the LHS of assignments #13328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5939849
6b04f15
614812b
1010692
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1886,6 +1886,7 @@ object Parsers { | |
* | `return' [Expr] | ||
* | ForExpr | ||
* | [SimpleExpr `.'] id `=' Expr | ||
* | PrefixOperator SimpleExpr `=' Expr | ||
* | SimpleExpr1 ArgumentExprs `=' Expr | ||
* | PostfixExpr [Ascription] | ||
* | ‘inline’ InfixExpr MatchClause | ||
|
@@ -2045,7 +2046,7 @@ object Parsers { | |
def expr1Rest(t: Tree, location: Location): Tree = in.token match | ||
case EQUALS => | ||
t match | ||
case Ident(_) | Select(_, _) | Apply(_, _) => | ||
case Ident(_) | Select(_, _) | Apply(_, _) | PrefixOp(_, _) => | ||
atSpan(startOffset(t), in.skipToken()) { | ||
val loc = if location.inArgs then location else Location.ElseWhere | ||
Assign(t, subPart(() => expr(loc))) | ||
|
@@ -2206,8 +2207,9 @@ object Parsers { | |
isOperator = !(location.inArgs && followingIsVararg()), | ||
maybePostfix = true) | ||
|
||
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr | ||
*/ | ||
/** PrefixExpr ::= [PrefixOperator'] SimpleExpr | ||
* PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
class Foo(var value: Int):
def `unary_+_=`(value: Int): Unit = this.value = +value
def `unary_-_=`(value: Int): Unit = this.value = -value
def `unary_~_=`(value: Int): Unit = this.value = ~value
end Foo
def test =
val x = Foo(9)
+x = 10 // error: value unary_+ is not a member of Foo - did you mean x.unary_+_=?
-x = 10 // error: value unary_- is not a member of Foo, but could be made available as an extension method.
~x = 10 // error: value unary_~ is not a member of Foo - did you mean x.unary_~_=? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's because Foo is missing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does that mean that we cannot write There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? Do we typecheck There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like that, yes. Using a setter |
||
*/ | ||
val prefixExpr: Location => Tree = location => | ||
if isIdent && nme.raw.isUnary(in.name) | ||
&& in.canStartExprTokens.contains(in.lookahead.token) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
class Ptr[T](var value: T): | ||
def `unary_!` : T = value | ||
def `unary_!_=`(value: T): Unit = this.value = value | ||
end Ptr | ||
|
||
def test = | ||
val x = Ptr(9) | ||
!x = 10 | ||
println(!x) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
final class Baz private (val x: Int) extends AnyVal { | ||
def `unary_!_=`() : Baz = ??? // parses ok, but will not be usable | ||
def `unary_~_=`() : Baz = ??? // parses ok, but will not be usable | ||
def `unary_+_=`() : Baz = ??? // parses ok, but will not be usable | ||
def `unary_-_=`() : Baz = ??? // parses ok, but will not be usable | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What must have happened in Scala 2: We had similar logic here, but we did not mark prefix operations specially; so a prefix operation was accepted since it was represented by a
Select
. Similarly for infix. The following expression is parsed in Scala 2, but will get a type error afterwards:In dotc you get instead a parse error:
That's because we represent infix operations as
Infix
nodes instead ofApply
nodes.