github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/fix/typecheck.go (about)

     1  // Copyright 2011 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 main
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/token"
    11  	"os"
    12  	"reflect"
    13  	"strings"
    14  )
    15  
    16  // Partial type checker.
    17  //
    18  // The fact that it is partial is very important: the input is
    19  // an AST and a description of some type information to
    20  // assume about one or more packages, but not all the
    21  // packages that the program imports.  The checker is
    22  // expected to do as much as it can with what it has been
    23  // given.  There is not enough information supplied to do
    24  // a full type check, but the type checker is expected to
    25  // apply information that can be derived from variable
    26  // declarations, function and method returns, and type switches
    27  // as far as it can, so that the caller can still tell the types
    28  // of expression relevant to a particular fix.
    29  //
    30  // TODO(rsc,gri): Replace with go/typechecker.
    31  // Doing that could be an interesting test case for go/typechecker:
    32  // the constraints about working with partial information will
    33  // likely exercise it in interesting ways.  The ideal interface would
    34  // be to pass typecheck a map from importpath to package API text
    35  // (Go source code), but for now we use data structures (TypeConfig, Type).
    36  //
    37  // The strings mostly use gofmt form.
    38  //
    39  // A Field or FieldList has as its type a comma-separated list
    40  // of the types of the fields.  For example, the field list
    41  //	x, y, z int
    42  // has type "int, int, int".
    43  
    44  // The prefix "type " is the type of a type.
    45  // For example, given
    46  //	var x int
    47  //	type T int
    48  // x's type is "int" but T's type is "type int".
    49  // mkType inserts the "type " prefix.
    50  // getType removes it.
    51  // isType tests for it.
    52  
    53  func mkType(t string) string {
    54  	return "type " + t
    55  }
    56  
    57  func getType(t string) string {
    58  	if !isType(t) {
    59  		return ""
    60  	}
    61  	return t[len("type "):]
    62  }
    63  
    64  func isType(t string) bool {
    65  	return strings.HasPrefix(t, "type ")
    66  }
    67  
    68  // TypeConfig describes the universe of relevant types.
    69  // For ease of creation, the types are all referred to by string
    70  // name (e.g., "reflect.Value").  TypeByName is the only place
    71  // where the strings are resolved.
    72  
    73  type TypeConfig struct {
    74  	Type map[string]*Type
    75  	Var  map[string]string
    76  	Func map[string]string
    77  }
    78  
    79  // typeof returns the type of the given name, which may be of
    80  // the form "x" or "p.X".
    81  func (cfg *TypeConfig) typeof(name string) string {
    82  	if cfg.Var != nil {
    83  		if t := cfg.Var[name]; t != "" {
    84  			return t
    85  		}
    86  	}
    87  	if cfg.Func != nil {
    88  		if t := cfg.Func[name]; t != "" {
    89  			return "func()" + t
    90  		}
    91  	}
    92  	return ""
    93  }
    94  
    95  // Type describes the Fields and Methods of a type.
    96  // If the field or method cannot be found there, it is next
    97  // looked for in the Embed list.
    98  type Type struct {
    99  	Field  map[string]string // map field name to type
   100  	Method map[string]string // map method name to comma-separated return types (should start with "func ")
   101  	Embed  []string          // list of types this type embeds (for extra methods)
   102  	Def    string            // definition of named type
   103  }
   104  
   105  // dot returns the type of "typ.name", making its decision
   106  // using the type information in cfg.
   107  func (typ *Type) dot(cfg *TypeConfig, name string) string {
   108  	if typ.Field != nil {
   109  		if t := typ.Field[name]; t != "" {
   110  			return t
   111  		}
   112  	}
   113  	if typ.Method != nil {
   114  		if t := typ.Method[name]; t != "" {
   115  			return t
   116  		}
   117  	}
   118  
   119  	for _, e := range typ.Embed {
   120  		etyp := cfg.Type[e]
   121  		if etyp != nil {
   122  			if t := etyp.dot(cfg, name); t != "" {
   123  				return t
   124  			}
   125  		}
   126  	}
   127  
   128  	return ""
   129  }
   130  
   131  // typecheck type checks the AST f assuming the information in cfg.
   132  // It returns two maps with type information:
   133  // typeof maps AST nodes to type information in gofmt string form.
   134  // assign maps type strings to lists of expressions that were assigned
   135  // to values of another type that were assigned to that type.
   136  func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) {
   137  	typeof = make(map[interface{}]string)
   138  	assign = make(map[string][]interface{})
   139  	cfg1 := &TypeConfig{}
   140  	*cfg1 = *cfg // make copy so we can add locally
   141  	copied := false
   142  
   143  	// gather function declarations
   144  	for _, decl := range f.Decls {
   145  		fn, ok := decl.(*ast.FuncDecl)
   146  		if !ok {
   147  			continue
   148  		}
   149  		typecheck1(cfg, fn.Type, typeof, assign)
   150  		t := typeof[fn.Type]
   151  		if fn.Recv != nil {
   152  			// The receiver must be a type.
   153  			rcvr := typeof[fn.Recv]
   154  			if !isType(rcvr) {
   155  				if len(fn.Recv.List) != 1 {
   156  					continue
   157  				}
   158  				rcvr = mkType(gofmt(fn.Recv.List[0].Type))
   159  				typeof[fn.Recv.List[0].Type] = rcvr
   160  			}
   161  			rcvr = getType(rcvr)
   162  			if rcvr != "" && rcvr[0] == '*' {
   163  				rcvr = rcvr[1:]
   164  			}
   165  			typeof[rcvr+"."+fn.Name.Name] = t
   166  		} else {
   167  			if isType(t) {
   168  				t = getType(t)
   169  			} else {
   170  				t = gofmt(fn.Type)
   171  			}
   172  			typeof[fn.Name] = t
   173  
   174  			// Record typeof[fn.Name.Obj] for future references to fn.Name.
   175  			typeof[fn.Name.Obj] = t
   176  		}
   177  	}
   178  
   179  	// gather struct declarations
   180  	for _, decl := range f.Decls {
   181  		d, ok := decl.(*ast.GenDecl)
   182  		if ok {
   183  			for _, s := range d.Specs {
   184  				switch s := s.(type) {
   185  				case *ast.TypeSpec:
   186  					if cfg1.Type[s.Name.Name] != nil {
   187  						break
   188  					}
   189  					if !copied {
   190  						copied = true
   191  						// Copy map lazily: it's time.
   192  						cfg1.Type = make(map[string]*Type)
   193  						for k, v := range cfg.Type {
   194  							cfg1.Type[k] = v
   195  						}
   196  					}
   197  					t := &Type{Field: map[string]string{}}
   198  					cfg1.Type[s.Name.Name] = t
   199  					switch st := s.Type.(type) {
   200  					case *ast.StructType:
   201  						for _, f := range st.Fields.List {
   202  							for _, n := range f.Names {
   203  								t.Field[n.Name] = gofmt(f.Type)
   204  							}
   205  						}
   206  					case *ast.ArrayType, *ast.StarExpr, *ast.MapType:
   207  						t.Def = gofmt(st)
   208  					}
   209  				}
   210  			}
   211  		}
   212  	}
   213  
   214  	typecheck1(cfg1, f, typeof, assign)
   215  	return typeof, assign
   216  }
   217  
   218  func makeExprList(a []*ast.Ident) []ast.Expr {
   219  	var b []ast.Expr
   220  	for _, x := range a {
   221  		b = append(b, x)
   222  	}
   223  	return b
   224  }
   225  
   226  // Typecheck1 is the recursive form of typecheck.
   227  // It is like typecheck but adds to the information in typeof
   228  // instead of allocating a new map.
   229  func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, assign map[string][]interface{}) {
   230  	// set sets the type of n to typ.
   231  	// If isDecl is true, n is being declared.
   232  	set := func(n ast.Expr, typ string, isDecl bool) {
   233  		if typeof[n] != "" || typ == "" {
   234  			if typeof[n] != typ {
   235  				assign[typ] = append(assign[typ], n)
   236  			}
   237  			return
   238  		}
   239  		typeof[n] = typ
   240  
   241  		// If we obtained typ from the declaration of x
   242  		// propagate the type to all the uses.
   243  		// The !isDecl case is a cheat here, but it makes
   244  		// up in some cases for not paying attention to
   245  		// struct fields.  The real type checker will be
   246  		// more accurate so we won't need the cheat.
   247  		if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") {
   248  			typeof[id.Obj] = typ
   249  		}
   250  	}
   251  
   252  	// Type-check an assignment lhs = rhs.
   253  	// If isDecl is true, this is := so we can update
   254  	// the types of the objects that lhs refers to.
   255  	typecheckAssign := func(lhs, rhs []ast.Expr, isDecl bool) {
   256  		if len(lhs) > 1 && len(rhs) == 1 {
   257  			if _, ok := rhs[0].(*ast.CallExpr); ok {
   258  				t := split(typeof[rhs[0]])
   259  				// Lists should have same length but may not; pair what can be paired.
   260  				for i := 0; i < len(lhs) && i < len(t); i++ {
   261  					set(lhs[i], t[i], isDecl)
   262  				}
   263  				return
   264  			}
   265  		}
   266  		if len(lhs) == 1 && len(rhs) == 2 {
   267  			// x = y, ok
   268  			rhs = rhs[:1]
   269  		} else if len(lhs) == 2 && len(rhs) == 1 {
   270  			// x, ok = y
   271  			lhs = lhs[:1]
   272  		}
   273  
   274  		// Match as much as we can.
   275  		for i := 0; i < len(lhs) && i < len(rhs); i++ {
   276  			x, y := lhs[i], rhs[i]
   277  			if typeof[y] != "" {
   278  				set(x, typeof[y], isDecl)
   279  			} else {
   280  				set(y, typeof[x], false)
   281  			}
   282  		}
   283  	}
   284  
   285  	expand := func(s string) string {
   286  		typ := cfg.Type[s]
   287  		if typ != nil && typ.Def != "" {
   288  			return typ.Def
   289  		}
   290  		return s
   291  	}
   292  
   293  	// The main type check is a recursive algorithm implemented
   294  	// by walkBeforeAfter(n, before, after).
   295  	// Most of it is bottom-up, but in a few places we need
   296  	// to know the type of the function we are checking.
   297  	// The before function records that information on
   298  	// the curfn stack.
   299  	var curfn []*ast.FuncType
   300  
   301  	before := func(n interface{}) {
   302  		// push function type on stack
   303  		switch n := n.(type) {
   304  		case *ast.FuncDecl:
   305  			curfn = append(curfn, n.Type)
   306  		case *ast.FuncLit:
   307  			curfn = append(curfn, n.Type)
   308  		}
   309  	}
   310  
   311  	// After is the real type checker.
   312  	after := func(n interface{}) {
   313  		if n == nil {
   314  			return
   315  		}
   316  		if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace
   317  			defer func() {
   318  				if t := typeof[n]; t != "" {
   319  					pos := fset.Position(n.(ast.Node).Pos())
   320  					fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos, gofmt(n), t)
   321  				}
   322  			}()
   323  		}
   324  
   325  		switch n := n.(type) {
   326  		case *ast.FuncDecl, *ast.FuncLit:
   327  			// pop function type off stack
   328  			curfn = curfn[:len(curfn)-1]
   329  
   330  		case *ast.FuncType:
   331  			typeof[n] = mkType(joinFunc(split(typeof[n.Params]), split(typeof[n.Results])))
   332  
   333  		case *ast.FieldList:
   334  			// Field list is concatenation of sub-lists.
   335  			t := ""
   336  			for _, field := range n.List {
   337  				if t != "" {
   338  					t += ", "
   339  				}
   340  				t += typeof[field]
   341  			}
   342  			typeof[n] = t
   343  
   344  		case *ast.Field:
   345  			// Field is one instance of the type per name.
   346  			all := ""
   347  			t := typeof[n.Type]
   348  			if !isType(t) {
   349  				// Create a type, because it is typically *T or *p.T
   350  				// and we might care about that type.
   351  				t = mkType(gofmt(n.Type))
   352  				typeof[n.Type] = t
   353  			}
   354  			t = getType(t)
   355  			if len(n.Names) == 0 {
   356  				all = t
   357  			} else {
   358  				for _, id := range n.Names {
   359  					if all != "" {
   360  						all += ", "
   361  					}
   362  					all += t
   363  					typeof[id.Obj] = t
   364  					typeof[id] = t
   365  				}
   366  			}
   367  			typeof[n] = all
   368  
   369  		case *ast.ValueSpec:
   370  			// var declaration.  Use type if present.
   371  			if n.Type != nil {
   372  				t := typeof[n.Type]
   373  				if !isType(t) {
   374  					t = mkType(gofmt(n.Type))
   375  					typeof[n.Type] = t
   376  				}
   377  				t = getType(t)
   378  				for _, id := range n.Names {
   379  					set(id, t, true)
   380  				}
   381  			}
   382  			// Now treat same as assignment.
   383  			typecheckAssign(makeExprList(n.Names), n.Values, true)
   384  
   385  		case *ast.AssignStmt:
   386  			typecheckAssign(n.Lhs, n.Rhs, n.Tok == token.DEFINE)
   387  
   388  		case *ast.Ident:
   389  			// Identifier can take its type from underlying object.
   390  			if t := typeof[n.Obj]; t != "" {
   391  				typeof[n] = t
   392  			}
   393  
   394  		case *ast.SelectorExpr:
   395  			// Field or method.
   396  			name := n.Sel.Name
   397  			if t := typeof[n.X]; t != "" {
   398  				t = strings.TrimPrefix(t, "*") // implicit *
   399  				if typ := cfg.Type[t]; typ != nil {
   400  					if t := typ.dot(cfg, name); t != "" {
   401  						typeof[n] = t
   402  						return
   403  					}
   404  				}
   405  				tt := typeof[t+"."+name]
   406  				if isType(tt) {
   407  					typeof[n] = getType(tt)
   408  					return
   409  				}
   410  			}
   411  			// Package selector.
   412  			if x, ok := n.X.(*ast.Ident); ok && x.Obj == nil {
   413  				str := x.Name + "." + name
   414  				if cfg.Type[str] != nil {
   415  					typeof[n] = mkType(str)
   416  					return
   417  				}
   418  				if t := cfg.typeof(x.Name + "." + name); t != "" {
   419  					typeof[n] = t
   420  					return
   421  				}
   422  			}
   423  
   424  		case *ast.CallExpr:
   425  			// make(T) has type T.
   426  			if isTopName(n.Fun, "make") && len(n.Args) >= 1 {
   427  				typeof[n] = gofmt(n.Args[0])
   428  				return
   429  			}
   430  			// new(T) has type *T
   431  			if isTopName(n.Fun, "new") && len(n.Args) == 1 {
   432  				typeof[n] = "*" + gofmt(n.Args[0])
   433  				return
   434  			}
   435  			// Otherwise, use type of function to determine arguments.
   436  			t := typeof[n.Fun]
   437  			in, out := splitFunc(t)
   438  			if in == nil && out == nil {
   439  				return
   440  			}
   441  			typeof[n] = join(out)
   442  			for i, arg := range n.Args {
   443  				if i >= len(in) {
   444  					break
   445  				}
   446  				if typeof[arg] == "" {
   447  					typeof[arg] = in[i]
   448  				}
   449  			}
   450  
   451  		case *ast.TypeAssertExpr:
   452  			// x.(type) has type of x.
   453  			if n.Type == nil {
   454  				typeof[n] = typeof[n.X]
   455  				return
   456  			}
   457  			// x.(T) has type T.
   458  			if t := typeof[n.Type]; isType(t) {
   459  				typeof[n] = getType(t)
   460  			} else {
   461  				typeof[n] = gofmt(n.Type)
   462  			}
   463  
   464  		case *ast.SliceExpr:
   465  			// x[i:j] has type of x.
   466  			typeof[n] = typeof[n.X]
   467  
   468  		case *ast.IndexExpr:
   469  			// x[i] has key type of x's type.
   470  			t := expand(typeof[n.X])
   471  			if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
   472  				// Lazy: assume there are no nested [] in the array
   473  				// length or map key type.
   474  				if i := strings.Index(t, "]"); i >= 0 {
   475  					typeof[n] = t[i+1:]
   476  				}
   477  			}
   478  
   479  		case *ast.StarExpr:
   480  			// *x for x of type *T has type T when x is an expr.
   481  			// We don't use the result when *x is a type, but
   482  			// compute it anyway.
   483  			t := expand(typeof[n.X])
   484  			if isType(t) {
   485  				typeof[n] = "type *" + getType(t)
   486  			} else if strings.HasPrefix(t, "*") {
   487  				typeof[n] = t[len("*"):]
   488  			}
   489  
   490  		case *ast.UnaryExpr:
   491  			// &x for x of type T has type *T.
   492  			t := typeof[n.X]
   493  			if t != "" && n.Op == token.AND {
   494  				typeof[n] = "*" + t
   495  			}
   496  
   497  		case *ast.CompositeLit:
   498  			// T{...} has type T.
   499  			typeof[n] = gofmt(n.Type)
   500  
   501  		case *ast.ParenExpr:
   502  			// (x) has type of x.
   503  			typeof[n] = typeof[n.X]
   504  
   505  		case *ast.RangeStmt:
   506  			t := expand(typeof[n.X])
   507  			if t == "" {
   508  				return
   509  			}
   510  			var key, value string
   511  			if t == "string" {
   512  				key, value = "int", "rune"
   513  			} else if strings.HasPrefix(t, "[") {
   514  				key = "int"
   515  				if i := strings.Index(t, "]"); i >= 0 {
   516  					value = t[i+1:]
   517  				}
   518  			} else if strings.HasPrefix(t, "map[") {
   519  				if i := strings.Index(t, "]"); i >= 0 {
   520  					key, value = t[4:i], t[i+1:]
   521  				}
   522  			}
   523  			changed := false
   524  			if n.Key != nil && key != "" {
   525  				changed = true
   526  				set(n.Key, key, n.Tok == token.DEFINE)
   527  			}
   528  			if n.Value != nil && value != "" {
   529  				changed = true
   530  				set(n.Value, value, n.Tok == token.DEFINE)
   531  			}
   532  			// Ugly failure of vision: already type-checked body.
   533  			// Do it again now that we have that type info.
   534  			if changed {
   535  				typecheck1(cfg, n.Body, typeof, assign)
   536  			}
   537  
   538  		case *ast.TypeSwitchStmt:
   539  			// Type of variable changes for each case in type switch,
   540  			// but go/parser generates just one variable.
   541  			// Repeat type check for each case with more precise
   542  			// type information.
   543  			as, ok := n.Assign.(*ast.AssignStmt)
   544  			if !ok {
   545  				return
   546  			}
   547  			varx, ok := as.Lhs[0].(*ast.Ident)
   548  			if !ok {
   549  				return
   550  			}
   551  			t := typeof[varx]
   552  			for _, cas := range n.Body.List {
   553  				cas := cas.(*ast.CaseClause)
   554  				if len(cas.List) == 1 {
   555  					// Variable has specific type only when there is
   556  					// exactly one type in the case list.
   557  					if tt := typeof[cas.List[0]]; isType(tt) {
   558  						tt = getType(tt)
   559  						typeof[varx] = tt
   560  						typeof[varx.Obj] = tt
   561  						typecheck1(cfg, cas.Body, typeof, assign)
   562  					}
   563  				}
   564  			}
   565  			// Restore t.
   566  			typeof[varx] = t
   567  			typeof[varx.Obj] = t
   568  
   569  		case *ast.ReturnStmt:
   570  			if len(curfn) == 0 {
   571  				// Probably can't happen.
   572  				return
   573  			}
   574  			f := curfn[len(curfn)-1]
   575  			res := n.Results
   576  			if f.Results != nil {
   577  				t := split(typeof[f.Results])
   578  				for i := 0; i < len(res) && i < len(t); i++ {
   579  					set(res[i], t[i], false)
   580  				}
   581  			}
   582  		}
   583  	}
   584  	walkBeforeAfter(f, before, after)
   585  }
   586  
   587  // Convert between function type strings and lists of types.
   588  // Using strings makes this a little harder, but it makes
   589  // a lot of the rest of the code easier.  This will all go away
   590  // when we can use go/typechecker directly.
   591  
   592  // splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"].
   593  func splitFunc(s string) (in, out []string) {
   594  	if !strings.HasPrefix(s, "func(") {
   595  		return nil, nil
   596  	}
   597  
   598  	i := len("func(") // index of beginning of 'in' arguments
   599  	nparen := 0
   600  	for j := i; j < len(s); j++ {
   601  		switch s[j] {
   602  		case '(':
   603  			nparen++
   604  		case ')':
   605  			nparen--
   606  			if nparen < 0 {
   607  				// found end of parameter list
   608  				out := strings.TrimSpace(s[j+1:])
   609  				if len(out) >= 2 && out[0] == '(' && out[len(out)-1] == ')' {
   610  					out = out[1 : len(out)-1]
   611  				}
   612  				return split(s[i:j]), split(out)
   613  			}
   614  		}
   615  	}
   616  	return nil, nil
   617  }
   618  
   619  // joinFunc is the inverse of splitFunc.
   620  func joinFunc(in, out []string) string {
   621  	outs := ""
   622  	if len(out) == 1 {
   623  		outs = " " + out[0]
   624  	} else if len(out) > 1 {
   625  		outs = " (" + join(out) + ")"
   626  	}
   627  	return "func(" + join(in) + ")" + outs
   628  }
   629  
   630  // split splits "int, float" into ["int", "float"] and splits "" into [].
   631  func split(s string) []string {
   632  	out := []string{}
   633  	i := 0 // current type being scanned is s[i:j].
   634  	nparen := 0
   635  	for j := 0; j < len(s); j++ {
   636  		switch s[j] {
   637  		case ' ':
   638  			if i == j {
   639  				i++
   640  			}
   641  		case '(':
   642  			nparen++
   643  		case ')':
   644  			nparen--
   645  			if nparen < 0 {
   646  				// probably can't happen
   647  				return nil
   648  			}
   649  		case ',':
   650  			if nparen == 0 {
   651  				if i < j {
   652  					out = append(out, s[i:j])
   653  				}
   654  				i = j + 1
   655  			}
   656  		}
   657  	}
   658  	if nparen != 0 {
   659  		// probably can't happen
   660  		return nil
   661  	}
   662  	if i < len(s) {
   663  		out = append(out, s[i:])
   664  	}
   665  	return out
   666  }
   667  
   668  // join is the inverse of split.
   669  func join(x []string) string {
   670  	return strings.Join(x, ", ")
   671  }