Skip to content

Commit c02e1bf

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: refactor assignVars
Rather than using exprList and handle all cases together, split apart the cases of n:n assignments and the cases of n:1 assignments. For the former, the lhs types may (in a future CL) be used to infer types on the rhs. This is a preparatory step. Because the two cases are handled separately, the code is longer (but also more explicit). Some test cases were adjusted to avoifd (legitimate, but previously supressed) "declared but not used" errors. Change-Id: Ia43265f84e423b0ad5594612ba5a0ddce31a4a37 Reviewed-on: https://go-review.googlesource.com/c/go/+/478256 Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Robert Griesemer <[email protected]>
1 parent 4237dea commit c02e1bf

File tree

4 files changed

+83
-31
lines changed

4 files changed

+83
-31
lines changed

src/cmd/compile/internal/types2/assignments.go

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -387,30 +387,55 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy
387387
}
388388

389389
func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
390-
rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2)
390+
l, r := len(lhs), len(orig_rhs)
391+
392+
// If l == 1 and the rhs is a single call, for a better
393+
// error message don't handle it as n:n mapping below.
394+
isCall := false
395+
if r == 1 {
396+
_, isCall = unparen(orig_rhs[0]).(*syntax.CallExpr)
397+
}
398+
399+
// If we have a n:n mapping from lhs variable to rhs expression,
400+
// each value can be assigned to its corresponding variable.
401+
if l == r && !isCall {
402+
for i, lhs := range lhs {
403+
var x operand
404+
check.expr(&x, orig_rhs[i])
405+
check.assignVar(lhs, &x)
406+
}
407+
return
408+
}
391409

392-
if len(lhs) != len(rhs) {
410+
// If we don't have an n:n mapping, the rhs must be a single expression
411+
// resulting in 2 or more values; otherwise we have an assignment mismatch.
412+
if r != 1 {
413+
check.assignError(orig_rhs, l, r)
393414
check.useLHS(lhs...)
394-
// don't report an error if we already reported one
395-
for _, x := range rhs {
396-
if x.mode == invalid {
397-
return
398-
}
399-
}
400-
check.assignError(orig_rhs, len(lhs), len(rhs))
415+
check.use(orig_rhs...)
401416
return
402417
}
403418

404-
if commaOk {
405-
check.assignVar(lhs[0], rhs[0])
406-
check.assignVar(lhs[1], rhs[1])
407-
check.recordCommaOkTypes(orig_rhs[0], rhs)
419+
rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2)
420+
r = len(rhs)
421+
if l == r {
422+
for i, lhs := range lhs {
423+
check.assignVar(lhs, rhs[i])
424+
}
425+
if commaOk {
426+
check.recordCommaOkTypes(orig_rhs[0], rhs)
427+
}
408428
return
409429
}
410430

411-
for i, lhs := range lhs {
412-
check.assignVar(lhs, rhs[i])
431+
// In all other cases we have an assignment mismatch.
432+
// Only report a mismatch error if there was no error
433+
// on the rhs.
434+
if rhs[0].mode != invalid {
435+
check.assignError(orig_rhs, l, r)
413436
}
437+
check.useLHS(lhs...)
438+
// orig_rhs[0] was already evaluated
414439
}
415440

416441
// unpackExpr unpacks a *syntax.ListExpr into a list of syntax.Expr.

src/cmd/compile/internal/types2/expr.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,7 @@ func (check *Checker) expr(x *operand, e syntax.Expr) {
18261826
// If allowCommaOk is set and e is a map index, comma-ok, or comma-err
18271827
// expression, the result is a two-element list containing the value
18281828
// of e, and an untyped bool value or an error value, respectively.
1829+
// If an error occurred, list[0] is not valid.
18291830
func (check *Checker) multiExpr(e syntax.Expr, allowCommaOk bool) (list []*operand, commaOk bool) {
18301831
var x operand
18311832
check.rawExpr(&x, e, nil, false)

src/go/types/assignments.go

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -372,31 +372,56 @@ func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnStmt ast.St
372372
}
373373
}
374374

375-
func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
376-
rhs, commaOk := check.exprList(origRHS, len(lhs) == 2)
375+
func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
376+
l, r := len(lhs), len(orig_rhs)
377+
378+
// If l == 1 and the rhs is a single call, for a better
379+
// error message don't handle it as n:n mapping below.
380+
isCall := false
381+
if r == 1 {
382+
_, isCall = unparen(orig_rhs[0]).(*ast.CallExpr)
383+
}
384+
385+
// If we have a n:n mapping from lhs variable to rhs expression,
386+
// each value can be assigned to its corresponding variable.
387+
if l == r && !isCall {
388+
for i, lhs := range lhs {
389+
var x operand
390+
check.expr(&x, orig_rhs[i])
391+
check.assignVar(lhs, &x)
392+
}
393+
return
394+
}
377395

378-
if len(lhs) != len(rhs) {
396+
// If we don't have an n:n mapping, the rhs must be a single expression
397+
// resulting in 2 or more values; otherwise we have an assignment mismatch.
398+
if r != 1 {
399+
check.assignError(orig_rhs, l, r)
379400
check.useLHS(lhs...)
380-
// don't report an error if we already reported one
381-
for _, x := range rhs {
382-
if x.mode == invalid {
383-
return
384-
}
385-
}
386-
check.assignError(origRHS, len(lhs), len(rhs))
401+
check.use(orig_rhs...)
387402
return
388403
}
389404

390-
if commaOk {
391-
check.assignVar(lhs[0], rhs[0])
392-
check.assignVar(lhs[1], rhs[1])
393-
check.recordCommaOkTypes(origRHS[0], rhs)
405+
rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2)
406+
r = len(rhs)
407+
if l == r {
408+
for i, lhs := range lhs {
409+
check.assignVar(lhs, rhs[i])
410+
}
411+
if commaOk {
412+
check.recordCommaOkTypes(orig_rhs[0], rhs)
413+
}
394414
return
395415
}
396416

397-
for i, lhs := range lhs {
398-
check.assignVar(lhs, rhs[i])
417+
// In all other cases we have an assignment mismatch.
418+
// Only report a mismatch error if there was no error
419+
// on the rhs.
420+
if rhs[0].mode != invalid {
421+
check.assignError(orig_rhs, l, r)
399422
}
423+
check.useLHS(lhs...)
424+
// orig_rhs[0] was already evaluated
400425
}
401426

402427
func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {

src/go/types/expr.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,7 @@ func (check *Checker) expr(x *operand, e ast.Expr) {
17731773
// If allowCommaOk is set and e is a map index, comma-ok, or comma-err
17741774
// expression, the result is a two-element list containing the value
17751775
// of e, and an untyped bool value or an error value, respectively.
1776+
// If an error occurred, list[0] is not valid.
17761777
func (check *Checker) multiExpr(e ast.Expr, allowCommaOk bool) (list []*operand, commaOk bool) {
17771778
var x operand
17781779
check.rawExpr(&x, e, nil, false)

0 commit comments

Comments
 (0)