Skip to content

Commit 911c78f

Browse files
committed
go/parser: fix incorrect resolution of receiver type parameters
Declare receiver type parameters in the function scope, but don't resolve them (for now), as ast.Object.Decl is not documented to hold *ast.Idents. This avoids incorrect resolution of identifiers to names outside the function scope. Also make tracing and error reporting more consistent. For #50956 Change-Id: I8cd61dd25f4c0f6b974221599b00e23d8da206a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/382247 Trust: Robert Findley <[email protected]> Run-TryBot: Robert Findley <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 7db75b3 commit 911c78f

File tree

3 files changed

+91
-16
lines changed

3 files changed

+91
-16
lines changed

src/go/parser/resolver.go

+78-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"go/ast"
1010
"go/token"
11+
"strings"
1112
)
1213

1314
const debugResolve = false
@@ -24,6 +25,7 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str
2425
declErr: declErr,
2526
topScope: pkgScope,
2627
pkgScope: pkgScope,
28+
depth: 1,
2729
}
2830

2931
for _, decl := range file.Decls {
@@ -45,7 +47,7 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str
4547
i++
4648
} else if debugResolve {
4749
pos := ident.Obj.Decl.(interface{ Pos() token.Pos }).Pos()
48-
r.dump("resolved %s@%v to package object %v", ident.Name, ident.Pos(), pos)
50+
r.trace("resolved %s@%v to package object %v", ident.Name, ident.Pos(), pos)
4951
}
5052
}
5153
file.Scope = r.pkgScope
@@ -60,15 +62,16 @@ type resolver struct {
6062
pkgScope *ast.Scope // pkgScope.Outer == nil
6163
topScope *ast.Scope // top-most scope; may be pkgScope
6264
unresolved []*ast.Ident // unresolved identifiers
65+
depth int // scope depth
6366

6467
// Label scopes
6568
// (maintained by open/close LabelScope)
6669
labelScope *ast.Scope // label scope for current function
6770
targetStack [][]*ast.Ident // stack of unresolved labels
6871
}
6972

