1
0
mirror of https://github.com/golang/go synced 2024-11-25 03:37:58 -07:00

undo CL 4896053 / c62cf48b7dc4: fix build

The subtle AST changes introduced with CL 4896053
broke type checking of type switches in gofix.
Coming up with a correct fix will take some time.
Undoing this change for now.

««« original CL description
go/parser: fix type switch scoping

The variable declared by a TypeSwitchGuard must be
visible in each TypeCaseClause and must not conflict
with other variables declared by the initial SimpleStmt
of a type switch.

Also:
- explicitly detect type switches (as opposed to detecting
  regular (expression switches) and then do extra testing
  for type switches
- fix all outstanding TODOs in parser.go

R=rsc
CC=golang-dev
https://golang.org/cl/4896053
»»»

R=rsc
CC=golang-dev
https://golang.org/cl/4902052
This commit is contained in:
Robert Griesemer 2011-08-18 11:42:19 -07:00
parent 18248ced36
commit 8843262599
3 changed files with 28 additions and 82 deletions

View File

@ -4,20 +4,3 @@ func _() {
// the scope of a local type declaration starts immediately after the type name // the scope of a local type declaration starts immediately after the type name
type T struct{ _ *T } type T struct{ _ *T }
} }
func _(x interface{}) {
// the variable defined by a TypeSwitchGuard is declared in each TypeCaseClause
switch t := x.(type) {
case int:
_ = t
case float32:
_ = t
default:
_ = t
}
// the variable defined by a TypeSwitchGuard must not conflict with other
// variables declared in the initial simple statement
switch t := 0; t := x.(type) {
}
}

View File

