blob: 9e60af3b6185c685a3a5ff7a75f81dbea4ba5d1f [file] [log] [blame]
Alan Donovanc90cb9e2014-09-22 16:19:29 -04001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package satisfy inspects the type-checked ASTs of Go packages and
6// reports the set of discovered type constraints of the form (lhs, rhs
7// Type) where lhs is a non-trivial interface, rhs satisfies this
8// interface, and this fact is necessary for the package to be
9// well-typed.
10//
11// THIS PACKAGE IS EXPERIMENTAL AND MAY CHANGE AT ANY TIME.
12//
Alan Donovanec0831a2022-06-24 18:10:35 -040013// It is provided only for the gopls tool. It requires well-typed inputs.
David Symonds24257c82014-12-09 15:00:58 +110014package satisfy // import "golang.org/x/tools/refactor/satisfy"
Alan Donovanc90cb9e2014-09-22 16:19:29 -040015
16// NOTES:
17//
18// We don't care about numeric conversions, so we don't descend into
19// types or constant expressions. This is unsound because
20// constant expressions can contain arbitrary statements, e.g.
21// const x = len([1]func(){func() {
22// ...
23// }})
24//
Alan Donovanc90cb9e2014-09-22 16:19:29 -040025// Assignability conversions are possible in the following places:
26// - in assignments y = x, y := x, var y = x.
27// - from call argument types to formal parameter types
28// - in append and delete calls
29// - from return operands to result parameter types
30// - in composite literal T{k:v}, from k and v to T's field/element/key type
31// - in map[key] from key to the map's key type
32// - in comparisons x==y and switch x { case y: }.
33// - in explicit conversions T(x)
34// - in sends ch <- x, from x to the channel element type
35// - in type assertions x.(T) and switch x.(type) { case T: }
36//
37// The results of this pass provide information equivalent to the
38// ssa.MakeInterface and ssa.ChangeInterface instructions.
39
40import (
41 "fmt"
42 "go/ast"
43 "go/token"
Alan Donovan542ffc72015-12-29 13:06:30 -050044 "go/types"
Alan Donovanc90cb9e2014-09-22 16:19:29 -040045
Peter Collingbourne4f8578d2015-01-08 18:32:51 -080046 "golang.org/x/tools/go/ast/astutil"
Robert Griesemer3f8eecd2015-06-05 10:18:37 -070047 "golang.org/x/tools/go/types/typeutil"
Alan Donovanec0831a2022-06-24 18:10:35 -040048 "golang.org/x/tools/internal/typeparams"
Alan Donovanc90cb9e2014-09-22 16:19:29 -040049)
50
51// A Constraint records the fact that the RHS type does and must
Ainar Garipovfeee8ac2019-09-11 09:14:36 +030052// satisfy the LHS type, which is an interface.
Alan Donovanc90cb9e2014-09-22 16:19:29 -040053// The names are suggestive of an assignment statement LHS = RHS.
Alan Donovanec0831a2022-06-24 18:10:35 -040054//
55// The constraint is implicitly universally quantified over any type
56// parameters appearing within the two types.
Alan Donovanc90cb9e2014-09-22 16:19:29 -040057type Constraint struct {
58 LHS, RHS types.Type
59}
60
61// A Finder inspects the type-checked ASTs of Go packages and
62// accumulates the set of type constraints (x, y) such that x is
63// assignable to y, y is an interface, and both x and y have methods.
64//
65// In other words, it returns the subset of the "implements" relation
66// that is checked during compilation of a package. Refactoring tools
67// will need to preserve at least this part of the relation to ensure
68// continued compilation.
Alan Donovanc90cb9e2014-09-22 16:19:29 -040069type Finder struct {
70 Result map[Constraint]bool
Robert Griesemer3f8eecd2015-06-05 10:18:37 -070071 msetcache typeutil.MethodSetCache
Alan Donovanc90cb9e2014-09-22 16:19:29 -040072
73 // per-Find state
74 info *types.Info
75 sig *types.Signature
76}
77
78// Find inspects a single package, populating Result with its pairs of
79// constrained types.
80//
Alan Donovanc6ec5ea2014-12-04 09:37:50 -050081// The result is non-canonical and thus may contain duplicates (but this
82// tends to preserves names of interface types better).
83//
Alan Donovanc90cb9e2014-09-22 16:19:29 -040084// The package must be free of type errors, and
85// info.{Defs,Uses,Selections,Types} must have been populated by the
86// type-checker.
Alan Donovanc90cb9e2014-09-22 16:19:29 -040087func (f *Finder) Find(info *types.Info, files []*ast.File) {
88 if f.Result == nil {
89 f.Result = make(map[Constraint]bool)
90 }
91
92 f.info = info
93 for _, file := range files {
94 for _, d := range file.Decls {
95 switch d := d.(type) {
96 case *ast.GenDecl:
97 if d.Tok == token.VAR { // ignore consts
98 for _, spec := range d.Specs {
99 f.valueSpec(spec.(*ast.ValueSpec))
100 }
101 }
102
103 case *ast.FuncDecl:
104 if d.Body != nil {
105 f.sig = f.info.Defs[d.Name].Type().(*types.Signature)
106 f.stmt(d.Body)
107 f.sig = nil
108 }
109 }
110 }
111 }
112 f.info = nil
113}
114
115var (
116 tInvalid = types.Typ[types.Invalid]
117 tUntypedBool = types.Typ[types.UntypedBool]
118 tUntypedNil = types.Typ[types.UntypedNil]
119)
120
121// exprN visits an expression in a multi-value context.
122func (f *Finder) exprN(e ast.Expr) types.Type {
123 typ := f.info.Types[e].Type.(*types.Tuple)
124 switch e := e.(type) {
125 case *ast.ParenExpr:
126 return f.exprN(e.X)
127
128 case *ast.CallExpr:
129 // x, err := f(args)
Alan Donovanec0831a2022-06-24 18:10:35 -0400130 sig := coreType(f.expr(e.Fun)).(*types.Signature)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400131 f.call(sig, e.Args)
132
133 case *ast.IndexExpr:
134 // y, ok := x[i]
135 x := f.expr(e.X)
Alan Donovanec0831a2022-06-24 18:10:35 -0400136 f.assign(f.expr(e.Index), coreType(x).(*types.Map).Key())
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400137
138 case *ast.TypeAssertExpr:
139 // y, ok := x.(T)
140 f.typeAssert(f.expr(e.X), typ.At(0).Type())
141
142 case *ast.UnaryExpr: // must be receive <-
143 // y, ok := <-x
144 f.expr(e.X)
145
146 default:
147 panic(e)
148 }
149 return typ
150}
151
152func (f *Finder) call(sig *types.Signature, args []ast.Expr) {
153 if len(args) == 0 {
154 return
155 }
156
157 // Ellipsis call? e.g. f(x, y, z...)
158 if _, ok := args[len(args)-1].(*ast.Ellipsis); ok {
159 for i, arg := range args {
160 // The final arg is a slice, and so is the final param.
161 f.assign(sig.Params().At(i).Type(), f.expr(arg))
162 }
163 return
164 }
165
166 var argtypes []types.Type
167
168 // Gather the effective actual parameter types.
169 if tuple, ok := f.info.Types[args[0]].Type.(*types.Tuple); ok {
170 // f(g()) call where g has multiple results?
171 f.expr(args[0])
172 // unpack the tuple
173 for i := 0; i < tuple.Len(); i++ {
174 argtypes = append(argtypes, tuple.At(i).Type())
175 }
176 } else {
177 for _, arg := range args {
178 argtypes = append(argtypes, f.expr(arg))
179 }
180 }
181
182 // Assign the actuals to the formals.
183 if !sig.Variadic() {
184 for i, argtype := range argtypes {
185 f.assign(sig.Params().At(i).Type(), argtype)
186 }
187 } else {
188 // The first n-1 parameters are assigned normally.
189 nnormals := sig.Params().Len() - 1
190 for i, argtype := range argtypes[:nnormals] {
191 f.assign(sig.Params().At(i).Type(), argtype)
192 }
193 // Remaining args are assigned to elements of varargs slice.
194 tElem := sig.Params().At(nnormals).Type().(*types.Slice).Elem()
195 for i := nnormals; i < len(argtypes); i++ {
196 f.assign(tElem, argtypes[i])
197 }
198 }
199}
200
Robert Findleyb93a56f2022-10-14 12:21:42 -0400201// builtin visits the arguments of a builtin type with signature sig.
202func (f *Finder) builtin(obj *types.Builtin, sig *types.Signature, args []ast.Expr) {
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400203 switch obj.Name() {
204 case "make", "new":
205 // skip the type operand
206 for _, arg := range args[1:] {
207 f.expr(arg)
208 }
209
210 case "append":
211 s := f.expr(args[0])
212 if _, ok := args[len(args)-1].(*ast.Ellipsis); ok && len(args) == 2 {
213 // append(x, y...) including append([]byte, "foo"...)
214 f.expr(args[1])
215 } else {
216 // append(x, y, z)
Alan Donovanec0831a2022-06-24 18:10:35 -0400217 tElem := coreType(s).(*types.Slice).Elem()
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400218 for _, arg := range args[1:] {
219 f.assign(tElem, f.expr(arg))
220 }
221 }
222
223 case "delete":
224 m := f.expr(args[0])
225 k := f.expr(args[1])
Alan Donovanec0831a2022-06-24 18:10:35 -0400226 f.assign(coreType(m).(*types.Map).Key(), k)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400227
228 default:
229 // ordinary call
230 f.call(sig, args)
231 }
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400232}
233
234func (f *Finder) extract(tuple types.Type, i int) types.Type {
235 if tuple, ok := tuple.(*types.Tuple); ok && i < tuple.Len() {
236 return tuple.At(i).Type()
237 }
238 return tInvalid
239}
240
241func (f *Finder) valueSpec(spec *ast.ValueSpec) {
242 var T types.Type
243 if spec.Type != nil {
244 T = f.info.Types[spec.Type].Type
245 }
246 switch len(spec.Values) {
247 case len(spec.Names): // e.g. var x, y = f(), g()
248 for _, value := range spec.Values {
249 v := f.expr(value)
250 if T != nil {
251 f.assign(T, v)
252 }
253 }
254
255 case 1: // e.g. var x, y = f()
256 tuple := f.exprN(spec.Values[0])
257 for i := range spec.Names {
258 if T != nil {
259 f.assign(T, f.extract(tuple, i))
260 }
261 }
262 }
263}
264
265// assign records pairs of distinct types that are related by
266// assignability, where the left-hand side is an interface and both
267// sides have methods.
268//
269// It should be called for all assignability checks, type assertions,
270// explicit conversions and comparisons between two types, unless the
271// types are uninteresting (e.g. lhs is a concrete type, or the empty
272// interface; rhs has no methods).
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400273func (f *Finder) assign(lhs, rhs types.Type) {
274 if types.Identical(lhs, rhs) {
275 return
276 }
277 if !isInterface(lhs) {
278 return
279 }
Alan Donovanc6ec5ea2014-12-04 09:37:50 -0500280
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400281 if f.msetcache.MethodSet(lhs).Len() == 0 {
282 return
283 }
284 if f.msetcache.MethodSet(rhs).Len() == 0 {
285 return
286 }
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400287 // record the pair
Alan Donovanc6ec5ea2014-12-04 09:37:50 -0500288 f.Result[Constraint{lhs, rhs}] = true
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400289}
290
291// typeAssert must be called for each type assertion x.(T) where x has
292// interface type I.
293func (f *Finder) typeAssert(I, T types.Type) {
294 // Type assertions are slightly subtle, because they are allowed
295 // to be "impossible", e.g.
296 //
297 // var x interface{f()}
298 // _ = x.(interface{f()int}) // legal
299 //
300 // (In hindsight, the language spec should probably not have
301 // allowed this, but it's too late to fix now.)
302 //
303 // This means that a type assert from I to T isn't exactly a
304 // constraint that T is assignable to I, but for a refactoring
305 // tool it is a conditional constraint that, if T is assignable
306 // to I before a refactoring, it should remain so after.
307
308 if types.AssignableTo(T, I) {
309 f.assign(I, T)
310 }
311}
312
313// compare must be called for each comparison x==y.
314func (f *Finder) compare(x, y types.Type) {
315 if types.AssignableTo(x, y) {
316 f.assign(y, x)
317 } else if types.AssignableTo(y, x) {
318 f.assign(x, y)
319 }
320}
321
322// expr visits a true expression (not a type or defining ident)
323// and returns its type.
324func (f *Finder) expr(e ast.Expr) types.Type {
325 tv := f.info.Types[e]
326 if tv.Value != nil {
327 return tv.Type // prune the descent for constants
328 }
329
330 // tv.Type may be nil for an ast.Ident.
331
332 switch e := e.(type) {
333 case *ast.BadExpr, *ast.BasicLit:
334 // no-op
335
336 case *ast.Ident:
337 // (referring idents only)
338 if obj, ok := f.info.Uses[e]; ok {
339 return obj.Type()
340 }
341 if e.Name == "_" { // e.g. "for _ = range x"
342 return tInvalid
343 }
344 panic("undefined ident: " + e.Name)
345
346 case *ast.Ellipsis:
347 if e.Elt != nil {
348 f.expr(e.Elt)
349 }
350
351 case *ast.FuncLit:
352 saved := f.sig
353 f.sig = tv.Type.(*types.Signature)
354 f.stmt(e.Body)
355 f.sig = saved
356
357 case *ast.CompositeLit:
Robert Findleyf42bca82023-08-07 15:10:26 -0400358 switch T := coreType(deref(tv.Type)).(type) {
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400359 case *types.Struct:
360 for i, elem := range e.Elts {
361 if kv, ok := elem.(*ast.KeyValueExpr); ok {
362 f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value))
363 } else {
364 f.assign(T.Field(i).Type(), f.expr(elem))
365 }
366 }
367
368 case *types.Map:
369 for _, elem := range e.Elts {
370 elem := elem.(*ast.KeyValueExpr)
371 f.assign(T.Key(), f.expr(elem.Key))
372 f.assign(T.Elem(), f.expr(elem.Value))
373 }
374
375 case *types.Array, *types.Slice:
376 tElem := T.(interface {
377 Elem() types.Type
378 }).Elem()
379 for _, elem := range e.Elts {
380 if kv, ok := elem.(*ast.KeyValueExpr); ok {
381 // ignore the key
382 f.assign(tElem, f.expr(kv.Value))
383 } else {
384 f.assign(tElem, f.expr(elem))
385 }
386 }
387
388 default:
Robert Findleyf42bca82023-08-07 15:10:26 -0400389 panic(fmt.Sprintf("unexpected composite literal type %T: %v", tv.Type, tv.Type.String()))
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400390 }
391
392 case *ast.ParenExpr:
393 f.expr(e.X)
394
395 case *ast.SelectorExpr:
396 if _, ok := f.info.Selections[e]; ok {
397 f.expr(e.X) // selection
398 } else {
399 return f.info.Uses[e.Sel].Type() // qualified identifier
400 }
401
402 case *ast.IndexExpr:
Alan Donovanec0831a2022-06-24 18:10:35 -0400403 if instance(f.info, e.X) {
404 // f[T] or C[T] -- generic instantiation
405 } else {
406 // x[i] or m[k] -- index or lookup operation
407 x := f.expr(e.X)
408 i := f.expr(e.Index)
409 if ux, ok := coreType(x).(*types.Map); ok {
410 f.assign(ux.Key(), i)
411 }
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400412 }
413
Alan Donovanec0831a2022-06-24 18:10:35 -0400414 case *typeparams.IndexListExpr:
415 // f[X, Y] -- generic instantiation
416
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400417 case *ast.SliceExpr:
418 f.expr(e.X)
419 if e.Low != nil {
420 f.expr(e.Low)
421 }
422 if e.High != nil {
423 f.expr(e.High)
424 }
425 if e.Max != nil {
426 f.expr(e.Max)
427 }
428
429 case *ast.TypeAssertExpr:
430 x := f.expr(e.X)
431 f.typeAssert(x, f.info.Types[e.Type].Type)
432
433 case *ast.CallExpr:
434 if tvFun := f.info.Types[e.Fun]; tvFun.IsType() {
435 // conversion
436 arg0 := f.expr(e.Args[0])
437 f.assign(tvFun.Type, arg0)
438 } else {
439 // function call
Robert Findleyb93a56f2022-10-14 12:21:42 -0400440
441 // unsafe call. Treat calls to functions in unsafe like ordinary calls,
442 // except that their signature cannot be determined by their func obj.
443 // Without this special handling, f.expr(e.Fun) would fail below.
444 if s, ok := unparen(e.Fun).(*ast.SelectorExpr); ok {
445 if obj, ok := f.info.Uses[s.Sel].(*types.Builtin); ok && obj.Pkg().Path() == "unsafe" {
446 sig := f.info.Types[e.Fun].Type.(*types.Signature)
447 f.call(sig, e.Args)
448 return tv.Type
449 }
450 }
451
452 // builtin call
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400453 if id, ok := unparen(e.Fun).(*ast.Ident); ok {
454 if obj, ok := f.info.Uses[id].(*types.Builtin); ok {
455 sig := f.info.Types[id].Type.(*types.Signature)
Robert Findleyb93a56f2022-10-14 12:21:42 -0400456 f.builtin(obj, sig, e.Args)
457 return tv.Type
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400458 }
459 }
Robert Findleyb93a56f2022-10-14 12:21:42 -0400460
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400461 // ordinary call
Alan Donovanec0831a2022-06-24 18:10:35 -0400462 f.call(coreType(f.expr(e.Fun)).(*types.Signature), e.Args)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400463 }
464
465 case *ast.StarExpr:
466 f.expr(e.X)
467
468 case *ast.UnaryExpr:
469 f.expr(e.X)
470
471 case *ast.BinaryExpr:
472 x := f.expr(e.X)
473 y := f.expr(e.Y)
474 if e.Op == token.EQL || e.Op == token.NEQ {
475 f.compare(x, y)
476 }
477
478 case *ast.KeyValueExpr:
479 f.expr(e.Key)
480 f.expr(e.Value)
481
482 case *ast.ArrayType,
483 *ast.StructType,
484 *ast.FuncType,
485 *ast.InterfaceType,
486 *ast.MapType,
487 *ast.ChanType:
488 panic(e)
489 }
490
491 if tv.Type == nil {
492 panic(fmt.Sprintf("no type for %T", e))
493 }
494
495 return tv.Type
496}
497
498func (f *Finder) stmt(s ast.Stmt) {
499 switch s := s.(type) {
500 case *ast.BadStmt,
501 *ast.EmptyStmt,
502 *ast.BranchStmt:
503 // no-op
504
505 case *ast.DeclStmt:
506 d := s.Decl.(*ast.GenDecl)
507 if d.Tok == token.VAR { // ignore consts
508 for _, spec := range d.Specs {
509 f.valueSpec(spec.(*ast.ValueSpec))
510 }
511 }
512
513 case *ast.LabeledStmt:
514 f.stmt(s.Stmt)
515
516 case *ast.ExprStmt:
517 f.expr(s.X)
518
519 case *ast.SendStmt:
520 ch := f.expr(s.Chan)
521 val := f.expr(s.Value)
Alan Donovanec0831a2022-06-24 18:10:35 -0400522 f.assign(coreType(ch).(*types.Chan).Elem(), val)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400523
524 case *ast.IncDecStmt:
525 f.expr(s.X)
526
527 case *ast.AssignStmt:
528 switch s.Tok {
529 case token.ASSIGN, token.DEFINE:
530 // y := x or y = x
531 var rhsTuple types.Type
532 if len(s.Lhs) != len(s.Rhs) {
533 rhsTuple = f.exprN(s.Rhs[0])
534 }
535 for i := range s.Lhs {
536 var lhs, rhs types.Type
537 if rhsTuple == nil {
538 rhs = f.expr(s.Rhs[i]) // 1:1 assignment
539 } else {
540 rhs = f.extract(rhsTuple, i) // n:1 assignment
541 }
542
543 if id, ok := s.Lhs[i].(*ast.Ident); ok {
544 if id.Name != "_" {
545 if obj, ok := f.info.Defs[id]; ok {
546 lhs = obj.Type() // definition
547 }
548 }
549 }
550 if lhs == nil {
551 lhs = f.expr(s.Lhs[i]) // assignment
552 }
553 f.assign(lhs, rhs)
554 }
555
556 default:
557 // y op= x
558 f.expr(s.Lhs[0])
559 f.expr(s.Rhs[0])
560 }
561
562 case *ast.GoStmt:
563 f.expr(s.Call)
564
565 case *ast.DeferStmt:
566 f.expr(s.Call)
567
568 case *ast.ReturnStmt:
569 formals := f.sig.Results()
570 switch len(s.Results) {
571 case formals.Len(): // 1:1
572 for i, result := range s.Results {
573 f.assign(formals.At(i).Type(), f.expr(result))
574 }
575
576 case 1: // n:1
577 tuple := f.exprN(s.Results[0])
578 for i := 0; i < formals.Len(); i++ {
579 f.assign(formals.At(i).Type(), f.extract(tuple, i))
580 }
581 }
582
583 case *ast.SelectStmt:
584 f.stmt(s.Body)
585
586 case *ast.BlockStmt:
587 for _, s := range s.List {
588 f.stmt(s)
589 }
590
591 case *ast.IfStmt:
592 if s.Init != nil {
593 f.stmt(s.Init)
594 }
595 f.expr(s.Cond)
596 f.stmt(s.Body)
597 if s.Else != nil {
598 f.stmt(s.Else)
599 }
600
601 case *ast.SwitchStmt:
602 if s.Init != nil {
603 f.stmt(s.Init)
604 }
605 var tag types.Type = tUntypedBool
606 if s.Tag != nil {
607 tag = f.expr(s.Tag)
608 }
609 for _, cc := range s.Body.List {
610 cc := cc.(*ast.CaseClause)
611 for _, cond := range cc.List {
612 f.compare(tag, f.info.Types[cond].Type)
613 }
614 for _, s := range cc.Body {
615 f.stmt(s)
616 }
617 }
618
619 case *ast.TypeSwitchStmt:
620 if s.Init != nil {
621 f.stmt(s.Init)
622 }
623 var I types.Type
624 switch ass := s.Assign.(type) {
625 case *ast.ExprStmt: // x.(type)
626 I = f.expr(unparen(ass.X).(*ast.TypeAssertExpr).X)
627 case *ast.AssignStmt: // y := x.(type)
628 I = f.expr(unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
629 }
630 for _, cc := range s.Body.List {
631 cc := cc.(*ast.CaseClause)
632 for _, cond := range cc.List {
633 tCase := f.info.Types[cond].Type
634 if tCase != tUntypedNil {
635 f.typeAssert(I, tCase)
636 }
637 }
638 for _, s := range cc.Body {
639 f.stmt(s)
640 }
641 }
642
643 case *ast.CommClause:
644 if s.Comm != nil {
645 f.stmt(s.Comm)
646 }
647 for _, s := range s.Body {
648 f.stmt(s)
649 }
650
651 case *ast.ForStmt:
652 if s.Init != nil {
653 f.stmt(s.Init)
654 }
655 if s.Cond != nil {
656 f.expr(s.Cond)
657 }
658 if s.Post != nil {
659 f.stmt(s.Post)
660 }
661 f.stmt(s.Body)
662
663 case *ast.RangeStmt:
664 x := f.expr(s.X)
665 // No conversions are involved when Tok==DEFINE.
666 if s.Tok == token.ASSIGN {
667 if s.Key != nil {
668 k := f.expr(s.Key)
669 var xelem types.Type
Alan Donovanec0831a2022-06-24 18:10:35 -0400670 // Keys of array, *array, slice, string aren't interesting
671 // since the RHS key type is just an int.
672 switch ux := coreType(x).(type) {
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400673 case *types.Chan:
674 xelem = ux.Elem()
675 case *types.Map:
676 xelem = ux.Key()
677 }
678 if xelem != nil {
Alan Donovanec0831a2022-06-24 18:10:35 -0400679 f.assign(k, xelem)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400680 }
681 }
682 if s.Value != nil {
683 val := f.expr(s.Value)
684 var xelem types.Type
Alan Donovanec0831a2022-06-24 18:10:35 -0400685 // Values of type strings aren't interesting because
686 // the RHS value type is just a rune.
687 switch ux := coreType(x).(type) {
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400688 case *types.Array:
689 xelem = ux.Elem()
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400690 case *types.Map:
691 xelem = ux.Elem()
692 case *types.Pointer: // *array
Alan Donovanec0831a2022-06-24 18:10:35 -0400693 xelem = coreType(deref(ux)).(*types.Array).Elem()
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400694 case *types.Slice:
695 xelem = ux.Elem()
696 }
697 if xelem != nil {
Alan Donovanec0831a2022-06-24 18:10:35 -0400698 f.assign(val, xelem)
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400699 }
700 }
701 }
702 f.stmt(s.Body)
703
704 default:
705 panic(s)
706 }
707}
708
Andrew Gerrand5ebbcd12014-11-10 08:50:40 +1100709// -- Plundered from golang.org/x/tools/go/ssa -----------------
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400710
711// deref returns a pointer's element type; otherwise it returns typ.
712func deref(typ types.Type) types.Type {
Alan Donovanec0831a2022-06-24 18:10:35 -0400713 if p, ok := coreType(typ).(*types.Pointer); ok {
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400714 return p.Elem()
715 }
716 return typ
717}
718
Alan Donovan4f137142014-12-29 15:35:00 -0500719func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
Alan Donovanc90cb9e2014-09-22 16:19:29 -0400720
Alan Donovan4d45c852014-12-29 15:47:06 -0500721func isInterface(T types.Type) bool { return types.IsInterface(T) }
Alan Donovanec0831a2022-06-24 18:10:35 -0400722
723func coreType(T types.Type) types.Type { return typeparams.CoreType(T) }
724
725func instance(info *types.Info, expr ast.Expr) bool {
726 var id *ast.Ident
727 switch x := expr.(type) {
728 case *ast.Ident:
729 id = x
730 case *ast.SelectorExpr:
731 id = x.Sel
732 default:
733 return false
734 }
735 _, ok := typeparams.GetInstances(info)[id]
736 return ok
737}