github.com/switchupcb/yaegi@v0.10.2/interp/gta.go (about)

     1  package interp
     2  
     3  import (
     4  	"path"
     5  	"path/filepath"
     6  )
     7  
     8  // gta performs a global types analysis on the AST, registering types,
     9  // variables and functions symbols at package level, prior to CFG.
    10  // All function bodies are skipped. GTA is necessary to handle out of
    11  // order declarations and multiple source files packages.
    12  // rpath is the relative path to the directory containing the source for the package.
    13  func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([]*node, error) {
    14  	sc := interp.initScopePkg(importPath, pkgName)
    15  	var err error
    16  	var revisit []*node
    17  
    18  	baseName := filepath.Base(interp.fset.Position(root.pos).Filename)
    19  
    20  	root.Walk(func(n *node) bool {
    21  		if err != nil {
    22  			return false
    23  		}
    24  		switch n.kind {
    25  		case constDecl:
    26  			// Early parse of constDecl subtree, to compute all constant
    27  			// values which may be used in further declarations.
    28  			if _, err = interp.cfg(n, sc, importPath, pkgName); err != nil {
    29  				// No error processing here, to allow recovery in subtree nodes.
    30  				// TODO(marc): check for a non recoverable error and return it for better diagnostic.
    31  				err = nil
    32  			}
    33  
    34  		case blockStmt:
    35  			if n != root {
    36  				return false // skip statement block if not the entry point
    37  			}
    38  
    39  		case defineStmt:
    40  			var (
    41  				atyp *itype
    42  				err2 error
    43  			)
    44  			if n.nleft+n.nright < len(n.child) {
    45  				// Type is declared explicitly in the assign expression.
    46  				if atyp, err2 = nodeType(interp, sc, n.child[n.nleft]); err2 != nil {
    47  					// The type does not exist yet, stash the error and come back
    48  					// when the type is known.
    49  					n.meta = err2
    50  					revisit = append(revisit, n)
    51  					return false
    52  				}
    53  			}
    54  
    55  			var sbase int
    56  			if n.nright > 0 {
    57  				sbase = len(n.child) - n.nright
    58  			}
    59  
    60  			for i := 0; i < n.nleft; i++ {
    61  				dest, src := n.child[i], n.child[sbase+i]
    62  				val := src.rval
    63  				if n.anc.kind == constDecl {
    64  					if _, err2 := interp.cfg(n, sc, importPath, pkgName); err2 != nil {
    65  						// Constant value can not be computed yet.
    66  						// Come back when child dependencies are known.
    67  						revisit = append(revisit, n)
    68  						return false
    69  					}
    70  				}
    71  				typ := atyp
    72  				if typ == nil {
    73  					if typ, err2 = nodeType(interp, sc, src); err2 != nil || typ == nil {
    74  						// The type does is not known yet, stash the error and come back
    75  						// when the type is known.
    76  						n.meta = err2
    77  						revisit = append(revisit, n)
    78  						return false
    79  					}
    80  					val = src.rval
    81  				}
    82  				if !typ.isComplete() {
    83  					// Come back when type is known.
    84  					revisit = append(revisit, n)
    85  					return false
    86  				}
    87  				if typ.cat == nilT {
    88  					err = n.cfgErrorf("use of untyped nil")
    89  					return false
    90  				}
    91  				if typ.isBinMethod {
    92  					typ = valueTOf(typ.methodCallType(), isBinMethod(), withScope(sc))
    93  				}
    94  				sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val, node: n}
    95  				if n.anc.kind == constDecl {
    96  					sc.sym[dest.ident].kind = constSym
    97  					if childPos(n) == len(n.anc.child)-1 {
    98  						sc.iota = 0
    99  					} else {
   100  						sc.iota++
   101  					}
   102  				}
   103  			}
   104  			return false
   105  
   106  		case defineXStmt:
   107  			err = compDefineX(sc, n)
   108  
   109  		case valueSpec:
   110  			l := len(n.child) - 1
   111  			if n.typ = n.child[l].typ; n.typ == nil {
   112  				if n.typ, err = nodeType(interp, sc, n.child[l]); err != nil {
   113  					return false
   114  				}
   115  				if !n.typ.isComplete() {
   116  					// Come back when type is known.
   117  					revisit = append(revisit, n)
   118  					return false
   119  				}
   120  			}
   121  			for _, c := range n.child[:l] {
   122  				asImportName := filepath.Join(c.ident, baseName)
   123  				sym, exists := sc.sym[asImportName]
   124  				if !exists {
   125  					sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ, node: n}
   126  					continue
   127  				}
   128  				c.level = globalFrame
   129  
   130  				// redeclaration error
   131  				if sym.typ.node != nil && sym.typ.node.anc != nil {
   132  					prevDecl := n.interp.fset.Position(sym.typ.node.anc.pos)
   133  					err = n.cfgErrorf("%s redeclared in this block\n\tprevious declaration at %v", c.ident, prevDecl)
   134  					return false
   135  				}
   136  				err = n.cfgErrorf("%s redeclared in this block", c.ident)
   137  				return false
   138  			}
   139  
   140  		case funcDecl:
   141  			if n.typ, err = nodeType(interp, sc, n.child[2]); err != nil {
   142  				return false
   143  			}
   144  			ident := n.child[1].ident
   145  			switch {
   146  			case isMethod(n):
   147  				// Add a method symbol in the receiver type name space
   148  				var rcvrtype *itype
   149  				n.ident = ident
   150  				rcvr := n.child[0].child[0]
   151  				rtn := rcvr.lastChild()
   152  				typName, typPtr := rtn.ident, false
   153  				if typName == "" {
   154  					typName, typPtr = rtn.child[0].ident, true
   155  				}
   156  				sym, _, found := sc.lookup(typName)
   157  				if !found {
   158  					n.meta = n.cfgErrorf("undefined: %s", typName)
   159  					revisit = append(revisit, n)
   160  					return false
   161  				}
   162  				if sym.kind != typeSym || (sym.node != nil && sym.node.kind == typeSpecAssign) {
   163  					err = n.cfgErrorf("cannot define new methods on non-local type %s", baseType(sym.typ).id())
   164  					return false
   165  				}
   166  				rcvrtype = sym.typ
   167  				if typPtr {
   168  					elementType := sym.typ
   169  					rcvrtype = ptrOf(elementType, withNode(rtn), withScope(sc))
   170  					rcvrtype.incomplete = elementType.incomplete
   171  					elementType.addMethod(n)
   172  				}
   173  				rcvrtype.addMethod(n)
   174  				n.child[0].child[0].lastChild().typ = rcvrtype
   175  			case ident == "init":
   176  				// init functions do not get declared as per the Go spec.
   177  			default:
   178  				asImportName := filepath.Join(ident, baseName)
   179  				if _, exists := sc.sym[asImportName]; exists {
   180  					// redeclaration error
   181  					err = n.cfgErrorf("%s redeclared in this block", ident)
   182  					return false
   183  				}
   184  				// Add a function symbol in the package name space except for init
   185  				sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
   186  			}
   187  			if !n.typ.isComplete() {
   188  				revisit = append(revisit, n)
   189  			}
   190  			return false
   191  
   192  		case importSpec:
   193  			var name, ipath string
   194  			if len(n.child) == 2 {
   195  				ipath = constToString(n.child[1].rval)
   196  				name = n.child[0].ident
   197  			} else {
   198  				ipath = constToString(n.child[0].rval)
   199  			}
   200  			// Try to import a binary package first, or a source package
   201  			var pkgName string
   202  			if packageName := path.Base(ipath); path.Dir(ipath) == packageName {
   203  				ipath = packageName
   204  			}
   205  			if pkg := interp.binPkg[ipath]; pkg != nil {
   206  				switch name {
   207  				case "_": // no import of symbols
   208  				case ".": // import symbols in current scope
   209  					for n, v := range pkg {
   210  						typ := v.Type()
   211  						if isBinType(v) {
   212  							typ = typ.Elem()
   213  						}
   214  						sc.sym[n] = &symbol{kind: binSym, typ: valueTOf(typ, withScope(sc)), rval: v}
   215  					}
   216  				default: // import symbols in package namespace
   217  					if name == "" {
   218  						name = interp.pkgNames[ipath]
   219  					}
   220  					// Imports of a same package are all mapped in the same scope, so we cannot just
   221  					// map them by their names, otherwise we could have collisions from same-name
   222  					// imports in different source files of the same package. Therefore, we suffix
   223  					// the key with the basename of the source file.
   224  					name = filepath.Join(name, baseName)
   225  					if sym, exists := sc.sym[name]; !exists {
   226  						sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath, scope: sc}}
   227  						break
   228  					} else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath {
   229  						// ignore re-import of identical package
   230  						break
   231  					}
   232  
   233  					// redeclaration error. Not caught by the parser.
   234  					err = n.cfgErrorf("%s redeclared in this block", name)
   235  					return false
   236  				}
   237  			} else if pkgName, err = interp.importSrc(rpath, ipath, NoTest); err == nil {
   238  				sc.types = interp.universe.types
   239  				switch name {
   240  				case "_": // no import of symbols
   241  				case ".": // import symbols in current namespace
   242  					for k, v := range interp.srcPkg[ipath] {
   243  						if canExport(k) {
   244  							sc.sym[k] = v
   245  						}
   246  					}
   247  				default: // import symbols in package namespace
   248  					if name == "" {
   249  						name = pkgName
   250  					}
   251  					name = filepath.Join(name, baseName)
   252  					if sym, exists := sc.sym[name]; !exists {
   253  						sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath, scope: sc}}
   254  						break
   255  					} else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath {
   256  						// ignore re-import of identical package
   257  						break
   258  					}
   259  
   260  					// redeclaration error
   261  					err = n.cfgErrorf("%s redeclared as imported package name", name)
   262  					return false
   263  				}
   264  			} else {
   265  				err = n.cfgErrorf("import %q error: %v", ipath, err)
   266  			}
   267  
   268  		case typeSpec, typeSpecAssign:
   269  			typeName := n.child[0].ident
   270  			var typ *itype
   271  			if typ, err = nodeType(interp, sc, n.child[1]); err != nil {
   272  				err = nil
   273  				revisit = append(revisit, n)
   274  				return false
   275  			}
   276  
   277  			switch n.child[1].kind {
   278  			case identExpr, selectorExpr:
   279  				n.typ = namedOf(typ, pkgName, typeName, withNode(n.child[0]), withScope(sc))
   280  				n.typ.incomplete = typ.incomplete
   281  				n.typ.field = typ.field
   282  				copy(n.typ.method, typ.method)
   283  			default:
   284  				n.typ = typ
   285  				n.typ.name = typeName
   286  				n.typ.path = pkgName
   287  			}
   288  			n.typ.str = n.typ.path + "." + n.typ.name
   289  
   290  			asImportName := filepath.Join(typeName, baseName)
   291  			if _, exists := sc.sym[asImportName]; exists {
   292  				// redeclaration error
   293  				err = n.cfgErrorf("%s redeclared in this block", typeName)
   294  				return false
   295  			}
   296  			sym, exists := sc.sym[typeName]
   297  			if !exists {
   298  				sc.sym[typeName] = &symbol{kind: typeSym, node: n}
   299  			} else {
   300  				if sym.typ != nil && (len(sym.typ.method) > 0) {
   301  					if n.kind == typeSpecAssign {
   302  						err = n.cfgErrorf("cannot define new methods on non-local type %s", baseType(typ).id())
   303  						return false
   304  					}
   305  					// Type has already been seen as a receiver in a method function
   306  					for _, m := range sym.typ.method {
   307  						n.typ.addMethod(m)
   308  					}
   309  				} else {
   310  					// TODO(mpl): figure out how to detect redeclarations without breaking type aliases.
   311  					// Allow redeclarations for now.
   312  					sc.sym[typeName] = &symbol{kind: typeSym, node: n}
   313  				}
   314  			}
   315  			sc.sym[typeName].typ = n.typ
   316  			if !n.typ.isComplete() {
   317  				revisit = append(revisit, n)
   318  			}
   319  			return false
   320  		}
   321  		return true
   322  	}, nil)
   323  
   324  	if sc != interp.universe {
   325  		sc.pop()
   326  	}
   327  	return revisit, err
   328  }
   329  
   330  func baseType(t *itype) *itype {
   331  	for {
   332  		switch t.cat {
   333  		case ptrT, aliasT:
   334  			t = t.val
   335  		default:
   336  			return t
   337  		}
   338  	}
   339  }
   340  
   341  // gtaRetry (re)applies gta until all global constants and types are defined.
   342  func (interp *Interpreter) gtaRetry(nodes []*node, importPath, pkgName string) error {
   343  	revisit := []*node{}
   344  	for {
   345  		for _, n := range nodes {
   346  			list, err := interp.gta(n, importPath, importPath, pkgName)
   347  			if err != nil {
   348  				return err
   349  			}
   350  			revisit = append(revisit, list...)
   351  		}
   352  
   353  		if len(revisit) == 0 || equalNodes(nodes, revisit) {
   354  			break
   355  		}
   356  
   357  		nodes = revisit
   358  		revisit = []*node{}
   359  	}
   360  
   361  	if len(revisit) > 0 {
   362  		n := revisit[0]
   363  		switch n.kind {
   364  		case typeSpec, typeSpecAssign:
   365  			if err := definedType(n.typ); err != nil {
   366  				return err
   367  			}
   368  		case defineStmt, funcDecl:
   369  			if err, ok := n.meta.(error); ok {
   370  				return err
   371  			}
   372  		}
   373  		return n.cfgErrorf("constant definition loop")
   374  	}
   375  	return nil
   376  }
   377  
   378  func definedType(typ *itype) error {
   379  	if !typ.incomplete {
   380  		return nil
   381  	}
   382  	switch typ.cat {
   383  	case interfaceT, structT:
   384  		for _, f := range typ.field {
   385  			if err := definedType(f.typ); err != nil {
   386  				return err
   387  			}
   388  		}
   389  	case funcT:
   390  		for _, t := range typ.arg {
   391  			if err := definedType(t); err != nil {
   392  				return err
   393  			}
   394  		}
   395  		for _, t := range typ.ret {
   396  			if err := definedType(t); err != nil {
   397  				return err
   398  			}
   399  		}
   400  	case mapT:
   401  		if err := definedType(typ.key); err != nil {
   402  			return err
   403  		}
   404  		fallthrough
   405  	case aliasT, arrayT, chanT, chanSendT, chanRecvT, ptrT, variadicT:
   406  		if err := definedType(typ.val); err != nil {
   407  			return err
   408  		}
   409  	case nilT:
   410  		return typ.node.cfgErrorf("undefined: %s", typ.node.ident)
   411  	}
   412  	return nil
   413  }
   414  
   415  // equalNodes returns true if two slices of nodes are identical.
   416  func equalNodes(a, b []*node) bool {
   417  	if len(a) != len(b) {
   418  		return false
   419  	}
   420  	for i, n := range a {
   421  		if n != b[i] {
   422  			return false
   423  		}
   424  	}
   425  	return true
   426  }