@ -587,6 +587,7 @@ func (p *parser) parseStructType() *ast.StructType {
} }
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
// TODO(gri): store struct scope in AST
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false} return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
} }
@ -799,6 +800,7 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
} }
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
// TODO(gri): store interface scope in AST
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false} return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
} }
@ -1434,14 +1436,14 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
case token.ARROW: case token.ARROW:
// send statement // send statement
arrow := p.pos arrow := p.pos
p.next() p.next() // consume "<-"
y := p.parseRhs() y := p.parseRhs()
return &ast.SendStmt{x[0], arrow, y}, false return &ast.SendStmt{x[0], arrow, y}, false
case token.INC, token.DEC: case token.INC, token.DEC:
// increment or decrement // increment or decrement
s := &ast.IncDecStmt{x[0], p.pos, p.tok} s := &ast.IncDecStmt{x[0], p.pos, p.tok}
p.next() p.next() // consume "++" or "--"
return s, false return s, false
} }
@ -1589,7 +1591,7 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return return
} }
func (p *parser) parseCaseClause(varName string) *ast.CaseClause { func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.trace { if p.trace {
defer un(trace(p, "CaseClause")) defer un(trace(p, "CaseClause"))
} }
@ -1598,12 +1600,10 @@ func (p *parser) parseCaseClause(varName string) *ast.CaseClause {
var list []ast.Expr var list []ast.Expr
if p.tok == token.CASE { if p.tok == token.CASE {
p.next() p.next()
if varName != "" { if exprSwitch {
// type switch
list = p.parseTypeList()
} else {
// expression switch
list = p.parseRhsList() list = p.parseRhsList()
} else {
list = p.parseTypeList()
} }
} else { } else {
p.expect(token.DEFAULT) p.expect(token.DEFAULT)
@ -1611,31 +1611,21 @@ func (p *parser) parseCaseClause(varName string) *ast.CaseClause {
colon := p.expect(token.COLON) colon := p.expect(token.COLON)
p.openScope() p.openScope()
// If we have a type switch declaring a variable in its TypeSwitchGuard,
// declare that variable in each of the TypeCaseClauses.
if varName != "" && varName != "_" {
ident := &ast.Ident{Name: varName} // dummy identifier
p.declare(nil, nil, p.topScope, ast.Var, ident)
}
body := p.parseStmtList() body := p.parseStmtList()
p.closeScope() p.closeScope()
return &ast.CaseClause{pos, list, colon, body} return &ast.CaseClause{pos, list, colon, body}
} }
func isTypeSwitchAssert(x ast.Expr) bool { func isExprSwitch(s ast.Stmt) bool {
a, ok := x.(*ast.TypeAssertExpr) if s == nil {
return ok && a.Type == nil return true
} }
if e, ok := s.(*ast.ExprStmt); ok {
func isTypeSwitchGuard(s ast.Stmt) bool { if a, ok := e.X.(*ast.TypeAssertExpr); ok {
switch t := s.(type) { return a.Type != nil // regular type assertion
case *ast.ExprStmt: }
// x.(nil) return true
return isTypeSwitchAssert(t.X)
case *ast.AssignStmt:
// v := x.(nil)
return len(t.Lhs) == 1 && t.Tok == token.DEFINE && len(t.Rhs) == 1 && isTypeSwitchAssert(t.Rhs[0])
} }
return false return false
} }
@ -1650,65 +1640,39 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
defer p.closeScope() defer p.closeScope()
var s1, s2 ast.Stmt var s1, s2 ast.Stmt
var scope *ast.Scope // scope for variable declared in TypeSwitchGuard, if any
if p.tok != token.LBRACE { if p.tok != token.LBRACE {
prevLev := p.exprLev prevLev := p.exprLev
p.exprLev = -1 p.exprLev = -1
if p.tok != token.SEMICOLON { if p.tok != token.SEMICOLON {
s2, _ = p.parseSimpleStmt(basic) s2, _ = p.parseSimpleStmt(basic)
scope = p.topScope
} }
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() p.next()
s1 = s2 s1 = s2
s2 = nil s2 = nil
if p.tok != token.LBRACE { if p.tok != token.LBRACE {
// A TypeSwitchGuard may declare a variable in addition
// to the variable declared in the initial SimpleStmt.
// Put it into an extra scope to avoid redeclaration
// errors, as in:
//
// switch t := 0; t := x.(T) { ... }
//
// (this code is still not valid Go because the first t
// will never be used - but the extra scope is needed
// for the correct error message).
//
// If we don't have a type switch, s2 must be an expression.
// Having the extra (empty) scope here won't affect it.
p.openScope()
s2, _ = p.parseSimpleStmt(basic) s2, _ = p.parseSimpleStmt(basic)
scope = p.topScope
p.closeScope()
} }
} }
p.exprLev = prevLev p.exprLev = prevLev
} }
// If varName != "", we have a type switch. If varName != "_" it exprSwitch := isExprSwitch(s2)
// is the name of the variable declared by the TypeSwitchGuard.
varName := ""
if isTypeSwitchGuard(s2) {
varName = "_"
// If s2 declared a variable, there is exactly one.
for varName = range scope.Objects {
}
}
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
var list []ast.Stmt var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT { for p.tok == token.CASE || p.tok == token.DEFAULT {
list = append(list, p.parseCaseClause(varName)) list = append(list, p.parseCaseClause(exprSwitch))
} }
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)
p.expectSemi() p.expectSemi()
body := &ast.BlockStmt{lbrace, list, rbrace} body := &ast.BlockStmt{lbrace, list, rbrace}
if varName != "" { if exprSwitch {
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body} return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
}
// type switch
// TODO(gri): do all the checks!
return &ast.TypeSwitchStmt{pos, s1, s2, body}
} }
func (p *parser) parseCommClause() *ast.CommClause { func (p *parser) parseCommClause() *ast.CommClause {
@ -2037,12 +2001,14 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
defer un(trace(p, "Receiver")) defer un(trace(p, "Receiver"))
} }
pos := p.pos
par := p.parseParameters(scope, false) par := p.parseParameters(scope, false)
// must have exactly one receiver // must have exactly one receiver
if par.NumFields() != 1 { if par.NumFields() != 1 {
p.errorExpected(par.Opening, "exactly one receiver") p.errorExpected(pos, "exactly one receiver")
par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{par.Opening, par.Closing + 1}}} // TODO determine a better range for BadExpr below
par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
return par return par
} }

View File

@ -26,9 +26,6 @@ var illegalInputs = []interface{}{
`package p; func f() { for _ = range x ; ; {} };`, `package p; func f() { for _ = range x ; ; {} };`,
`package p; func f() { for ; ; _ = range x {} };`, `package p; func f() { for ; ; _ = range x {} };`,
`package p; func f() { for ; _ = range x ; {} };`, `package p; func f() { for ; _ = range x ; {} };`,
`package p; func f() { switch t = t.(type) {} };`,
`package p; func f() { switch t, t = t.(type) {} };`,
`package p; func f() { switch t = t.(type), t {} };`,
`package p; var a = [1]int; /* illegal expression */`, `package p; var a = [1]int; /* illegal expression */`,
`package p; var a = [...]int; /* illegal expression */`, `package p; var a = [...]int; /* illegal expression */`,
`package p; var a = struct{} /* illegal expression */`, `package p; var a = struct{} /* illegal expression */`,