mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:22:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			599 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			599 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | // 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 | ||
|  | } |