defer un(trace(p, "ExpressionList"))
}
- list = append(list, p.checkExpr(p.parseExpr()))
+ list = append(list, p.parseExpr())
for p.tok == token.COMMA {
p.next()
- list = append(list, p.checkExpr(p.parseExpr()))
+ list = append(list, p.parseExpr())
}
return
var args []ast.Expr
if p.tok != token.RBRACK {
p.exprLev++
- args = append(args, p.parseRhsOrType())
+ args = append(args, p.parseRhs())
for p.tok == token.COMMA {
p.next()
- args = append(args, p.parseRhsOrType())
+ args = append(args, p.parseRhs())
}
p.exprLev--
}
lparen := p.pos
p.next()
p.exprLev++
- x := p.parseRhsOrType() // types may be parenthesized: (some type)
+ x := p.parseRhs() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
return &ast.ParenExpr{Lparen: lparen, X: x, Rparen: rparen}
if p.tok != token.COLON {
// We can't know if we have an index expression or a type instantiation;
// so even if we see a (named) type we are not going to be in type context.
- index[0] = p.parseRhsOrType()
+ index[0] = p.parseRhs()
}
ncolons := 0
switch p.tok {
var list []ast.Expr
var ellipsis token.Pos
for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
- list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...)
+ list = append(list, p.parseRhs()) // builtins may expect a type: make(some type, ...)
if p.tok == token.ELLIPSIS {
ellipsis = p.pos
p.next()
return p.parseLiteralValue(nil)
}
- x := p.checkExpr(p.parseExpr())
+ x := p.parseExpr()
return x
}
return &ast.CompositeLit{Type: typ, Lbrace: lbrace, Elts: elts, Rbrace: rbrace}
}
-// checkExpr checks that x is an expression (and not a type).
-func (p *parser) checkExpr(x ast.Expr) ast.Expr {
- switch unparen(x).(type) {
- case *ast.BadExpr:
- case *ast.Ident:
- case *ast.BasicLit:
- case *ast.FuncLit:
- case *ast.CompositeLit:
- case *ast.ParenExpr:
- panic("unreachable")
- case *ast.SelectorExpr:
- case *ast.IndexExpr:
- case *ast.IndexListExpr:
- case *ast.SliceExpr:
- case *ast.TypeAssertExpr:
- // If t.Type == nil we have a type assertion of the form
- // y.(type), which is only allowed in type switch expressions.
- // It's hard to exclude those but for the case where we are in
- // a type switch. Instead be lenient and test this in the type
- // checker.
- case *ast.CallExpr:
- case *ast.StarExpr:
- case *ast.UnaryExpr:
- case *ast.BinaryExpr:
- default:
- // all other nodes are not proper expressions
- p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
- }
- return x
-}
-
// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
func unparen(x ast.Expr) ast.Expr {
if p, isParen := x.(*ast.ParenExpr); isParen {
return x
}
-// checkExprOrType checks that x is an expression or a type
-// (and not a raw type such as [...]T).
-func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
- switch t := unparen(x).(type) {
- case *ast.ParenExpr:
- panic("unreachable")
- case *ast.ArrayType:
- if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
- p.error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
- }
- }
-
- // all other nodes are expressions or types
- return x
-}
-
func (p *parser) parsePrimaryExpr(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "PrimaryExpr"))
p.next()
switch p.tok {
case token.IDENT:
- x = p.parseSelector(p.checkExprOrType(x))
+ x = p.parseSelector(x)
case token.LPAREN:
- x = p.parseTypeAssertion(p.checkExpr(x))
+ x = p.parseTypeAssertion(x)
default:
pos := p.pos
p.errorExpected(pos, "selector or type assertion")
x = &ast.SelectorExpr{X: x, Sel: sel}
}
case token.LBRACK:
- x = p.parseIndexOrSliceOrInstance(p.checkExpr(x))
+ x = p.parseIndexOrSliceOrInstance(x)
case token.LPAREN:
- x = p.parseCallOrConversion(p.checkExprOrType(x))
+ x = p.parseCallOrConversion(x)
case token.LBRACE:
// operand may have returned a parenthesized complit
// type; accept it but complain if we have a complit
pos, op := p.pos, p.tok
p.next()
x := p.parseUnaryExpr()
- return &ast.UnaryExpr{OpPos: pos, Op: op, X: p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: pos, Op: op, X: x}
case token.ARROW:
// channel type or receive expression
}
// <-(expr)
- return &ast.UnaryExpr{OpPos: arrow, Op: token.ARROW, X: p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: arrow, Op: token.ARROW, X: x}
case token.MUL:
// pointer type or unary "*" expression
pos := p.pos
p.next()
x := p.parseUnaryExpr()
- return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
+ return &ast.StarExpr{Star: pos, X: x}
}
return p.parsePrimaryExpr(nil)
// parseBinaryExpr parses a (possibly) binary expression.
// If x is non-nil, it is used as the left operand.
-// If check is true, operands are checked to be valid expressions.
//
// TODO(rfindley): parseBinaryExpr has become overloaded. Consider refactoring.
-func (p *parser) parseBinaryExpr(x ast.Expr, prec1 int, check bool) ast.Expr {
+func (p *parser) parseBinaryExpr(x ast.Expr, prec1 int) ast.Expr {
if p.trace {
defer un(trace(p, "BinaryExpr"))
}
return x
}
pos := p.expect(op)
- y := p.parseBinaryExpr(nil, oprec+1, check)
- if check {
- x = p.checkExpr(x)
- y = p.checkExpr(y)
- }
+ y := p.parseBinaryExpr(nil, oprec+1)
x = &ast.BinaryExpr{X: x, OpPos: pos, Op: op, Y: y}
}
}
-// The result may be a type or even a raw type ([...]int). Callers must
-// check the result (using checkExpr or checkExprOrType), depending on
-// context.
+// The result may be a type or even a raw type ([...]int).
func (p *parser) parseExpr() ast.Expr {
if p.trace {
defer un(trace(p, "Expression"))
}
- return p.parseBinaryExpr(nil, token.LowestPrec+1, true)
+ return p.parseBinaryExpr(nil, token.LowestPrec+1)
}
func (p *parser) parseRhs() ast.Expr {
old := p.inRhs
p.inRhs = true
- x := p.checkExpr(p.parseExpr())
- p.inRhs = old
- return x
-}
-
-func (p *parser) parseRhsOrType() ast.Expr {
- old := p.inRhs
- p.inRhs = true
- x := p.checkExprOrType(p.parseExpr())
+ x := p.parseExpr()
p.inRhs = old
return x
}
}
func (p *parser) parseCallExpr(callType string) *ast.CallExpr {
- x := p.parseRhsOrType() // could be a conversion: (some type)(x)
+ x := p.parseRhs() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
return nil
}
if es, isExpr := s.(*ast.ExprStmt); isExpr {
- return p.checkExpr(es.X)
+ return es.X
}
found := "simple statement"
if _, isAss := s.(*ast.AssignStmt); isAss {
return &ast.IfStmt{If: pos, Init: init, Cond: cond, Body: body, Else: else_}
}
-func (p *parser) parseTypeList() (list []ast.Expr) {
- if p.trace {
- defer un(trace(p, "TypeList"))
- }
-
- list = append(list, p.parseType())
- for p.tok == token.COMMA {
- p.next()
- list = append(list, p.parseType())
- }
-
- return
-}
-
-func (p *parser) parseCaseClause(typeSwitch bool) *ast.CaseClause {
+func (p *parser) parseCaseClause() *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
}
var list []ast.Expr
if p.tok == token.CASE {
p.next()
- if typeSwitch {
- list = p.parseTypeList()
- } else {
- list = p.parseList(true)
- }
+ list = p.parseList(true)
} else {
p.expect(token.DEFAULT)
}
lbrace := p.expect(token.LBRACE)
var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT {
- list = append(list, p.parseCaseClause(typeSwitch))
+ list = append(list, p.parseCaseClause())
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
// to parser.expr, and pass in name to parsePrimaryExpr.
p.exprLev++
lhs := p.parsePrimaryExpr(x)
- x = p.parseBinaryExpr(lhs, token.LowestPrec+1, false)
+ x = p.parseBinaryExpr(lhs, token.LowestPrec+1)
p.exprLev--
}
// Analyze expression x. If we can split x into a type parameter
`package p; func f() { switch t = /* ERROR "expected ':=', found '='" */ t.(type) {} };`,
`package p; func f() { switch t /* ERROR "expected switch expression" */ , t = t.(type) {} };`,
`package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type), t {} };`,
- `package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
- `package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
- `package p; var a = struct /* ERROR "expected expression" */ {}`,
- `package p; var a = func /* ERROR "expected expression" */ ();`,
- `package p; var a = interface /* ERROR "expected expression" */ {}`,
- `package p; var a = [ /* ERROR "expected expression" */ ]int`,
- `package p; var a = map /* ERROR "expected expression" */ [int]int`,
- `package p; var a = chan /* ERROR "expected expression" */ int;`,
- `package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
- `package p; var a = ( /* ERROR "expected expression" */ []int);`,
- `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
- `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
`package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan<- /* ERROR "expected channel type" */ int)(nil) };`,
`package p; func f() { var t []int; t /* ERROR "expected identifier on left side of :=" */ [0] := 0 };`,
`package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ int) }`,
`package p; type _ struct{ *( /* ERROR "cannot parenthesize embedded type" */ []byte) }`,
- // TODO(rfindley): this error should be positioned on the ':'
- `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`,
-
- // TODO(rfindley): the compiler error is better here: "cannot parenthesize embedded type"
- // TODO(rfindley): confirm that parenthesized types should now be accepted.
- // `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`,
-
// issue 8656
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,