8
8
"fmt"
9
9
"go/ast"
10
10
"go/token"
11
+ "strings"
11
12
)
12
13
13
14
const debugResolve = false
@@ -24,6 +25,7 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str
24
25
declErr : declErr ,
25
26
topScope : pkgScope ,
26
27
pkgScope : pkgScope ,
28
+ depth : 1 ,
27
29
}
28
30
29
31
for _ , decl := range file .Decls {
@@ -45,7 +47,7 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str
45
47
i ++
46
48
} else if debugResolve {
47
49
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 )
49
51
}
50
52
}
51
53
file .Scope = r .pkgScope
@@ -60,15 +62,16 @@ type resolver struct {
60
62
pkgScope * ast.Scope // pkgScope.Outer == nil
61
63
topScope * ast.Scope // top-most scope; may be pkgScope
62
64
unresolved []* ast.Ident // unresolved identifiers
65
+ depth int // scope depth
63
66
64
67
// Label scopes
65
68
// (maintained by open/close LabelScope)
66
69
labelScope * ast.Scope // label scope for current function
67
70
targetStack [][]* ast.Ident // stack of unresolved labels
68
71
}
69
72
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 ... ))
72
75
}
73
76
74
77
func (r * resolver ) sprintf (format string , args ... any ) string {
@@ -83,14 +86,16 @@ func (r *resolver) sprintf(format string, args ...any) string {
83
86
84
87
func (r * resolver ) openScope (pos token.Pos ) {
85
88
if debugResolve {
86
- r .dump ("opening scope @%v" , pos )
89
+ r .trace ("opening scope @%v" , pos )
90
+ r .depth ++
87
91
}
88
92
r .topScope = ast .NewScope (r .topScope )
89
93
}
90
94
91
95
func (r * resolver ) closeScope () {
92
96
if debugResolve {
93
- r .dump ("closing scope" )
97
+ r .depth --
98
+ r .trace ("closing scope" )
94
99
}
95
100
r .topScope = r .topScope .Outer
96
101
}
@@ -117,21 +122,27 @@ func (r *resolver) closeLabelScope() {
117
122
118
123
func (r * resolver ) declare (decl , data any , scope * ast.Scope , kind ast.ObjKind , idents ... * ast.Ident ) {
119
124
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
+ }
121
128
obj := ast .NewObj (kind , ident .Name )
122
129
// remember the corresponding declaration for redeclaration
123
130
// errors and global variable resolution/typechecking phase
124
131
obj .Decl = decl
125
132
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
+ }
127
138
if ident .Name != "_" {
128
139
if debugResolve {
129
- r .dump ("declaring %s@%v" , ident .Name , ident .Pos ())
140
+ r .trace ("declaring %s@%v" , ident .Name , ident .Pos ())
130
141
}
131
142
if alt := scope .Insert (obj ); alt != nil && r .declErr != nil {
132
143
prevDecl := ""
133
144
if pos := alt .Pos (); pos .IsValid () {
134
- prevDecl = fmt . Sprintf ("\n \t previous declaration at %s " , r . handle . Position ( pos ) )
145
+ prevDecl = r . sprintf ("\n \t previous declaration at %v " , pos )
135
146
}
136
147
r .declErr (ident .Pos (), fmt .Sprintf ("%s redeclared in this block%s" , ident .Name , prevDecl ))
137
148
}
@@ -153,7 +164,7 @@ func (r *resolver) shortVarDecl(decl *ast.AssignStmt) {
153
164
ident .Obj = obj
154
165
if ident .Name != "_" {
155
166
if debugResolve {
156
- r .dump ("declaring %s@%v" , ident .Name , ident .Pos ())
167
+ r .trace ("declaring %s@%v" , ident .Name , ident .Pos ())
157
168
}
158
169
if alt := r .topScope .Insert (obj ); alt != nil {
159
170
ident .Obj = alt // redeclaration
@@ -180,7 +191,7 @@ var unresolved = new(ast.Object)
180
191
//
181
192
func (r * resolver ) resolve (ident * ast.Ident , collectUnresolved bool ) {
182
193
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 ))
184
195
}
185
196
// '_' should never refer to existing declarations, because it has special
186
197
// handling in the spec.
@@ -189,8 +200,15 @@ func (r *resolver) resolve(ident *ast.Ident, collectUnresolved bool) {
189
200
}
190
201
for s := r .topScope ; s != nil ; s = s .Outer {
191
202
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
+ }
192
206
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
+ }
194
212
return
195
213
}
196
214
}
@@ -227,7 +245,7 @@ func (r *resolver) walkStmts(list []ast.Stmt) {
227
245
228
246
func (r * resolver ) Visit (node ast.Node ) ast.Visitor {
229
247
if debugResolve && node != nil {
230
- r .dump ("node %T@%v" , node , node .Pos ())
248
+ r .trace ("node %T@%v" , node , node .Pos ())
231
249
}
232
250
233
251
switch n := node .(type ) {
@@ -461,8 +479,7 @@ func (r *resolver) Visit(node ast.Node) ast.Visitor {
461
479
r .openScope (n .Pos ())
462
480
defer r .closeScope ()
463
481
464
- // Resolve the receiver first, without declaring.
465
- r .resolveList (n .Recv )
482
+ r .walkRecv (n .Recv )
466
483
467
484
// Type parameters are walked normally: they can reference each other, and
468
485
// can be referenced by normal parameters.
@@ -519,6 +536,52 @@ func (r *resolver) declareList(list *ast.FieldList, kind ast.ObjKind) {
519
536
}
520
537
}
521
538
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
+
522
585
func (r * resolver ) walkFieldList (list * ast.FieldList , kind ast.ObjKind ) {
523
586
if list == nil {
524
587
return
0 commit comments