From 1a57267a17c2fc17fb6e104846fabc3e363c326c Mon Sep 17 00:00:00 2001 From: Emile Date: Fri, 16 Aug 2024 19:50:26 +0200 Subject: initial commit --- vendor/modernc.org/gc/v3/check.go | 598 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100644 vendor/modernc.org/gc/v3/check.go (limited to 'vendor/modernc.org/gc/v3/check.go') diff --git a/vendor/modernc.org/gc/v3/check.go b/vendor/modernc.org/gc/v3/check.go new file mode 100644 index 0000000..0c5e0a2 --- /dev/null +++ b/vendor/modernc.org/gc/v3/check.go @@ -0,0 +1,598 @@ +// 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 +} -- cgit 1.4.1