From 2465ae64591a0be336f0b0b654e1c02c89fdbe4e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 21 Feb 2018 20:27:29 -0800 Subject: [PATCH] go/types: fix regression with short variable declarations The variables on the lhs of a short variable declaration are only in scope after the variable declaration. Specifically, function literals on the rhs of a short variable declaration must not see newly declared variables on the lhs. This used to work and this bug was likely introduced with https://go-review.googlesource.com/c/go/+/83397 for go1.11. Luckily this is just an oversight and the fix is trivial: Simply use the mechanism for delayed type-checkin of function literals introduced in the before-mentioned change here as well. Fixes #24026. Change-Id: I74ce3a0d05c5a2a42ce4b27601645964f906e82d Reviewed-on: https://go-review.googlesource.com/96177 Reviewed-by: Alan Donovan --- src/go/types/assignments.go | 4 ++++ src/go/types/testdata/issues.src | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index f0030efedc..cb0fe3bc3a 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -279,6 +279,7 @@ func (check *Checker) assignVars(lhs, rhs []ast.Expr) { } func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { + top := len(check.delayed) scope := check.scope // collect lhs variables @@ -319,6 +320,9 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { check.initVars(lhsVars, rhs, token.NoPos) + // process function literals in rhs expressions before scope changes + check.processDelayed(top) + // declare new variables if len(newVars) > 0 { // spec: "The scope of a constant or variable identifier declared inside diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index 8729555e17..a346ab169a 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -207,3 +207,25 @@ func issue20358() { _ = T{t} _ = P{f: p} } + +// Test that we don't declare lhs variables in short variable +// declarations before we type-check function literals on the +// rhs. +func issue24026() { + f := func() int { f(0) /* must refer to outer f */; return 0 } + _ = f + + _ = func() { + f := func() { _ = f() /* must refer to outer f */ } + _ = f + } + + // b and c must not be visible inside function literal + a := 0 + a, b, c := func() (int, int, int) { + return a, b /* ERROR undeclared */ , c /* ERROR undeclared */ + }() + _, _ = b, c +} + +func f(int) {} // for issue24026