package types
import (
)
const (
debug = false
trace = false
compilerErrorMessages = false
)
type exprInfo struct {
isLhs bool
mode operandMode
typ *Basic
val constant.Value
}
type environment struct {
decl *declInfo
scope *Scope
pos token.Pos
iota constant.Value
errpos positioner
inTParamList bool
sig *Signature
isPanic map[*ast.CallExpr]bool
hasLabel bool
hasCallOrRecv bool
}
func ( *environment) ( string) Object {
, := .scope.LookupParent(, .pos)
return
}
type importKey struct {
path, dir string
}
type dotImportKey struct {
scope *Scope
name string
}
type action struct {
f func()
desc *actionDesc
}
func ( *action) ( positioner, string, ...any) {
if debug {
.desc = &actionDesc{, , }
}
}
type actionDesc struct {
pos positioner
format string
args []any
}
type Checker struct {
conf *Config
ctxt *Context
fset *token.FileSet
pkg *Package
*Info
version version
nextID uint64
objMap map[Object]*declInfo
impMap map[importKey]*Package
infoMap map[*Named]typeInfo
pkgPathMap map[string]map[string]bool
seenPkgMap map[*Package]bool
files []*ast.File
imports []*PkgName
dotImportMap map[dotImportKey]*PkgName
recvTParamMap map[*ast.Ident]*TypeParam
brokenAliases map[*TypeName]bool
unionTypeSets map[*Union]*_TypeSet
mono monoGraph
firstErr error
methods map[*TypeName][]*Func
untyped map[ast.Expr]exprInfo
delayed []action
objPath []Object
cleaners []cleaner
environment
indent int
}
func ( *Checker) ( Object) {
:= .decl
if == nil {
return
}
if , := .objMap[]; ! {
return
}
.addDep()
}
func ( *Checker) ( *TypeName) {
if .brokenAliases == nil {
.brokenAliases = make(map[*TypeName]bool)
}
.brokenAliases[] = true
.typ = Typ[Invalid]
}
func ( *Checker) ( *TypeName, Type) {
delete(.brokenAliases, )
.typ =
}
func ( *Checker) ( *TypeName) bool {
return .typ == Typ[Invalid] && .brokenAliases[]
}
func ( *Checker) ( ast.Expr, bool, operandMode, *Basic, constant.Value) {
:= .untyped
if == nil {
= make(map[ast.Expr]exprInfo)
.untyped =
}
[] = exprInfo{, , , }
}
func ( *Checker) ( func()) *action {
:= len(.delayed)
.delayed = append(.delayed, action{f: })
return &.delayed[]
}
func ( *Checker) ( Object) int {
.objPath = append(.objPath, )
return len(.objPath) - 1
}
func ( *Checker) () Object {
:= len(.objPath) - 1
:= .objPath[]
.objPath[] = nil
.objPath = .objPath[:]
return
}
type cleaner interface {
cleanup()
}
func ( *Checker) ( cleaner) {
.cleaners = append(.cleaners, )
}
func ( *Config, *token.FileSet, *Package, *Info) *Checker {
if == nil {
= new(Config)
}
if == nil {
= new(Info)
}
, := parseGoVersion(.GoVersion)
if != nil {
panic(fmt.Sprintf("invalid Go version %q (%v)", .GoVersion, ))
}
return &Checker{
conf: ,
ctxt: .Context,
fset: ,
pkg: ,
Info: ,
version: ,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
infoMap: make(map[*Named]typeInfo),
}
}
func ( *Checker) ( []*ast.File) {
.files = nil
.imports = nil
.dotImportMap = nil
.firstErr = nil
.methods = nil
.untyped = nil
.delayed = nil
.objPath = nil
.cleaners = nil
:= .pkg
for , := range {
switch := .Name.Name; .name {
case "":
if != "_" {
.name =
} else {
.errorf(.Name, _BlankPkgName, "invalid package name _")
}
fallthrough
case :
.files = append(.files, )
default:
.errorf(atPos(.Package), _MismatchedPkgName, "package %s; expected %s", , .name)
}
}
}
type bailout struct{}
func ( *Checker) ( *error) {
switch p := recover().(type) {
case nil, bailout:
* = .firstErr
default:
panic()
}
}
func ( *Checker) ( []*ast.File) error { return .checkFiles() }
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
func ( *Checker) ( []*ast.File) ( error) {
if .conf.FakeImportC && .conf.go115UsesCgo {
return errBadCgo
}
defer .handleBailout(&)
:= func( string) {
if trace {
fmt.Println()
fmt.Println()
}
}
("== initFiles ==")
.initFiles()
("== collectObjects ==")
.collectObjects()
("== packageObjects ==")
.packageObjects()
("== processDelayed ==")
.processDelayed(0)
("== cleanup ==")
.cleanup()
("== initOrder ==")
.initOrder()
if !.conf.DisableUnusedImportCheck {
("== unusedImports ==")
.unusedImports()
}
("== recordUntyped ==")
.recordUntyped()
if .firstErr == nil {
.monomorph()
}
.pkg.complete = true
.imports = nil
.dotImportMap = nil
.pkgPathMap = nil
.seenPkgMap = nil
.recvTParamMap = nil
.brokenAliases = nil
.unionTypeSets = nil
.ctxt = nil
return
}
func ( *Checker) ( int) {
for := ; < len(.delayed); ++ {
:= &.delayed[]
if trace && .desc != nil {
fmt.Println()
.trace(.desc.pos.Pos(), "-- "+.desc.format, .desc.args...)
}
.f()
}
assert( <= len(.delayed))
.delayed = .delayed[:]
}
func ( *Checker) () {
for := 0; < len(.cleaners); ++ {
.cleaners[].cleanup()
}
.cleaners = nil
}
func ( *Checker) ( *operand) {
var Type
var constant.Value
switch .mode {
case invalid:
= Typ[Invalid]
case novalue:
= (*Tuple)(nil)
case constant_:
= .typ
= .val
default:
= .typ
}
assert(.expr != nil && != nil)
if isUntyped() {
.rememberUntyped(.expr, false, .mode, .(*Basic), )
} else {
.recordTypeAndValue(.expr, .mode, , )
}
}
func ( *Checker) () {
if !debug && .Types == nil {
return
}
for , := range .untyped {
if debug && isTyped(.typ) {
.dump("%v: %s (type %s) is typed", .Pos(), , .typ)
unreachable()
}
.recordTypeAndValue(, .mode, .typ, .val)
}
}
func ( *Checker) ( ast.Expr, operandMode, Type, constant.Value) {
assert( != nil)
assert( != nil)
if == invalid {
return
}
if == constant_ {
assert( != nil)
assert( == Typ[Invalid] || allBasic(, IsConstType))
}
if := .Types; != nil {
[] = TypeAndValue{, , }
}
}
func ( *Checker) ( ast.Expr, *Signature) {
for {
.recordTypeAndValue(, builtin, , nil)
switch p := .(type) {
case *ast.Ident, *ast.SelectorExpr:
return
case *ast.ParenExpr:
= .X
default:
unreachable()
}
}
}
func ( *Checker) ( ast.Expr, [2]Type) {
assert( != nil)
if [0] == nil || [1] == nil {
return
}
assert(isTyped([0]) && isTyped([1]) && (isBoolean([1]) || [1] == universeError))
if := .Types; != nil {
for {
:= []
assert(.Type != nil)
:= .Pos()
.Type = NewTuple(
NewVar(, .pkg, "", [0]),
NewVar(, .pkg, "", [1]),
)
[] =
, := .(*ast.ParenExpr)
if == nil {
break
}
= .X
}
}
}
func ( *Checker) ( ast.Expr, []Type, Type) {
:= instantiatedIdent()
assert( != nil)
assert( != nil)
if := .Instances; != nil {
[] = Instance{newTypeList(), }
}
}
func ( ast.Expr) *ast.Ident {
var ast.Expr
switch e := .(type) {
case *ast.IndexExpr:
= .X
case *ast.IndexListExpr:
= .X
case *ast.SelectorExpr, *ast.Ident:
=
}
switch x := .(type) {
case *ast.Ident:
return
case *ast.SelectorExpr:
return .Sel
}
panic("instantiated ident not found")
}
func ( *Checker) ( *ast.Ident, Object) {
assert( != nil)
if := .Defs; != nil {
[] =
}
}
func ( *Checker) ( *ast.Ident, Object) {
assert( != nil)
assert( != nil)
if := .Uses; != nil {
[] =
}
}
func ( *Checker) ( ast.Node, Object) {
assert( != nil)
assert( != nil)
if := .Implicits; != nil {
[] =
}
}
func ( *Checker) ( *ast.SelectorExpr, SelectionKind, Type, Object, []int, bool) {
assert( != nil && ( == nil || len() > 0))
.recordUse(.Sel, )
if := .Selections; != nil {
[] = &Selection{, , , , }
}
}
func ( *Checker) ( ast.Node, *Scope) {
assert( != nil)
assert( != nil)
if := .Scopes; != nil {
[] =
}
}