1 | // 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 | // |
13 | // It is provided only for the gopls tool. It requires well-typed inputs. |
14 | package satisfy // import "golang.org/x/tools/refactor/satisfy" |
15 | |
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 | // |
25 | // 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 | |
40 | import ( |
41 | "fmt" |
42 | "go/ast" |
43 | "go/token" |
44 | "go/types" |
45 | |
46 | "golang.org/x/tools/go/ast/astutil" |
47 | "golang.org/x/tools/go/types/typeutil" |
48 | "golang.org/x/tools/internal/typeparams" |
49 | ) |
50 | |
51 | // A Constraint records the fact that the RHS type does and must |
52 | // satisfy the LHS type, which is an interface. |
53 | // The names are suggestive of an assignment statement LHS = RHS. |
54 | // |
55 | // The constraint is implicitly universally quantified over any type |
56 | // parameters appearing within the two types. |
57 | type 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. |
69 | type Finder struct { |
70 | Result map[Constraint]bool |
71 | msetcache typeutil.MethodSetCache |
72 | |
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 | // |
81 | // The result is non-canonical and thus may contain duplicates (but this |
82 | // tends to preserves names of interface types better). |
83 | // |
84 | // The package must be free of type errors, and |
85 | // info.{Defs,Uses,Selections,Types} must have been populated by the |
86 | // type-checker. |
87 | func (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 | |
115 | var ( |
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. |
122 | func (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) |
130 | sig := coreType(f.expr(e.Fun)).(*types.Signature) |
131 | f.call(sig, e.Args) |
132 | |
133 | case *ast.IndexExpr: |
134 | // y, ok := x[i] |
135 | x := f.expr(e.X) |
136 | f.assign(f.expr(e.Index), coreType(x).(*types.Map).Key()) |
137 | |
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 | |
152 | func (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 | |
201 | // builtin visits the arguments of a builtin type with signature sig. |
202 | func (f *Finder) builtin(obj *types.Builtin, sig *types.Signature, args []ast.Expr) { |
203 | 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) |
217 | tElem := coreType(s).(*types.Slice).Elem() |
218 | 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]) |
226 | f.assign(coreType(m).(*types.Map).Key(), k) |
227 | |
228 | default: |
229 | // ordinary call |
230 | f.call(sig, args) |
231 | } |
232 | } |
233 | |
234 | func (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 | |
241 | func (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). |
273 | func (f *Finder) assign(lhs, rhs types.Type) { |
274 | if types.Identical(lhs, rhs) { |
275 | return |
276 | } |
277 | if !isInterface(lhs) { |
278 | return |
279 | } |
280 | |
281 | if f.msetcache.MethodSet(lhs).Len() == 0 { |
282 | return |
283 | } |
284 | if f.msetcache.MethodSet(rhs).Len() == 0 { |
285 | return |
286 | } |
287 | // record the pair |
288 | f.Result[Constraint{lhs, rhs}] = true |
289 | } |
290 | |
291 | // typeAssert must be called for each type assertion x.(T) where x has |
292 | // interface type I. |
293 | func (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. |
314 | func (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. |
324 | func (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: |
358 | // No need for coreType here: go1.18 disallows P{...} for type param P. |
359 | switch T := deref(tv.Type).Underlying().(type) { |
360 | case *types.Struct: |
361 | for i, elem := range e.Elts { |
362 | if kv, ok := elem.(*ast.KeyValueExpr); ok { |
363 | f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value)) |
364 | } else { |
365 | f.assign(T.Field(i).Type(), f.expr(elem)) |
366 | } |
367 | } |
368 | |
369 | case *types.Map: |
370 | for _, elem := range e.Elts { |
371 | elem := elem.(*ast.KeyValueExpr) |
372 | f.assign(T.Key(), f.expr(elem.Key)) |
373 | f.assign(T.Elem(), f.expr(elem.Value)) |
374 | } |
375 | |
376 | case *types.Array, *types.Slice: |
377 | tElem := T.(interface { |
378 | Elem() types.Type |
379 | }).Elem() |
380 | for _, elem := range e.Elts { |
381 | if kv, ok := elem.(*ast.KeyValueExpr); ok { |
382 | // ignore the key |
383 | f.assign(tElem, f.expr(kv.Value)) |
384 | } else { |
385 | f.assign(tElem, f.expr(elem)) |
386 | } |
387 | } |
388 | |
389 | default: |
390 | panic("unexpected composite literal type: " + tv.Type.String()) |
391 | } |
392 | |
393 | case *ast.ParenExpr: |
394 | f.expr(e.X) |
395 | |
396 | case *ast.SelectorExpr: |
397 | if _, ok := f.info.Selections[e]; ok { |
398 | f.expr(e.X) // selection |
399 | } else { |
400 | return f.info.Uses[e.Sel].Type() // qualified identifier |
401 | } |
402 | |
403 | case *ast.IndexExpr: |
404 | if instance(f.info, e.X) { |
405 | // f[T] or C[T] -- generic instantiation |
406 | } else { |
407 | // x[i] or m[k] -- index or lookup operation |
408 | x := f.expr(e.X) |
409 | i := f.expr(e.Index) |
410 | if ux, ok := coreType(x).(*types.Map); ok { |
411 | f.assign(ux.Key(), i) |
412 | } |
413 | } |
414 | |
415 | case *typeparams.IndexListExpr: |
416 | // f[X, Y] -- generic instantiation |
417 | |
418 | case *ast.SliceExpr: |
419 | f.expr(e.X) |
420 | if e.Low != nil { |
421 | f.expr(e.Low) |
422 | } |
423 | if e.High != nil { |
424 | f.expr(e.High) |
425 | } |
426 | if e.Max != nil { |
427 | f.expr(e.Max) |
428 | } |
429 | |
430 | case *ast.TypeAssertExpr: |
431 | x := f.expr(e.X) |
432 | f.typeAssert(x, f.info.Types[e.Type].Type) |
433 | |
434 | case *ast.CallExpr: |
435 | if tvFun := f.info.Types[e.Fun]; tvFun.IsType() { |
436 | // conversion |
437 | arg0 := f.expr(e.Args[0]) |
438 | f.assign(tvFun.Type, arg0) |
439 | } else { |
440 | // function call |
441 | |
442 | // unsafe call. Treat calls to functions in unsafe like ordinary calls, |
443 | // except that their signature cannot be determined by their func obj. |
444 | // Without this special handling, f.expr(e.Fun) would fail below. |
445 | if s, ok := unparen(e.Fun).(*ast.SelectorExpr); ok { |
446 | if obj, ok := f.info.Uses[s.Sel].(*types.Builtin); ok && obj.Pkg().Path() == "unsafe" { |
447 | sig := f.info.Types[e.Fun].Type.(*types.Signature) |
448 | f.call(sig, e.Args) |
449 | return tv.Type |
450 | } |
451 | } |
452 | |
453 | // builtin call |
454 | if id, ok := unparen(e.Fun).(*ast.Ident); ok { |
455 | if obj, ok := f.info.Uses[id].(*types.Builtin); ok { |
456 | sig := f.info.Types[id].Type.(*types.Signature) |
457 | f.builtin(obj, sig, e.Args) |
458 | return tv.Type |
459 | } |
460 | } |
461 | |
462 | // ordinary call |
463 | f.call(coreType(f.expr(e.Fun)).(*types.Signature), e.Args) |
464 | } |
465 | |
466 | case *ast.StarExpr: |
467 | f.expr(e.X) |
468 | |
469 | case *ast.UnaryExpr: |
470 | f.expr(e.X) |
471 | |
472 | case *ast.BinaryExpr: |
473 | x := f.expr(e.X) |
474 | y := f.expr(e.Y) |
475 | if e.Op == token.EQL || e.Op == token.NEQ { |
476 | f.compare(x, y) |
477 | } |
478 | |
479 | case *ast.KeyValueExpr: |
480 | f.expr(e.Key) |
481 | f.expr(e.Value) |
482 | |
483 | case *ast.ArrayType, |
484 | *ast.StructType, |
485 | *ast.FuncType, |
486 | *ast.InterfaceType, |
487 | *ast.MapType, |
488 | *ast.ChanType: |
489 | panic(e) |
490 | } |
491 | |
492 | if tv.Type == nil { |
493 | panic(fmt.Sprintf("no type for %T", e)) |
494 | } |
495 | |
496 | return tv.Type |
497 | } |
498 | |
499 | func (f *Finder) stmt(s ast.Stmt) { |
500 | switch s := s.(type) { |
501 | case *ast.BadStmt, |
502 | *ast.EmptyStmt, |
503 | *ast.BranchStmt: |
504 | // no-op |
505 | |
506 | case *ast.DeclStmt: |
507 | d := s.Decl.(*ast.GenDecl) |
508 | if d.Tok == token.VAR { // ignore consts |
509 | for _, spec := range d.Specs { |
510 | f.valueSpec(spec.(*ast.ValueSpec)) |
511 | } |
512 | } |
513 | |
514 | case *ast.LabeledStmt: |
515 | f.stmt(s.Stmt) |
516 | |
517 | case *ast.ExprStmt: |
518 | f.expr(s.X) |
519 | |
520 | case *ast.SendStmt: |
521 | ch := f.expr(s.Chan) |
522 | val := f.expr(s.Value) |
523 | f.assign(coreType(ch).(*types.Chan).Elem(), val) |
524 | |
525 | case *ast.IncDecStmt: |
526 | f.expr(s.X) |
527 | |
528 | case *ast.AssignStmt: |
529 | switch s.Tok { |
530 | case token.ASSIGN, token.DEFINE: |
531 | // y := x or y = x |
532 | var rhsTuple types.Type |
533 | if len(s.Lhs) != len(s.Rhs) { |
534 | rhsTuple = f.exprN(s.Rhs[0]) |
535 | } |
536 | for i := range s.Lhs { |
537 | var lhs, rhs types.Type |
538 | if rhsTuple == nil { |
539 | rhs = f.expr(s.Rhs[i]) // 1:1 assignment |
540 | } else { |
541 | rhs = f.extract(rhsTuple, i) // n:1 assignment |
542 | } |
543 | |
544 | if id, ok := s.Lhs[i].(*ast.Ident); ok { |
545 | if id.Name != "_" { |
546 | if obj, ok := f.info.Defs[id]; ok { |
547 | lhs = obj.Type() // definition |
548 | } |
549 | } |
550 | } |
551 | if lhs == nil { |
552 | lhs = f.expr(s.Lhs[i]) // assignment |
553 | } |
554 | f.assign(lhs, rhs) |
555 | } |
556 | |
557 | default: |
558 | // y op= x |
559 | f.expr(s.Lhs[0]) |
560 | f.expr(s.Rhs[0]) |
561 | } |
562 | |
563 | case *ast.GoStmt: |
564 | f.expr(s.Call) |
565 | |
566 | case *ast.DeferStmt: |
567 | f.expr(s.Call) |
568 | |
569 | case *ast.ReturnStmt: |
570 | formals := f.sig.Results() |
571 | switch len(s.Results) { |
572 | case formals.Len(): // 1:1 |
573 | for i, result := range s.Results { |
574 | f.assign(formals.At(i).Type(), f.expr(result)) |
575 | } |
576 | |
577 | case 1: // n:1 |
578 | tuple := f.exprN(s.Results[0]) |
579 | for i := 0; i < formals.Len(); i++ { |
580 | f.assign(formals.At(i).Type(), f.extract(tuple, i)) |
581 | } |
582 | } |
583 | |
584 | case *ast.SelectStmt: |
585 | f.stmt(s.Body) |
586 | |
587 | case *ast.BlockStmt: |
588 | for _, s := range s.List { |
589 | f.stmt(s) |
590 | } |
591 | |
592 | case *ast.IfStmt: |
593 | if s.Init != nil { |
594 | f.stmt(s.Init) |
595 | } |
596 | f.expr(s.Cond) |
597 | f.stmt(s.Body) |
598 | if s.Else != nil { |
599 | f.stmt(s.Else) |
600 | } |
601 | |
602 | case *ast.SwitchStmt: |
603 | if s.Init != nil { |
604 | f.stmt(s.Init) |
605 | } |
606 | var tag types.Type = tUntypedBool |
607 | if s.Tag != nil { |
608 | tag = f.expr(s.Tag) |
609 | } |
610 | for _, cc := range s.Body.List { |
611 | cc := cc.(*ast.CaseClause) |
612 | for _, cond := range cc.List { |
613 | f.compare(tag, f.info.Types[cond].Type) |
614 | } |
615 | for _, s := range cc.Body { |
616 | f.stmt(s) |
617 | } |
618 | } |
619 | |
620 | case *ast.TypeSwitchStmt: |
621 | if s.Init != nil { |
622 | f.stmt(s.Init) |
623 | } |
624 | var I types.Type |
625 | switch ass := s.Assign.(type) { |
626 | case *ast.ExprStmt: // x.(type) |
627 | I = f.expr(unparen(ass.X).(*ast.TypeAssertExpr).X) |
628 | case *ast.AssignStmt: // y := x.(type) |
629 | I = f.expr(unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X) |
630 | } |
631 | for _, cc := range s.Body.List { |
632 | cc := cc.(*ast.CaseClause) |
633 | for _, cond := range cc.List { |
634 | tCase := f.info.Types[cond].Type |
635 | if tCase != tUntypedNil { |
636 | f.typeAssert(I, tCase) |
637 | } |
638 | } |
639 | for _, s := range cc.Body { |
640 | f.stmt(s) |
641 | } |
642 | } |
643 | |
644 | case *ast.CommClause: |
645 | if s.Comm != nil { |
646 | f.stmt(s.Comm) |
647 | } |
648 | for _, s := range s.Body { |
649 | f.stmt(s) |
650 | } |
651 | |
652 | case *ast.ForStmt: |
653 | if s.Init != nil { |
654 | f.stmt(s.Init) |
655 | } |
656 | if s.Cond != nil { |
657 | f.expr(s.Cond) |
658 | } |
659 | if s.Post != nil { |
660 | f.stmt(s.Post) |
661 | } |
662 | f.stmt(s.Body) |
663 | |
664 | case *ast.RangeStmt: |
665 | x := f.expr(s.X) |
666 | // No conversions are involved when Tok==DEFINE. |
667 | if s.Tok == token.ASSIGN { |
668 | if s.Key != nil { |
669 | k := f.expr(s.Key) |
670 | var xelem types.Type |
671 | // Keys of array, *array, slice, string aren't interesting |
672 | // since the RHS key type is just an int. |
673 | switch ux := coreType(x).(type) { |
674 | case *types.Chan: |
675 | xelem = ux.Elem() |
676 | case *types.Map: |
677 | xelem = ux.Key() |
678 | } |
679 | if xelem != nil { |
680 | f.assign(k, xelem) |
681 | } |
682 | } |
683 | if s.Value != nil { |
684 | val := f.expr(s.Value) |
685 | var xelem types.Type |
686 | // Values of type strings aren't interesting because |
687 | // the RHS value type is just a rune. |
688 | switch ux := coreType(x).(type) { |
689 | case *types.Array: |
690 | xelem = ux.Elem() |
691 | case *types.Map: |
692 | xelem = ux.Elem() |
693 | case *types.Pointer: // *array |
694 | xelem = coreType(deref(ux)).(*types.Array).Elem() |
695 | case *types.Slice: |
696 | xelem = ux.Elem() |
697 | } |
698 | if xelem != nil { |
699 | f.assign(val, xelem) |
700 | } |
701 | } |
702 | } |
703 | f.stmt(s.Body) |
704 | |
705 | default: |
706 | panic(s) |
707 | } |
708 | } |
709 | |
710 | // -- Plundered from golang.org/x/tools/go/ssa ----------------- |
711 | |
712 | // deref returns a pointer's element type; otherwise it returns typ. |
713 | func deref(typ types.Type) types.Type { |
714 | if p, ok := coreType(typ).(*types.Pointer); ok { |
715 | return p.Elem() |
716 | } |
717 | return typ |
718 | } |
719 | |
720 | func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } |
721 | |
722 | func isInterface(T types.Type) bool { return types.IsInterface(T) } |
723 | |
724 | func coreType(T types.Type) types.Type { return typeparams.CoreType(T) } |
725 | |
726 | func instance(info *types.Info, expr ast.Expr) bool { |
727 | var id *ast.Ident |
728 | switch x := expr.(type) { |
729 | case *ast.Ident: |
730 | id = x |
731 | case *ast.SelectorExpr: |
732 | id = x.Sel |
733 | default: |
734 | return false |
735 | } |
736 | _, ok := typeparams.GetInstances(info)[id] |
737 | return ok |
738 | } |
739 |
Members