defer un(trace(p, "ExpressionList"))
}
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
for p.tok == token.COMMA {
p.next()
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
}
return
lparen := p.pos
p.next()
p.exprLev++
- x := p.parseRhs()
+ x := p.parseRhsOrType() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
return &ast.ParenExpr{lparen, x, rparen}
var list []ast.Expr
var ellipsis token.Pos
for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
- list = append(list, p.parseRhs())
+ list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...)
if p.tok == token.ELLIPSIS {
ellipsis = p.pos
p.next()
return p.parseLiteralValue(nil)
}
- x := p.parseExpr(keyOk) // don't resolve if map key
+ x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key
if keyOk {
if p.tok == token.COLON {
colon := p.pos
case *ast.IndexExpr:
case *ast.SliceExpr:
case *ast.TypeAssertExpr:
- if t.Type == nil {
- // the form X.(type) is only allowed in type switch expressions
- p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos(), x.End()}
- }
+ // 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:
}
// If lhs is set and the result is an identifier, it is not resolved.
-// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
-// should reject when a type/raw type is obviously not allowed
+// The result may be a type or even a raw type ([...]int). Callers must
+// check the result (using checkExpr or checkExprOrType), depending on
+// context.
func (p *parser) parseExpr(lhs bool) ast.Expr {
if p.trace {
defer un(trace(p, "Expression"))
}
func (p *parser) parseRhs() ast.Expr {
- return p.parseExpr(false)
+ return p.checkExpr(p.parseExpr(false))
+}
+
+func (p *parser) parseRhsOrType() ast.Expr {
+ return p.checkExprOrType(p.parseExpr(false))
}
// ----------------------------------------------------------------------------
}
func (p *parser) parseCallExpr() *ast.CallExpr {
- x := p.parseRhs()
+ x := p.parseRhsOrType() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
}
}
- // TODO(gri): store p.imports in AST
return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
}
`package p; func f() { if ; /* should have condition */ {} };`,
`package p; func f() { if f(); /* should have condition */ {} };`,
`package p; const c; /* should have constant value */`,
+ `package p; var a = [1]int; /* illegal expression */`,
+ `package p; var a = [...]int; /* illegal expression */`,
+ `package p; var a = struct{} /* illegal expression */`,
+ `package p; var a = func(); /* illegal expression */`,
+ `package p; var a = interface{} /* illegal expression */`,
+ `package p; var a = []int /* illegal expression */`,
+ `package p; var a = map[int]int /* illegal expression */`,
+ `package p; var a = chan int; /* illegal expression */`,
+ `package p; var a = []int{[]int}; /* illegal expression */`,
+ `package p; var a = ([]int); /* illegal expression */`,
+ `package p; var a = a[[]int:[]int]; /* illegal expression */`,
+ `package p; var a = <- chan int; /* illegal expression */`,
+ `package p; func f() { select { case _ <- chan int: } };`,
}
func TestParseIllegalInputs(t *testing.T) {