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 }