Source file src/cmd/vendor/golang.org/x/tools/refactor/satisfy/find.go

     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/types/typeutil"
    47  	"golang.org/x/tools/internal/typeparams"
    48  )
    49  
    50  // A Constraint records the fact that the RHS type does and must
    51  // satisfy the LHS type, which is an interface.
    52  // The names are suggestive of an assignment statement LHS = RHS.
    53  //
    54  // The constraint is implicitly universally quantified over any type
    55  // parameters appearing within the two types.
    56  type Constraint struct {
    57  	LHS, RHS types.Type
    58  }
    59  
    60  // A Finder inspects the type-checked ASTs of Go packages and
    61  // accumulates the set of type constraints (x, y) such that x is
    62  // assignable to y, y is an interface, and both x and y have methods.
    63  //
    64  // In other words, it returns the subset of the "implements" relation
    65  // that is checked during compilation of a package.  Refactoring tools
    66  // will need to preserve at least this part of the relation to ensure
    67  // continued compilation.
    68  type Finder struct {
    69  	Result    map[Constraint]bool
    70  	msetcache typeutil.MethodSetCache
    71  
    72  	// per-Find state
    73  	info *types.Info
    74  	sig  *types.Signature
    75  }
    76  
    77  // Find inspects a single package, populating Result with its pairs of
    78  // constrained types.
    79  //
    80  // The result is non-canonical and thus may contain duplicates (but this
    81  // tends to preserves names of interface types better).
    82  //
    83  // The package must be free of type errors, and
    84  // info.{Defs,Uses,Selections,Types} must have been populated by the
    85  // type-checker.
    86  func (f *Finder) Find(info *types.Info, files []*ast.File) {
    87  	if info.Defs == nil || info.Uses == nil || info.Selections == nil || info.Types == nil {
    88  		panic("Finder.Find: one of info.{Defs,Uses,Selections.Types} is not populated")
    89  	}
    90  	if f.Result == nil {
    91  		f.Result = make(map[Constraint]bool)
    92  	}
    93  
    94  	f.info = info
    95  	for _, file := range files {
    96  		for _, d := range file.Decls {
    97  			switch d := d.(type) {
    98  			case *ast.GenDecl:
    99  				if d.Tok == token.VAR { // ignore consts
   100  					for _, spec := range d.Specs {
   101  						f.valueSpec(spec.(*ast.ValueSpec))
   102  					}
   103  				}
   104  
   105  			case *ast.FuncDecl:
   106  				if d.Body != nil {
   107  					f.sig = f.info.Defs[d.Name].Type().(*types.Signature)
   108  					f.stmt(d.Body)
   109  					f.sig = nil
   110  				}
   111  			}
   112  		}
   113  	}
   114  	f.info = nil
   115  }
   116  
   117  var (
   118  	tInvalid     = types.Typ[types.Invalid]
   119  	tUntypedBool = types.Typ[types.UntypedBool]
   120  	tUntypedNil  = types.Typ[types.UntypedNil]
   121  )
   122  
   123  // exprN visits an expression in a multi-value context.
   124  func (f *Finder) exprN(e ast.Expr) types.Type {
   125  	typ := f.info.Types[e].Type.(*types.Tuple)
   126  	switch e := e.(type) {
   127  	case *ast.ParenExpr:
   128  		return f.exprN(e.X)
   129  
   130  	case *ast.CallExpr:
   131  		// x, err := f(args)
   132  		sig := typeparams.CoreType(f.expr(e.Fun)).(*types.Signature)
   133  		f.call(sig, e.Args)
   134  
   135  	case *ast.IndexExpr:
   136  		// y, ok := x[i]
   137  		x := f.expr(e.X)
   138  		f.assign(f.expr(e.Index), typeparams.CoreType(x).(*types.Map).Key())
   139  
   140  	case *ast.TypeAssertExpr:
   141  		// y, ok := x.(T)
   142  		f.typeAssert(f.expr(e.X), typ.At(0).Type())
   143  
   144  	case *ast.UnaryExpr: // must be receive <-
   145  		// y, ok := <-x
   146  		f.expr(e.X)
   147  
   148  	default:
   149  		panic(e)
   150  	}
   151  	return typ
   152  }
   153  
   154  func (f *Finder) call(sig *types.Signature, args []ast.Expr) {
   155  	if len(args) == 0 {
   156  		return
   157  	}
   158  
   159  	// Ellipsis call?  e.g. f(x, y, z...)
   160  	if _, ok := args[len(args)-1].(*ast.Ellipsis); ok {
   161  		for i, arg := range args {
   162  			// The final arg is a slice, and so is the final param.
   163  			f.assign(sig.Params().At(i).Type(), f.expr(arg))
   164  		}
   165  		return
   166  	}
   167  
   168  	var argtypes []types.Type
   169  
   170  	// Gather the effective actual parameter types.
   171  	if tuple, ok := f.info.Types[args[0]].Type.(*types.Tuple); ok {
   172  		// f(g()) call where g has multiple results?
   173  		f.expr(args[0])
   174  		// unpack the tuple
   175  		for v := range tuple.Variables() {
   176  			argtypes = append(argtypes, v.Type())
   177  		}
   178  	} else {
   179  		for _, arg := range args {
   180  			argtypes = append(argtypes, f.expr(arg))
   181  		}
   182  	}
   183  
   184  	// Assign the actuals to the formals.
   185  	if !sig.Variadic() {
   186  		for i, argtype := range argtypes {
   187  			f.assign(sig.Params().At(i).Type(), argtype)
   188  		}
   189  	} else {
   190  		// The first n-1 parameters are assigned normally.
   191  		nnormals := sig.Params().Len() - 1
   192  		for i, argtype := range argtypes[:nnormals] {
   193  			f.assign(sig.Params().At(i).Type(), argtype)
   194  		}
   195  		// Remaining args are assigned to elements of varargs slice.
   196  		tElem := sig.Params().At(nnormals).Type().(*types.Slice).Elem()
   197  		for i := nnormals; i < len(argtypes); i++ {
   198  			f.assign(tElem, argtypes[i])
   199  		}
   200  	}
   201  }
   202  
   203  // builtin visits the arguments of a builtin type with signature sig.
   204  func (f *Finder) builtin(obj *types.Builtin, sig *types.Signature, args []ast.Expr) {
   205  	switch obj.Name() {
   206  	case "make", "new":
   207  		for i, arg := range args {
   208  			if i == 0 && f.info.Types[arg].IsType() {
   209  				continue // skip the type operand
   210  			}
   211  			f.expr(arg)
   212  		}
   213  
   214  	case "append":
   215  		s := f.expr(args[0])
   216  		if _, ok := args[len(args)-1].(*ast.Ellipsis); ok && len(args) == 2 {
   217  			// append(x, y...)   including append([]byte, "foo"...)
   218  			f.expr(args[1])
   219  		} else {
   220  			// append(x, y, z)
   221  			tElem := typeparams.CoreType(s).(*types.Slice).Elem()
   222  			for _, arg := range args[1:] {
   223  				f.assign(tElem, f.expr(arg))
   224  			}
   225  		}
   226  
   227  	case "delete":
   228  		m := f.expr(args[0])
   229  		k := f.expr(args[1])
   230  		f.assign(typeparams.CoreType(m).(*types.Map).Key(), k)
   231  
   232  	default:
   233  		// ordinary call
   234  		f.call(sig, args)
   235  	}
   236  }
   237  
   238  func (f *Finder) extract(tuple types.Type, i int) types.Type {
   239  	if tuple, ok := tuple.(*types.Tuple); ok && i < tuple.Len() {
   240  		return tuple.At(i).Type()
   241  	}
   242  	return tInvalid
   243  }
   244  
   245  func (f *Finder) valueSpec(spec *ast.ValueSpec) {
   246  	var T types.Type
   247  	if spec.Type != nil {
   248  		T = f.info.Types[spec.Type].Type
   249  	}
   250  	switch len(spec.Values) {
   251  	case len(spec.Names): // e.g. var x, y = f(), g()
   252  		for _, value := range spec.Values {
   253  			v := f.expr(value)
   254  			if T != nil {
   255  				f.assign(T, v)
   256  			}
   257  		}
   258  
   259  	case 1: // e.g. var x, y = f()
   260  		tuple := f.exprN(spec.Values[0])
   261  		for i := range spec.Names {
   262  			if T != nil {
   263  				f.assign(T, f.extract(tuple, i))
   264  			}
   265  		}
   266  	}
   267  }
   268  
   269  // assign records pairs of distinct types that are related by
   270  // assignability, where the left-hand side is an interface and both
   271  // sides have methods.
   272  //
   273  // It should be called for all assignability checks, type assertions,
   274  // explicit conversions and comparisons between two types, unless the
   275  // types are uninteresting (e.g. lhs is a concrete type, or the empty
   276  // interface; rhs has no methods).
   277  func (f *Finder) assign(lhs, rhs types.Type) {
   278  	if types.Identical(lhs, rhs) {
   279  		return
   280  	}
   281  	if !types.IsInterface(lhs) {
   282  		return
   283  	}
   284  
   285  	if f.msetcache.MethodSet(lhs).Len() == 0 {
   286  		return
   287  	}
   288  	if f.msetcache.MethodSet(rhs).Len() == 0 {
   289  		return
   290  	}
   291  	// record the pair
   292  	f.Result[Constraint{lhs, rhs}] = true
   293  }
   294  
   295  // typeAssert must be called for each type assertion x.(T) where x has
   296  // interface type I.
   297  func (f *Finder) typeAssert(I, T types.Type) {
   298  	// Type assertions are slightly subtle, because they are allowed
   299  	// to be "impossible", e.g.
   300  	//
   301  	// 	var x interface{f()}
   302  	//	_ = x.(interface{f()int}) // legal
   303  	//
   304  	// (In hindsight, the language spec should probably not have
   305  	// allowed this, but it's too late to fix now.)
   306  	//
   307  	// This means that a type assert from I to T isn't exactly a
   308  	// constraint that T is assignable to I, but for a refactoring
   309  	// tool it is a conditional constraint that, if T is assignable
   310  	// to I before a refactoring, it should remain so after.
   311  
   312  	if types.AssignableTo(T, I) {
   313  		f.assign(I, T)
   314  	}
   315  }
   316  
   317  // compare must be called for each comparison x==y.
   318  func (f *Finder) compare(x, y types.Type) {
   319  	if types.AssignableTo(x, y) {
   320  		f.assign(y, x)
   321  	} else if types.AssignableTo(y, x) {
   322  		f.assign(x, y)
   323  	}
   324  }
   325  
   326  // expr visits a true expression (not a type or defining ident)
   327  // and returns its type.
   328  func (f *Finder) expr(e ast.Expr) types.Type {
   329  	tv := f.info.Types[e]
   330  	if tv.Value != nil {
   331  		return tv.Type // prune the descent for constants
   332  	}
   333  
   334  	// tv.Type may be nil for an ast.Ident.
   335  
   336  	switch e := e.(type) {
   337  	case *ast.BadExpr, *ast.BasicLit:
   338  		// no-op
   339  
   340  	case *ast.Ident:
   341  		// (referring idents only)
   342  		if obj, ok := f.info.Uses[e]; ok {
   343  			return obj.Type()
   344  		}
   345  		if e.Name == "_" { // e.g. "for _ = range x"
   346  			return tInvalid
   347  		}
   348  		panic("undefined ident: " + e.Name)
   349  
   350  	case *ast.Ellipsis:
   351  		if e.Elt != nil {
   352  			f.expr(e.Elt)
   353  		}
   354  
   355  	case *ast.FuncLit:
   356  		saved := f.sig
   357  		f.sig = tv.Type.(*types.Signature)
   358  		f.stmt(e.Body)
   359  		f.sig = saved
   360  
   361  	case *ast.CompositeLit:
   362  		switch T := typeparams.CoreType(typeparams.Deref(tv.Type)).(type) {
   363  		case *types.Struct:
   364  			for i, elem := range e.Elts {
   365  				if kv, ok := elem.(*ast.KeyValueExpr); ok {
   366  					f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value))
   367  				} else {
   368  					f.assign(T.Field(i).Type(), f.expr(elem))
   369  				}
   370  			}
   371  
   372  		case *types.Map:
   373  			for _, elem := range e.Elts {
   374  				elem := elem.(*ast.KeyValueExpr)
   375  				f.assign(T.Key(), f.expr(elem.Key))
   376  				f.assign(T.Elem(), f.expr(elem.Value))
   377  			}
   378  
   379  		case *types.Array, *types.Slice:
   380  			tElem := T.(interface {
   381  				Elem() types.Type
   382  			}).Elem()
   383  			for _, elem := range e.Elts {
   384  				if kv, ok := elem.(*ast.KeyValueExpr); ok {
   385  					// ignore the key
   386  					f.assign(tElem, f.expr(kv.Value))
   387  				} else {
   388  					f.assign(tElem, f.expr(elem))
   389  				}
   390  			}
   391  
   392  		default:
   393  			panic(fmt.Sprintf("unexpected composite literal type %T: %v", tv.Type, tv.Type.String()))
   394  		}
   395  
   396  	case *ast.ParenExpr:
   397  		f.expr(e.X)
   398  
   399  	case *ast.SelectorExpr:
   400  		if _, ok := f.info.Selections[e]; ok {
   401  			f.expr(e.X) // selection
   402  		} else {
   403  			return f.info.Uses[e.Sel].Type() // qualified identifier
   404  		}
   405  
   406  	case *ast.IndexExpr:
   407  		if instance(f.info, e.X) {
   408  			// f[T] or C[T] -- generic instantiation
   409  		} else {
   410  			// x[i] or m[k] -- index or lookup operation
   411  			x := f.expr(e.X)
   412  			i := f.expr(e.Index)
   413  			if ux, ok := typeparams.CoreType(x).(*types.Map); ok {
   414  				f.assign(ux.Key(), i)
   415  			}
   416  		}
   417  
   418  	case *ast.IndexListExpr:
   419  		// f[X, Y] -- generic instantiation
   420  
   421  	case *ast.SliceExpr:
   422  		f.expr(e.X)
   423  		if e.Low != nil {
   424  			f.expr(e.Low)
   425  		}
   426  		if e.High != nil {
   427  			f.expr(e.High)
   428  		}
   429  		if e.Max != nil {
   430  			f.expr(e.Max)
   431  		}
   432  
   433  	case *ast.TypeAssertExpr:
   434  		x := f.expr(e.X)
   435  		f.typeAssert(x, f.info.Types[e.Type].Type)
   436  
   437  	case *ast.CallExpr:
   438  		if tvFun := f.info.Types[e.Fun]; tvFun.IsType() {
   439  			// conversion
   440  			arg0 := f.expr(e.Args[0])
   441  			f.assign(tvFun.Type, arg0)
   442  		} else {
   443  			// function call
   444  
   445  			// unsafe call. Treat calls to functions in unsafe like ordinary calls,
   446  			// except that their signature cannot be determined by their func obj.
   447  			// Without this special handling, f.expr(e.Fun) would fail below.
   448  			if s, ok := ast.Unparen(e.Fun).(*ast.SelectorExpr); ok {
   449  				if obj, ok := f.info.Uses[s.Sel].(*types.Builtin); ok && obj.Pkg().Path() == "unsafe" {
   450  					sig := f.info.Types[e.Fun].Type.(*types.Signature)
   451  					f.call(sig, e.Args)
   452  					return tv.Type
   453  				}
   454  			}
   455  
   456  			// builtin call
   457  			if id, ok := ast.Unparen(e.Fun).(*ast.Ident); ok {
   458  				if obj, ok := f.info.Uses[id].(*types.Builtin); ok {
   459  					sig := f.info.Types[id].Type.(*types.Signature)
   460  					f.builtin(obj, sig, e.Args)
   461  					return tv.Type
   462  				}
   463  			}
   464  
   465  			// ordinary call
   466  			f.call(typeparams.CoreType(f.expr(e.Fun)).(*types.Signature), e.Args)
   467  		}
   468  
   469  	case *ast.StarExpr:
   470  		f.expr(e.X)
   471  
   472  	case *ast.UnaryExpr:
   473  		f.expr(e.X)
   474  
   475  	case *ast.BinaryExpr:
   476  		x := f.expr(e.X)
   477  		y := f.expr(e.Y)
   478  		if e.Op == token.EQL || e.Op == token.NEQ {
   479  			f.compare(x, y)
   480  		}
   481  
   482  	case *ast.KeyValueExpr:
   483  		f.expr(e.Key)
   484  		f.expr(e.Value)
   485  
   486  	case *ast.ArrayType,
   487  		*ast.StructType,
   488  		*ast.FuncType,
   489  		*ast.InterfaceType,
   490  		*ast.MapType,
   491  		*ast.ChanType:
   492  		panic(e)
   493  	}
   494  
   495  	if tv.Type == nil {
   496  		panic(fmt.Sprintf("no type for %T", e))
   497  	}
   498  
   499  	return tv.Type
   500  }
   501  
   502  func (f *Finder) stmt(s ast.Stmt) {
   503  	switch s := s.(type) {
   504  	case *ast.BadStmt,
   505  		*ast.EmptyStmt,
   506  		*ast.BranchStmt:
   507  		// no-op
   508  
   509  	case *ast.DeclStmt:
   510  		d := s.Decl.(*ast.GenDecl)
   511  		if d.Tok == token.VAR { // ignore consts
   512  			for _, spec := range d.Specs {
   513  				f.valueSpec(spec.(*ast.ValueSpec))
   514  			}
   515  		}
   516  
   517  	case *ast.LabeledStmt:
   518  		f.stmt(s.Stmt)
   519  
   520  	case *ast.ExprStmt:
   521  		f.expr(s.X)
   522  
   523  	case *ast.SendStmt:
   524  		ch := f.expr(s.Chan)
   525  		val := f.expr(s.Value)
   526  		f.assign(typeparams.CoreType(ch).(*types.Chan).Elem(), val)
   527  
   528  	case *ast.IncDecStmt:
   529  		f.expr(s.X)
   530  
   531  	case *ast.AssignStmt:
   532  		switch s.Tok {
   533  		case token.ASSIGN, token.DEFINE:
   534  			// y := x   or   y = x
   535  			var rhsTuple types.Type
   536  			if len(s.Lhs) != len(s.Rhs) {
   537  				rhsTuple = f.exprN(s.Rhs[0])
   538  			}
   539  			for i := range s.Lhs {
   540  				var lhs, rhs types.Type
   541  				if rhsTuple == nil {
   542  					rhs = f.expr(s.Rhs[i]) // 1:1 assignment
   543  				} else {
   544  					rhs = f.extract(rhsTuple, i) // n:1 assignment
   545  				}
   546  
   547  				if id, ok := s.Lhs[i].(*ast.Ident); ok {
   548  					if id.Name != "_" {
   549  						if obj, ok := f.info.Defs[id]; ok {
   550  							lhs = obj.Type() // definition
   551  						}
   552  					}
   553  				}
   554  				if lhs == nil {
   555  					lhs = f.expr(s.Lhs[i]) // assignment
   556  				}
   557  				f.assign(lhs, rhs)
   558  			}
   559  
   560  		default:
   561  			// y op= x
   562  			f.expr(s.Lhs[0])
   563  			f.expr(s.Rhs[0])
   564  		}
   565  
   566  	case *ast.GoStmt:
   567  		f.expr(s.Call)
   568  
   569  	case *ast.DeferStmt:
   570  		f.expr(s.Call)
   571  
   572  	case *ast.ReturnStmt:
   573  		formals := f.sig.Results()
   574  		switch len(s.Results) {
   575  		case formals.Len(): // 1:1
   576  			for i, result := range s.Results {
   577  				f.assign(formals.At(i).Type(), f.expr(result))
   578  			}
   579  
   580  		case 1: // n:1
   581  			tuple := f.exprN(s.Results[0])
   582  			for i := 0; i < formals.Len(); i++ {
   583  				f.assign(formals.At(i).Type(), f.extract(tuple, i))
   584  			}
   585  		}
   586  
   587  	case *ast.SelectStmt:
   588  		f.stmt(s.Body)
   589  
   590  	case *ast.BlockStmt:
   591  		for _, s := range s.List {
   592  			f.stmt(s)
   593  		}
   594  
   595  	case *ast.IfStmt:
   596  		if s.Init != nil {
   597  			f.stmt(s.Init)
   598  		}
   599  		f.expr(s.Cond)
   600  		f.stmt(s.Body)
   601  		if s.Else != nil {
   602  			f.stmt(s.Else)
   603  		}
   604  
   605  	case *ast.SwitchStmt:
   606  		if s.Init != nil {
   607  			f.stmt(s.Init)
   608  		}
   609  		var tag types.Type = tUntypedBool
   610  		if s.Tag != nil {
   611  			tag = f.expr(s.Tag)
   612  		}
   613  		for _, cc := range s.Body.List {
   614  			cc := cc.(*ast.CaseClause)
   615  			for _, cond := range cc.List {
   616  				f.compare(tag, f.info.Types[cond].Type)
   617  			}
   618  			for _, s := range cc.Body {
   619  				f.stmt(s)
   620  			}
   621  		}
   622  
   623  	case *ast.TypeSwitchStmt:
   624  		if s.Init != nil {
   625  			f.stmt(s.Init)
   626  		}
   627  		var I types.Type
   628  		switch ass := s.Assign.(type) {
   629  		case *ast.ExprStmt: // x.(type)
   630  			I = f.expr(ast.Unparen(ass.X).(*ast.TypeAssertExpr).X)
   631  		case *ast.AssignStmt: // y := x.(type)
   632  			I = f.expr(ast.Unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
   633  		}
   634  		for _, cc := range s.Body.List {
   635  			cc := cc.(*ast.CaseClause)
   636  			for _, cond := range cc.List {
   637  				tCase := f.info.Types[cond].Type
   638  				if tCase != tUntypedNil {
   639  					f.typeAssert(I, tCase)
   640  				}
   641  			}
   642  			for _, s := range cc.Body {
   643  				f.stmt(s)
   644  			}
   645  		}
   646  
   647  	case *ast.CommClause:
   648  		if s.Comm != nil {
   649  			f.stmt(s.Comm)
   650  		}
   651  		for _, s := range s.Body {
   652  			f.stmt(s)
   653  		}
   654  
   655  	case *ast.ForStmt:
   656  		if s.Init != nil {
   657  			f.stmt(s.Init)
   658  		}
   659  		if s.Cond != nil {
   660  			f.expr(s.Cond)
   661  		}
   662  		if s.Post != nil {
   663  			f.stmt(s.Post)
   664  		}
   665  		f.stmt(s.Body)
   666  
   667  	case *ast.RangeStmt:
   668  		x := f.expr(s.X)
   669  		// No conversions are involved when Tok==DEFINE.
   670  		if s.Tok == token.ASSIGN {
   671  			if s.Key != nil {
   672  				k := f.expr(s.Key)
   673  				var xelem types.Type
   674  				// Keys of array, *array, slice, string aren't interesting
   675  				// since the RHS key type is just an int.
   676  				switch ux := typeparams.CoreType(x).(type) {
   677  				case *types.Chan:
   678  					xelem = ux.Elem()
   679  				case *types.Map:
   680  					xelem = ux.Key()
   681  				}
   682  				if xelem != nil {
   683  					f.assign(k, xelem)
   684  				}
   685  			}
   686  			if s.Value != nil {
   687  				val := f.expr(s.Value)
   688  				var xelem types.Type
   689  				// Values of type strings aren't interesting because
   690  				// the RHS value type is just a rune.
   691  				switch ux := typeparams.CoreType(x).(type) {
   692  				case *types.Array:
   693  					xelem = ux.Elem()
   694  				case *types.Map:
   695  					xelem = ux.Elem()
   696  				case *types.Pointer: // *array
   697  					xelem = typeparams.CoreType(typeparams.Deref(ux)).(*types.Array).Elem()
   698  				case *types.Slice:
   699  					xelem = ux.Elem()
   700  				}
   701  				if xelem != nil {
   702  					f.assign(val, xelem)
   703  				}
   704  			}
   705  		}
   706  		f.stmt(s.Body)
   707  
   708  	default:
   709  		panic(s)
   710  	}
   711  }
   712  
   713  // -- Plundered from golang.org/x/tools/go/ssa -----------------
   714  
   715  func instance(info *types.Info, expr ast.Expr) bool {
   716  	var id *ast.Ident
   717  	switch x := expr.(type) {
   718  	case *ast.Ident:
   719  		id = x
   720  	case *ast.SelectorExpr:
   721  		id = x.Sel
   722  	default:
   723  		return false
   724  	}
   725  	_, ok := info.Instances[id]
   726  	return ok
   727  }
   728  

View as plain text