diff --git a/compiler/parser.go b/compiler/parser.go index 51bf534f6..20f8a873b 100644 --- a/compiler/parser.go +++ b/compiler/parser.go @@ -9,6 +9,7 @@ package compiler import ( "errors" "fmt" + "strings" "unicode" "unicode/utf8" @@ -589,10 +590,7 @@ LABEL: if cond != nil { condition, _ = cond.(ast.Expression) if condition == nil { - if a, ok := cond.(*ast.Assignment); ok && a.Type == ast.AssignmentSimple { - panic(syntaxError(tok.pos, "assignment %s used as value", init)) - } - panic(syntaxError(tok.pos, "%s used as value", init)) + panic(cannotUseAsValueError(pos, init)) } } var post ast.Node @@ -611,10 +609,7 @@ LABEL: if init != nil { condition, _ = init.(ast.Expression) if condition == nil { - if a, ok := init.(*ast.Assignment); ok && a.Type == ast.AssignmentSimple { - panic(syntaxError(tok.pos, "assignment %s used as value", init)) - } - panic(syntaxError(tok.pos, "%s used as value", init)) + panic(cannotUseAsValueError(pos, init)) } } pos.End = tok.pos.End @@ -892,10 +887,7 @@ LABEL: } else if init != nil { expr, _ = init.(ast.Expression) if expr == nil { - if a, ok := init.(*ast.Assignment); ok && a.Type == ast.AssignmentSimple { - panic(syntaxError(tok.pos, "assignment %s used as value", init)) - } - panic(syntaxError(tok.pos, "%s used as value", init)) + panic(cannotUseAsValueError(pos, init)) } init = nil } @@ -1696,6 +1688,28 @@ func (p *parsing) parseAssignment(variables []ast.Expression, tok token, canBeRa return node, tok } +// cannotUseAsValueError returns a syntax error returned when node is used as +// value at position pos. +func cannotUseAsValueError(pos *ast.Position, node ast.Node) *SyntaxError { + if a, ok := node.(*ast.Assignment); ok && a.Type == ast.AssignmentSimple { + return syntaxError(pos, "cannot use assignment (%s) = (%s) as value", + printExpressions(a.Lhs), printExpressions(a.Rhs)) + } + panic(syntaxError(pos, "cannot use %s as value", node)) +} + +// printExpressions prints expressions as a comma separated list. +func printExpressions(expressions []ast.Expression) string { + var b strings.Builder + for i, e := range expressions { + if i > 0 { + b.WriteString(", ") + } + b.WriteString(e.String()) + } + return b.String() +} + // addNode adds a node to the tree. It adds the node as a child to the current // parent node and sets the node as new ancestor if necessary. func (p *parsing) addNode(node ast.Node) { diff --git a/compiler/parser_switch.go b/compiler/parser_switch.go index 68a5091e5..c6c3920ef 100644 --- a/compiler/parser_switch.go +++ b/compiler/parser_switch.go @@ -129,14 +129,8 @@ func (p *parsing) parseSwitch(tok token, end tokenTyp) ast.Node { // TODO (Gianluca): should error contain the position of the // expression which caused the error instead of the token (as Go // does)? - if !ok { - panic(syntaxError(tok.pos, "assignment %s used as value", assignment)) - } - if ta.Type != nil { - panic(syntaxError(tok.pos, "%s used as value", assignment)) - } - if len(assignment.Lhs) != 1 { - panic(syntaxError(tok.pos, "%s used as value", assignment)) + if !ok || ta.Type != nil || len(assignment.Lhs) != 1 { + panic(cannotUseAsValueError(tok.pos, assignment)) } afterSemicolon = assignment } else { @@ -160,15 +154,9 @@ func (p *parsing) parseSwitch(tok token, end tokenTyp) ast.Node { if len(assignment.Rhs) != 1 { panic(syntaxError(tok.pos, "unexpected %s, expecting expression", want)) } - if len(assignment.Lhs) != 1 { - panic(syntaxError(tok.pos, "%s used as value", assignment)) - } ta, ok := assignment.Rhs[0].(*ast.TypeAssertion) - if !ok { - panic(syntaxError(tok.pos, "assignment %s used as value", assignment)) - } - if ta.Type != nil { - panic(syntaxError(tok.pos, "%s used as value", assignment)) + if !ok || ta.Type != nil || len(assignment.Lhs) != 1 { + panic(cannotUseAsValueError(tok.pos, assignment)) } afterSemicolon = assignment } diff --git a/test/compare/testdata/misc/switch2.go b/test/compare/testdata/misc/switch2.go index 3143b58c4..f67f74738 100755 --- a/test/compare/testdata/misc/switch2.go +++ b/test/compare/testdata/misc/switch2.go @@ -21,6 +21,8 @@ func main() { switch 5 { case 'a': } switch 'a' { case 5: } switch 5.4 { case 2i: } // ERROR `constant 2i truncated to real` + switch a = 1 { case true: } // ERROR `cannot use assignment (a) = (1) as value` + switch a := 1 { case true: } // ERROR `cannot use a := 1 as value` switch 1 < 2 { case true: } switch a < "b" { case true: } switch a { case "b": } diff --git a/test/compare/testdata/syntax/for_statement.go b/test/compare/testdata/syntax/for_statement.go index db29ed8a3..a0cd5d26b 100644 --- a/test/compare/testdata/syntax/for_statement.go +++ b/test/compare/testdata/syntax/for_statement.go @@ -22,7 +22,8 @@ func main() { for ; {} // ERROR `syntax error: unexpected {, expecting for loop condition` for ; true {} // ERROR `syntax error: unexpected {, expecting semicolon or newline` for ; ; { break } - for a := 5 {} // ERROR `syntax error: a := 5 used as value` + for a = 5 {} // ERROR `syntax error: cannot use assignment (a) = (5) as value` + for a := 5 {} // ERROR `syntax error: cannot use a := 5 as value` for a := 5; {} // ERROR `syntax error: unexpected {, expecting for loop condition` for a := 5; true {} // ERROR `syntax error: unexpected {, expecting semicolon or newline` for a := false; a; {} diff --git a/test/compare/testdata/syntax/if_statement.go b/test/compare/testdata/syntax/if_statement.go index 8343bbcb4..01911e94e 100644 --- a/test/compare/testdata/syntax/if_statement.go +++ b/test/compare/testdata/syntax/if_statement.go @@ -44,12 +44,13 @@ func main() { if f() {} if <-ch {} // ERROR `non-bool <-ch (type int) used as if condition` if <-chb {} - if ch <- 3 {} // ERROR `ch <- 3 used as value` - if i++ for {} // ERROR `syntax error: i++ used as value` - if i++ {} // ERROR `syntax error: i++ used as value` - if i-- {} // ERROR `syntax error: i-- used as value` - if i = 3 {} // ERROR `syntax error: assignment i = 3 used as value` - if i := 3 { _ = i } // ERROR `syntax error: i := 3 used as value` + if ch <- 3 {} // ERROR `cannot use ch <- 3 as value` + if i++ for {} // ERROR `syntax error: cannot use i++ as value` + if i++ {} // ERROR `syntax error: cannot use i++ as value` + if i-- {} // ERROR `syntax error: cannot use i-- as value` + if i = 3 {} // ERROR `syntax error: cannot use assignment (i) = (3) as value` + if a, b = 3, 6 {} // ERROR `syntax error: cannot use assignment (a, b) = (3, 6) as value` + if i := 3 { _ = i } // ERROR `syntax error: cannot use i := 3 as value` if print(); {} // ERROR `syntax error: missing condition in if statement` if <-ch; {} // ERROR `syntax error: missing condition in if statement` if ch <- 3; {} // ERROR `syntax error: missing condition in if statement`