gitlab.com/ethan.reesor/vscode-notebooks/yaegi@v0.0.0-20220417214422-5c573557938e/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  
   221  					// If an incomplete type exists, delete it
   222  					if sym, exists := sc.sym[name]; exists && sym.kind == typeSym && sym.typ.incomplete {
   223  						delete(sc.sym, name)
   224  					}
   225  
   226  					// Imports of a same package are all mapped in the same scope, so we cannot just
   227  					// map them by their names, otherwise we could have collisions from same-name
   228  					// imports in different source files of the same package. Therefore, we suffix
   229  					// the key with the basename of the source file.
   230  					name = filepath.Join(name, baseName)
   231  					if sym, exists := sc.sym[name]; !exists {
   232  						sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath, scope: sc}}
   233  						break
   234  					} else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath {
   235  						// ignore re-import of identical package
   236  						break
   237  					}
   238  
   239  					// redeclaration error. Not caught by the parser.
   240  					err = n.cfgErrorf("%s redeclared in this block", name)
   241  					return false
   242  				}
   243  			} else if pkgName, err = interp.importSrc(rpath, ipath, NoTest); err == nil {
   244  				sc.types = interp.universe.types
   245  				switch name {
   246  				case "_": // no import of symbols
   247  				case ".": // import symbols in current namespace
   248  					for k, v := range interp.srcPkg[ipath] {
   249  						if canExport(k) {
   250  							sc.sym[k] = v
   251  						}
   252  					}
   253  				default: // import symbols in package namespace
   254  					if name == "" {
   255  						name = pkgName
   256  					}
   257  					name = filepath.Join(name, baseName)
   258  					if sym, exists := sc.sym[name]; !exists {
   259  						sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: ipath, scope: sc}}
   260  						break
   261  					} else if sym.kind == pkgSym && sym.typ.cat == srcPkgT && sym.typ.path == ipath {
   262  						// ignore re-import of identical package
   263  						break
   264  					}
   265  
   266  					// redeclaration error
   267  					err = n.cfgErrorf("%s redeclared as imported package name", name)
   268  					return false
   269  				}
   270  			} else {
   271  				err = n.cfgErrorf("import %q error: %v", ipath, err)
   272  			}
   273  
   274  		case typeSpec, typeSpecAssign:
   275  			typeName := n.child[0].ident
   276  			var typ *itype
   277  			if typ, err = nodeType(interp, sc, n.child[1]); err != nil {
   278  				err = nil
   279  				revisit = append(revisit, n)
   280  				return false
   281  			}
   282  
   283  			switch n.child[1].kind {
   284  			case identExpr, selectorExpr:
   285  				n.typ = namedOf(typ, pkgName, typeName, withNode(n.child[0]), withScope(sc))
   286  				n.typ.incomplete = typ.incomplete
   287  				n.typ.field = typ.field
   288  				copy(n.typ.method, typ.method)
   289  			default:
   290  				n.typ = typ
   291  				n.typ.name = typeName
   292  				n.typ.path = pkgName
   293  			}
   294  			n.typ.str = n.typ.path + "." + n.typ.name
   295  
   296  			asImportName := filepath.Join(typeName, baseName)
   297  			if _, exists := sc.sym[asImportName]; exists {
   298  				// redeclaration error
   299  				err = n.cfgErrorf("%s redeclared in this block", typeName)
   300  				return false
   301  			}
   302  			sym, exists := sc.sym[typeName]
   303  			if !exists {
   304  				sc.sym[typeName] = &symbol{kind: typeSym, node: n}
   305  			} else {
   306  				if sym.typ != nil && (len(sym.typ.method) > 0) {
   307  					if n.kind == typeSpecAssign {
   308  						err = n.cfgErrorf("cannot define new methods on non-local type %s", baseType(typ).id())
   309  						return false
   310  					}
   311  					// Type has already been seen as a receiver in a method function
   312  					for _, m := range sym.typ.method {
   313  						n.typ.addMethod(m)
   314  					}
   315  				} else {
   316  					// TODO(mpl): figure out how to detect redeclarations without breaking type aliases.
   317  					// Allow redeclarations for now.
   318  					sc.sym[typeName] = &symbol{kind: typeSym, node: n}
   319  				}
   320  			}
   321  			sc.sym[typeName].typ = n.typ
   322  			if !n.typ.isComplete() {
   323  				revisit = append(revisit, n)
   324  			}
   325  			return false
   326  		}
   327  		return true
   328  	}, nil)
   329  
   330  	if sc != interp.universe {
   331  		sc.pop()
   332  	}
   333  	return revisit, err
   334  }
   335  
   336  func baseType(t *itype) *itype {
   337  	for {
   338  		switch t.cat {
   339  		case ptrT, aliasT:
   340  			t = t.val
   341  		default:
   342  			return t
   343  		}
   344  	}
   345  }
   346  
   347  // gtaRetry (re)applies gta until all global constants and types are defined.
   348  func (interp *Interpreter) gtaRetry(nodes []*node, importPath, pkgName string) error {
   349  	revisit := []*node{}
   350  	for {
   351  		for _, n := range nodes {
   352  			list, err := interp.gta(n, importPath, importPath, pkgName)
   353  			if err != nil {
   354  				return err
   355  			}
   356  			revisit = append(revisit, list...)
   357  		}
   358  
   359  		if len(revisit) == 0 || equalNodes(nodes, revisit) {
   360  			break
   361  		}
   362  
   363  		nodes = revisit
   364  		revisit = []*node{}
   365  	}
   366  
   367  	if len(revisit) > 0 {
   368  		n := revisit[0]
   369  		switch n.kind {
   370  		case typeSpec, typeSpecAssign:
   371  			if err := definedType(n.typ); err != nil {
   372  				return err
   373  			}
   374  		case defineStmt, funcDecl:
   375  			if err, ok := n.meta.(error); ok {
   376  				return err
   377  			}
   378  		}
   379  		return n.cfgErrorf("constant definition loop")
   380  	}
   381  	return nil
   382  }
   383  
   384  func definedType(typ *itype) error {
   385  	if !typ.incomplete {
   386  		return nil
   387  	}
   388  	switch typ.cat {
   389  	case interfaceT, structT:
   390  		for _, f := range typ.field {
   391  			if err := definedType(f.typ); err != nil {
   392  				return err
   393  			}
   394  		}
   395  	case funcT:
   396  		for _, t := range typ.arg {
   397  			if err := definedType(t); err != nil {
   398  				return err
   399  			}
   400  		}
   401  		for _, t := range typ.ret {
   402  			if err := definedType(t); err != nil {
   403  				return err
   404  			}
   405  		}
   406  	case mapT:
   407  		if err := definedType(typ.key); err != nil {
   408  			return err
   409  		}
   410  		fallthrough
   411  	case aliasT, arrayT, chanT, chanSendT, chanRecvT, ptrT, variadicT:
   412  		if err := definedType(typ.val); err != nil {
   413  			return err
   414  		}
   415  	case nilT:
   416  		return typ.node.cfgErrorf("undefined: %s", typ.node.ident)
   417  	}
   418  	return nil
   419  }
   420  
   421  // equalNodes returns true if two slices of nodes are identical.
   422  func equalNodes(a, b []*node) bool {
   423  	if len(a) != len(b) {
   424  		return false
   425  	}
   426  	for i, n := range a {
   427  		if n != b[i] {
   428  			return false
   429  		}
   430  	}
   431  	return true
   432  }