about summary refs log tree commit diff
path: root/vendor/modernc.org/gc/v3/check.go
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-08-16 19:50:26 +0200
committerEmile <git@emile.space>2024-08-16 19:50:26 +0200
commit1a57267a17c2fc17fb6e104846fabc3e363c326c (patch)
tree1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /vendor/modernc.org/gc/v3/check.go
initial commit
Diffstat (limited to 'vendor/modernc.org/gc/v3/check.go')
-rw-r--r--vendor/modernc.org/gc/v3/check.go598
1 files changed, 598 insertions, 0 deletions
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
+}