| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- // Copyright 2022 The Gc Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package gc // modernc.org/gc/v3
- import (
- "fmt"
- "go/constant"
- "go/token"
- "os"
- "path/filepath"
- "strings"
- "sync"
- )
- type ctx struct {
- ast *AST
- cfg *Config
- errs errList
- iota int64
- pkg *Package
- int32 Type // Set by newCtx
- untypedFloat Type // Set by newCtx
- untypedInt Type // Set by newCtx
- untypedString Type // Set by newCtx
- }
- func newCtx(cfg *Config) (r *ctx) {
- r = &ctx{
- cfg: cfg,
- iota: -1, // -> Invalid
- }
- r.int32 = r.newPredeclaredType(znode, Int32)
- r.untypedFloat = r.newPredeclaredType(znode, UntypedFloat)
- r.untypedInt = r.newPredeclaredType(znode, UntypedInt)
- r.untypedString = r.newPredeclaredType(znode, UntypedString)
- return r
- }
- func (c *ctx) err(n Node, msg string, args ...interface{}) {
- var pos token.Position
- if n != nil {
- pos = n.Position()
- }
- s := fmt.Sprintf(msg, args...)
- if trcTODOs && strings.HasPrefix(s, "TODO") {
- fmt.Fprintf(os.Stderr, "%v: %s (%v)\n", pos, s, origin(2))
- os.Stderr.Sync()
- }
- switch {
- case extendedErrors:
- c.errs.err(pos, "%s (%v: %v: %v)", s, origin(4), origin(3), origin(2))
- default:
- c.errs.err(pos, s)
- }
- }
- func (c *ctx) isBuiltin() bool { return c.pkg.Scope.kind == UniverseScope }
- func (c *ctx) isUnsafe() bool { return c.pkg.isUnsafe }
- func (c *ctx) lookup(sc *Scope, id Token) (pkg *Package, in *Scope, r named) {
- sc0 := sc
- pkg = c.pkg
- for {
- switch in, nm := sc.lookup(id); x := nm.n.(type) {
- case *TypeDefNode:
- if sc.kind == UniverseScope {
- if sc0.kind != UniverseScope && token.IsExported(id.Src()) {
- // trc("%v: %q %v %v", id.Position(), id.Src(), sc0.kind, sc.kind)
- return nil, nil, r
- }
- }
- return x.pkg, in, nm
- default:
- panic(todo("%v: %q %T", id.Position(), id.Src(), x))
- }
- }
- }
- func (n *Package) check(c *ctx) (err error) {
- if n == nil {
- return nil
- }
- c.pkg = n
- // trc("PKG %q", n.ImportPath)
- // defer func() { trc("PKG %q -> err: %v", n.ImportPath, err) }()
- for _, v := range n.GoFiles {
- path := filepath.Join(n.FSPath, v.Name())
- n.AST[path].check(c)
- }
- return c.errs.Err()
- }
- func (n *AST) check(c *ctx) {
- if n == nil {
- return
- }
- c.ast = n
- n.SourceFile.check(c)
- }
- func (n *SourceFileNode) check(c *ctx) {
- if n == nil {
- return
- }
- n.PackageClause.check(c)
- for l := n.ImportDeclList; l != nil; l = l.List {
- l.ImportDecl.check(c)
- }
- for l := n.TopLevelDeclList; l != nil; l = l.List {
- switch x := l.TopLevelDecl.(type) {
- case *TypeDeclNode:
- x.check(c)
- case *ConstDeclNode:
- x.check(c)
- case *VarDeclNode:
- x.check(c)
- case *FunctionDeclNode:
- x.check(c)
- case *MethodDeclNode:
- x.check(c)
- default:
- panic(todo("%v: %T %s", x.Position(), x, x.Source(false)))
- }
- }
- }
- func (n *MethodDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- n.Receiver.check(c)
- n.Signature.check(c)
- }
- func (n *FunctionDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- if c.isBuiltin() {
- switch nm := n.FunctionName.IDENT.Src(); nm {
- case
- "append",
- "cap",
- "close",
- "complex",
- "copy",
- "delete",
- "imag",
- "len",
- "make",
- "new",
- "panic",
- "print",
- "println",
- "real",
- "recover",
- // Go 1.21
- "max",
- "min",
- "clear":
- n.Signature.t = c.newPredeclaredType(n, Function)
- default:
- panic(todo("%v: %q %s", n.Position(), nm, n.Source(false)))
- }
- return
- }
- n.Signature.check(c)
- if n.TypeParameters != nil {
- panic(todo("%v: %T %s", n.Position(), n, n.Source(false)))
- }
- }
- func (n *SignatureNode) check(c *ctx) Type {
- if n == nil {
- return Invalid
- }
- if !n.enter(c, n) {
- return n.Type()
- }
- in := n.Parameters.check(c)
- out := n.Result.check(c)
- return n.setType(newTupleType(n.Parameters, []Type{in, out}))
- }
- func (n *ResultNode) check(c *ctx) Type {
- if n == nil {
- return Invalid
- }
- switch {
- case n.Parameters != nil:
- return n.Parameters.check(c)
- case n.TypeNode != nil:
- return n.TypeNode.check(c)
- default:
- panic(todo("%v: %T %s", n.Position(), n, n.Source(false)))
- }
- }
- func (n *ParametersNode) check(c *ctx) Type {
- if n == nil {
- return Invalid
- }
- r := newTupleType(n, nil)
- for l := n.ParameterDeclList; l != nil; l = l.List {
- r.Types = append(r.Types, l.ParameterDecl.check(c)...)
- }
- return r
- }
- func (n *ParameterDeclNode) check(c *ctx) (r []Type) {
- if n == nil {
- return nil
- }
- t := n.TypeNode.check(c)
- for l := n.IdentifierList; l != nil; l = l.List {
- r = append(r, t)
- }
- return r
- }
- func (n *VarDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- switch x := n.VarSpec.(type) {
- case *VarSpecNode:
- x.check(c)
- default:
- panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- }
- }
- func (n *VarSpecNode) check(c *ctx) {
- if n == nil {
- return
- }
- if c.isBuiltin() {
- switch nm := n.IDENT.Src(); nm {
- case "nil":
- n.TypeNode = c.newPredeclaredType(n, UntypedNil)
- default:
- panic(todo("%v: %q", n.IDENT.Position(), nm))
- }
- return
- }
- if n.TypeNode != nil {
- c.err(n, "TODO %v", n.TypeNode.Source(false))
- }
- var e []Expression
- for l := n.ExpressionList; l != nil; l = l.List {
- e = append(e, l.Expression.checkExpr(c))
- }
- switch len(e) {
- default:
- panic(todo("", len(e)))
- c.err(n, "TODO %v", len(e))
- }
- }
- func (n *ConstDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- switch x := n.ConstSpec.(type) {
- case *ConstSpecListNode:
- var prev Node
- for l := x; l != nil; l = l.List {
- switch y := l.ConstSpec.(type) {
- case *ConstSpecNode:
- y.check(c, prev)
- if y.Expression != nil || y.TypeNode != nil {
- prev = y
- }
- default:
- panic(todo("%v: %T %s", n.Position(), y, n.Source(false)))
- }
- }
- case *ConstSpecNode:
- x.check(c, nil)
- default:
- panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- }
- }
- func (n *ConstSpecNode) check(c *ctx, prev Node) {
- if n == nil {
- return
- }
- if !n.enter(c, n) {
- if n.guard == guardChecking {
- panic(todo("")) // report recursive
- }
- return
- }
- defer func() { n.guard = guardChecked }()
- if c.isBuiltin() {
- switch n.IDENT.Src() {
- case "true":
- switch x := n.Expression.(type) {
- case *BinaryExpressionNode:
- x.setValue(trueVal)
- x.setType(c.newPredeclaredType(x, UntypedBool))
- default:
- panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- }
- case "false":
- switch x := n.Expression.(type) {
- case *BinaryExpressionNode:
- x.setValue(falseVal)
- x.setType(c.newPredeclaredType(x, UntypedBool))
- default:
- panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- }
- case "iota":
- switch x := n.Expression.(type) {
- case *BasicLitNode:
- // ok
- default:
- panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- }
- default:
- panic(todo("", n.Position(), n.Source(false)))
- }
- return
- }
- save := c.iota
- c.iota = n.iota
- defer func() { c.iota = save }()
- switch {
- case n.Expression != nil:
- n.Expression = n.Expression.checkExpr(c)
- if n.TypeNode == nil {
- n.TypeNode = n.Expression.Type()
- return
- }
- t := n.TypeNode.check(c)
- trc("", t)
- panic(todo("%v: %T %s", n.Position(), n, n.Source(false)))
- default:
- // var e Expression
- // var pe *Expression
- // switch {
- // case n.Expression != nil:
- // e = n.Expression
- // pe = &n.Expression
- // default:
- // switch x := prev.(type) {
- // case *ConstSpecNode:
- // e = x.Expression.clone()
- // pe = &e
- // default:
- // panic(todo("%v: %T %s", n.Position(), x, n.Source(false)))
- // }
- // }
- // ev, et := e.checkExpr(c, pe)
- // e = *pe
- // if ev.Kind() == constant.Unknown {
- // c.err(e, "%s is not a constant", e.Source(false))
- // n.t = Invalid
- // n.setValue(unknown)
- // return Invalid
- // }
- // switch {
- // case n.t == nil:
- // n.t = et
- // default:
- // c.err(n.Expression, "cannot assign %v (type %v) to type %v", ev, et, n.Type())
- // return Invalid
- // } else {
- // n.setValue(convertValue(c, e, ev, n.Type()))
- // }
- // }
- // return n.Type()
- panic(todo("%v: %T %s", n.Position(), n, n.Source(false)))
- }
- }
- func (n *TypeDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- for l := n.TypeSpecList; l != nil; l = l.List {
- switch x := l.TypeSpec.(type) {
- case *TypeDefNode:
- switch {
- case c.isBuiltin():
- x.pkg = c.pkg
- switch nm := x.IDENT.Src(); nm {
- case "bool":
- x.TypeNode = c.newPredeclaredType(x, Bool)
- case "int":
- x.TypeNode = c.newPredeclaredType(x, Int)
- c.cfg.int = x.TypeNode
- case "int8":
- x.TypeNode = c.newPredeclaredType(x, Int8)
- case "int16":
- x.TypeNode = c.newPredeclaredType(x, Int16)
- case "int32":
- x.TypeNode = c.newPredeclaredType(x, Int32)
- case "int64":
- x.TypeNode = c.newPredeclaredType(x, Int64)
- case "uint":
- x.TypeNode = c.newPredeclaredType(x, Uint)
- c.cfg.uint = x.TypeNode
- case "uint8":
- x.TypeNode = c.newPredeclaredType(x, Uint8)
- case "uint16":
- x.TypeNode = c.newPredeclaredType(x, Uint16)
- case "uint32":
- x.TypeNode = c.newPredeclaredType(x, Uint32)
- case "uint64":
- x.TypeNode = c.newPredeclaredType(x, Uint64)
- case "uintptr":
- x.TypeNode = c.newPredeclaredType(x, Uintptr)
- case "string":
- x.TypeNode = c.newPredeclaredType(x, String)
- case "float32":
- x.TypeNode = c.newPredeclaredType(x, Float32)
- case "float64":
- x.TypeNode = c.newPredeclaredType(x, Float64)
- case "complex64":
- x.TypeNode = c.newPredeclaredType(x, Complex64)
- case "complex128":
- x.TypeNode = c.newPredeclaredType(x, Complex128)
- case "comparable":
- x.TypeNode = c.newPredeclaredType(x, Interface)
- case "error":
- x.check(c)
- default:
- if token.IsExported(nm) {
- delete(c.pkg.Scope.nodes, nm)
- return
- }
- panic(todo("%v: %T %s", x.Position(), x, x.Source(false)))
- }
- case c.isUnsafe():
- switch nm := x.IDENT.Src(); nm {
- case "ArbitraryType", "IntegerType", "Pointer":
- x.TypeNode.check(c)
- default:
- panic(todo("%v: %T %s", x.Position(), x, x.Source(false)))
- }
- default:
- switch {
- case x.TypeParameters != nil:
- panic(todo("%v: %T %s", x.Position(), x, x.Source(false)))
- default:
- x.check(c)
- }
- }
- case *AliasDeclNode:
- x.check(c)
- default:
- panic(todo("%v: %T %s", x.Position(), x, x.Source(false)))
- }
- }
- }
- func (n *AliasDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- n.TypeNode.check(c)
- }
- func (n *ImportDeclNode) check(c *ctx) {
- if n == nil {
- return
- }
- type result struct {
- spec *ImportSpecNode
- pkg *Package
- err error
- }
- var a []*result
- var wg sync.WaitGroup
- for l := n.ImportSpecList; l != nil; l = l.List {
- r := &result{}
- a = append(a, r)
- wg.Add(1)
- go func(isln *ImportSpecListNode, r *result) {
- defer wg.Done()
- r.spec = isln.ImportSpec
- r.pkg, r.err = r.spec.check(c)
- r.spec.pkg = r.pkg
- }(l, r)
- }
- wg.Wait()
- fileScope := c.ast.FileScope
- pkgScope := c.pkg.Scope
- for _, v := range a {
- switch x := v.err.(type) {
- case nil:
- // ok
- default:
- panic(todo("%v: %T: %s", v.spec.Position(), x, x))
- }
- if c.pkg.ImportPath == "builtin" && v.spec.ImportPath.Src() == `"cmp"` {
- continue
- }
- switch ex := fileScope.declare(v.pkg.Name, v.spec, 0, nil, true); {
- case ex.declTok.IsValid():
- c.err(n, "%s redeclared, previous declaration at %v:", v.pkg.Name.Src(), ex.declTok.Position())
- continue
- }
- switch ex := pkgScope.declare(v.pkg.Name, v.spec, 0, nil, true); {
- case ex.declTok.IsValid():
- c.err(n, "%s redeclared, previous declaration at %v:", v.pkg.Name.Src(), ex.declTok.Position())
- continue
- }
- }
- }
- func (n *ImportSpecNode) check(c *ctx) (*Package, error) {
- if n == nil {
- return nil, nil
- }
- switch {
- case n.PERIOD.IsValid():
- panic(todo("", n.Position(), n.Source(false)))
- case n.PackageName.IsValid():
- //TODO version
- check := c.pkg.typeCheck
- switch check {
- case TypeCheckAll:
- // nop
- default:
- panic(todo("", check))
- }
- return c.cfg.newPackage(c.pkg.FSPath, constant.StringVal(n.ImportPath.Value()), "", nil, false, check, c.pkg.guard)
- default:
- //TODO version
- check := c.pkg.typeCheck
- switch check {
- case TypeCheckAll:
- // nop
- default:
- if c.pkg.ImportPath == "builtin" && n.ImportPath.Src() == `"cmp"` {
- return nil, nil
- }
- }
- return c.cfg.newPackage(c.pkg.FSPath, constant.StringVal(n.ImportPath.Value()), "", nil, false, check, c.pkg.guard)
- }
- }
- func (n *PackageClauseNode) check(c *ctx) {
- if n == nil {
- return
- }
- nm := n.PackageName.Src()
- if ex := c.pkg.Name; ex.IsValid() && ex.Src() != nm {
- c.err(n.PackageName, "found different packages %q and %q", ex.Src(), nm)
- return
- }
- c.pkg.Name = n.PackageName
- }
|