diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 399eabfff0f1..46e18195ce4a 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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 ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ + */ val prefixExpr: Location => Tree = location => if isIdent && nme.raw.isUnary(in.name) && in.canStartExprTokens.contains(in.lookahead.token) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 6e9d4caa7f6a..6ced45428eef 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1039,7 +1039,7 @@ object RefChecks { val what = if tpe.paramNames.isEmpty then "empty parameter list.\n\nPossible fix: remove the `()` arguments." else "parameters" - report.warning(s"Unary method cannot take $what", sym.sourcePos) + report.warning(s"unary_ method cannot take $what", sym.sourcePos) case tpe: PolyType => checkParameters(tpe.resType) case _ => @@ -1057,7 +1057,13 @@ object RefChecks { case tpe: PolyType => checkExtensionParameters(tpe.resType) - if sym.name.startsWith(nme.UNARY_PREFIX.toString) then + def isUnaryPrefixName(name: Name) = name match + case name: SimpleName => + name.startsWith("unary_") && nme.raw.isUnary(name.drop(6)) + case _ => + false + + if isUnaryPrefixName(sym.name) then if sym.is(Extension) || sym.name.is(ExtMethName) then // if is method from `extension` or value class checkExtensionParameters(sym.info) diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index f3f60dc50a13..1598e1199822 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -223,7 +223,8 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[ | ‘return’ [Expr] Return(expr?) | ForExpr | [SimpleExpr ‘.’] id ‘=’ Expr Assign(expr, expr) - | SimpleExpr1 ArgumentExprs ‘=’ Expr Assign(expr, expr) + | PrefixOperator SimpleExpr ‘=’ Expr Assign(expr, expr) + | SimpleExpr ArgumentExprs ‘=’ Expr Assign(expr, expr) | PostfixExpr [Ascription] | ‘inline’ InfixExpr MatchClause Ascription ::= ‘:’ InfixType Typed(expr, tp) @@ -235,7 +236,8 @@ InfixExpr ::= PrefixExpr | InfixExpr id ‘:’ IndentedExpr | InfixExpr MatchClause MatchClause ::= ‘match’ <<< CaseClauses >>> Match(expr, cases) -PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr PrefixOp(expr, op) +PrefixExpr ::= [PrefixOperator] SimpleExpr PrefixOp(expr, op) +PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ SimpleExpr ::= SimpleRef | Literal | ‘_’ @@ -250,8 +252,8 @@ SimpleExpr ::= SimpleRef | SimpleExpr ‘.’ MatchClause | SimpleExpr TypeArgs TypeApply(expr, args) | SimpleExpr ArgumentExprs Apply(expr, args) - | SimpleExpr1 ‘:’ IndentedExpr -- under language.experimental.fewerBraces - | SimpleExpr1 FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces + | SimpleExpr ‘:’ IndentedExpr -- under language.experimental.fewerBraces + | SimpleExpr FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces | SimpleExpr ‘_’ PostfixOp(expr, _) (to be dropped) | XmlExpr -- to be dropped IndentedExpr ::= indent CaseClauses | Block outdent diff --git a/docs/docs/reference/syntax.md b/docs/docs/reference/syntax.md index ecb44ef35b2e..5964fa47da12 100644 --- a/docs/docs/reference/syntax.md +++ b/docs/docs/reference/syntax.md @@ -221,7 +221,8 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[ | ‘return’ [Expr] | ForExpr | [SimpleExpr ‘.’] id ‘=’ Expr - | SimpleExpr1 ArgumentExprs ‘=’ Expr + | PrefixOperator SimpleExpr ‘=’ Expr + | SimpleExpr ArgumentExprs ‘=’ Expr | PostfixExpr [Ascription] | ‘inline’ InfixExpr MatchClause Ascription ::= ‘:’ InfixType @@ -232,7 +233,8 @@ InfixExpr ::= PrefixExpr | InfixExpr id [nl] InfixExpr | InfixExpr MatchClause MatchClause ::= ‘match’ <<< CaseClauses >>> -PrefixExpr ::= [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr +PrefixExpr ::= [PrefixOperator] SimpleExpr +PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ SimpleExpr ::= SimpleRef | Literal | ‘_’ diff --git a/tests/pos/i13282.scala b/tests/pos/i13282.scala new file mode 100644 index 000000000000..2241fdc17941 --- /dev/null +++ b/tests/pos/i13282.scala @@ -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) diff --git a/tests/pos/unary-eq.scala b/tests/pos/unary-eq.scala new file mode 100644 index 000000000000..9e9d871a0912 --- /dev/null +++ b/tests/pos/unary-eq.scala @@ -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 +}