70-
func (r *resolver) dump(format string, args ...any) {
71-
fmt.Println(">>> " + r.sprintf(format, args...))
73+
func (r *resolver) trace(format string, args ...any) {
74+
fmt.Println(strings.Repeat(". ", r.depth) + r.sprintf(format, args...))
7275
}
7376

7477
func (r *resolver) sprintf(format string, args ...any) string {
@@ -83,14 +86,16 @@ func (r *resolver) sprintf(format string, args ...any) string {
8386

8487
func (r *resolver) openScope(pos token.Pos) {
8588
if debugResolve {
86-
r.dump("opening scope @%v", pos)
89+
r.trace("opening scope @%v", pos)
90+
r.depth++
8791
}
8892
r.topScope = ast.NewScope(r.topScope)
8993
}
9094

9195
func (r *resolver) closeScope() {
9296
if debugResolve {
93-
r.dump("closing scope")
97+
r.depth--
98+
r.trace("closing scope")
9499
}
95100
r.topScope = r.topScope.Outer
96101
}
@@ -117,21 +122,27 @@ func (r *resolver) closeLabelScope() {
117122

118123
func (r *resolver) declare(decl, data any, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
119124
for _, ident := range idents {
120-
assert(ident.Obj == nil, "identifier already declared or resolved")
125+
if ident.Obj != nil {
126+
panic(fmt.Sprintf("%v: identifier %s already declared or resolved", ident.Pos(), ident.Name))
127+
}
121128
obj := ast.NewObj(kind, ident.Name)
122129
// remember the corresponding declaration for redeclaration
123130
// errors and global variable resolution/typechecking phase
124131
obj.Decl = decl
125132
obj.Data = data
126-
ident.Obj = obj
133+
// Identifiers (for receiver type parameters) are written to the scope, but
134+
// never set as the resolved object. See issue #50956.
135+
if _, ok := decl.(*ast.Ident); !ok {
136+
ident.Obj = obj
137+
}
127138
if ident.Name != "_" {
128139
if debugResolve {
129-
r.dump("declaring %s@%v", ident.Name, ident.Pos())
140+
r.trace("declaring %s@%v", ident.Name, ident.Pos())
130141
}
131142
if alt := scope.Insert(obj); alt != nil && r.declErr != nil {
132143
prevDecl := ""
133144
if pos := alt.Pos(); pos.IsValid() {
134-
prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", r.handle.Position(pos))
145+
prevDecl = r.sprintf("\n\tprevious declaration at %v", pos)
135146
}
136147
r.declErr(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
137148
}
@@ -153,7 +164,7 @@ func (r *resolver) shortVarDecl(decl *ast.AssignStmt) {
153164
ident.Obj = obj
154165
if ident.Name != "_" {
155166
if debugResolve {
156-
r.dump("declaring %s@%v", ident.Name, ident.Pos())
167+
r.trace("declaring %s@%v", ident.Name, ident.Pos())
157168
}
158169
if alt := r.topScope.Insert(obj); alt != nil {
159170
ident.Obj = alt // redeclaration
@@ -180,7 +191,7 @@ var unresolved = new(ast.Object)
180191
//
181192
func (r *resolver) resolve(ident *ast.Ident, collectUnresolved bool) {
182193
if ident.Obj != nil {
183-
panic(fmt.Sprintf("%s: identifier %s already declared or resolved", r.handle.Position(ident.Pos()), ident.Name))
194+
panic(r.sprintf("%v: identifier %s already declared or resolved", ident.Pos(), ident.Name))
184195
}
185196
// '_' should never refer to existing declarations, because it has special
186197
// handling in the spec.
@@ -189,8 +200,15 @@ func (r *resolver) resolve(ident *ast.Ident, collectUnresolved bool) {
189200
}
190201
for s := r.topScope; s != nil; s = s.Outer {
191202
if obj := s.Lookup(ident.Name); obj != nil {
203+
if debugResolve {
204+
r.trace("resolved %v:%s to %v", ident.Pos(), ident.Name, obj)
205+
}
192206
assert(obj.Name != "", "obj with no name")
193-
ident.Obj = obj
207+
// Identifiers (for receiver type parameters) are written to the scope,
208+
// but never set as the resolved object. See issue #50956.
209+
if _, ok := obj.Decl.(*ast.Ident); !ok {
210+
ident.Obj = obj
211+
}
194212
return
195213
}
196214
}
@@ -227,7 +245,7 @@ func (r *resolver) walkStmts(list []ast.Stmt) {
227245

228246
func (r *resolver) Visit(node ast.Node) ast.Visitor {
229247
if debugResolve && node != nil {
230-
r.dump("node %T@%v", node, node.Pos())
248+
r.trace("node %T@%v", node, node.Pos())
231249
}
232250

233251
switch n := node.(type) {
@@ -461,8 +479,7 @@ func (r *resolver) Visit(node ast.Node) ast.Visitor {
461479
r.openScope(n.Pos())
462480
defer r.closeScope()
463481

464-
// Resolve the receiver first, without declaring.
465-
r.resolveList(n.Recv)
482+
r.walkRecv(n.Recv)
466483

467484
// Type parameters are walked normally: they can reference each other, and
468485
// can be referenced by normal parameters.
@@ -519,6 +536,52 @@ func (r *resolver) declareList(list *ast.FieldList, kind ast.ObjKind) {
519536
}
520537
}
521538

539+
func (r *resolver) walkRecv(recv *ast.FieldList) {
540+
// If our receiver has receiver type parameters, we must declare them before
541+
// trying to resolve the rest of the receiver, and avoid re-resolving the
542+
// type parameter identifiers.
543+
if recv == nil || len(recv.List) == 0 {
544+
return // nothing to do
545+
}
546+
typ := recv.List[0].Type
547+
if ptr, ok := typ.(*ast.StarExpr); ok {
548+
typ = ptr.X
549+
}
550+
551+
var declareExprs []ast.Expr // exprs to declare
552+
var resolveExprs []ast.Expr // exprs to resolve
553+
switch typ := typ.(type) {
554+
case *ast.IndexExpr:
555+
declareExprs = []ast.Expr{typ.Index}
556+
resolveExprs = append(resolveExprs, typ.X)
557+
case *ast.IndexListExpr:
558+
declareExprs = typ.Indices
559+
resolveExprs = append(resolveExprs, typ.X)
560+
default:
561+
resolveExprs = append(resolveExprs, typ)
562+
}
563+
for _, expr := range declareExprs {
564+
if id, _ := expr.(*ast.Ident); id != nil {
565+
r.declare(expr, nil, r.topScope, ast.Typ, id)
566+
} else {
567+
// The receiver type parameter expression is invalid, but try to resolve
568+
// it anyway for consistency.
569+
resolveExprs = append(resolveExprs, expr)
570+
}
571+
}
572+
for _, expr := range resolveExprs {
573+
if expr != nil {
574+
ast.Walk(r, expr)
575+
}
576+
}
577+
// The receiver is invalid, but try to resolve it anyway for consistency.
578+
for _, f := range recv.List[1:] {
579+
if f.Type != nil {
580+
ast.Walk(r, f.Type)
581+
}
582+
}
583+
}
584+
522585
func (r *resolver) walkFieldList(list *ast.FieldList, kind ast.ObjKind) {
523586
if list == nil {
524587
return

src/go/parser/short_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ var invalidNoTParamErrs = []string{
237237
`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
238238
`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
239239
`package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
240+
241+
`package p; func(*T[ /* ERROR "missing ',' in parameter list" */ e, e]) _()`,
240242
}
241243

242244
// invalidTParamErrs holds invalid source code examples annotated with the
@@ -255,6 +257,8 @@ var invalidTParamErrs = []string{
255257
`package p; func (T) _[ /* ERROR "must have no type parameters" */ A, B any](a A) B`,
256258
`package p; func (T) _[ /* ERROR "must have no type parameters" */ A, B C](a A) B`,
257259
`package p; func (T) _[ /* ERROR "must have no type parameters" */ A, B C[A, B]](a A) B`,
260+
261+
`package p; func(*T[e, e /* ERROR "e redeclared" */ ]) _()`,
258262
}
259263

260264
func TestInvalid(t *testing.T) {

src/go/parser/testdata/resolution/typeparams.go2

+9-1
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ func Add /* =@AddDecl */[T /* =@T */ Addable /* @Addable */](l /* =@l */, r /* =
2525

2626
type Receiver /* =@Receiver */[P /* =@P */ any] struct {}
2727

28+
type RP /* =@RP1 */ struct{}
29+
2830
// TODO(rFindley): make a decision on how/whether to resolve identifiers that
2931
// refer to receiver type parameters, as is the case for the 'P' result
3032
// parameter below.
31-
func (r /* =@recv */ Receiver /* @Receiver */ [P]) m() P {}
33+
//
34+
// For now, we ensure that types are not incorrectly resolved when receiver
35+
// type parameters are in scope.
36+
func (r /* =@recv */ Receiver /* @Receiver */ [RP]) m(RP) RP {}
3237

3338
func f /* =@f */[T1 /* =@T1 */ interface{~[]T2 /* @T2 */}, T2 /* =@T2 */ any](
3439
x /* =@x */ T1 /* @T1 */, T1 /* =@T1_duplicate */ y, // Note that this is a bug:
@@ -41,3 +46,6 @@ func f /* =@f */[T1 /* =@T1 */ interface{~[]T2 /* @T2 */}, T2 /* =@T2 */ any](
4146
T1 /* @T1 */ := 0
4247
var t1var /* =@t1var */ T1 /* @T1 */
4348
}
49+
50+
// From issue #39634
51+
func(*ph1[e, e])h(d)

0 commit comments

Comments
 (0)