mirror of
https://github.com/golang/go
synced 2024-11-18 18:54:42 -07:00
go.tools/go/types: Factories for all objects
R=adonovan CC=golang-dev https://golang.org/cl/9794044
This commit is contained in:
parent
fc4c97d1f1
commit
221795b447
@ -112,7 +112,7 @@ type Context struct {
|
|||||||
// of the given struct fields, in bytes. Otherwise DefaultOffsetsof
|
// of the given struct fields, in bytes. Otherwise DefaultOffsetsof
|
||||||
// is called. Offsetsof must implement the offset guarantees
|
// is called. Offsetsof must implement the offset guarantees
|
||||||
// required by the spec.
|
// required by the spec.
|
||||||
Offsetsof func(fields []*Field) []int64
|
Offsetsof func(fields *Scope) []int64
|
||||||
|
|
||||||
// If Sizeof != nil, it is called to determine the size of the
|
// If Sizeof != nil, it is called to determine the size of the
|
||||||
// given type. Otherwise, DefaultSizeof is called. Sizeof must
|
// given type. Otherwise, DefaultSizeof is called. Sizeof must
|
||||||
|
@ -232,8 +232,8 @@ func TestCheck(t *testing.T) {
|
|||||||
if !testBuiltinsDeclared {
|
if !testBuiltinsDeclared {
|
||||||
testBuiltinsDeclared = true
|
testBuiltinsDeclared = true
|
||||||
// Pkg == nil for Universe objects
|
// Pkg == nil for Universe objects
|
||||||
def(&Func{name: "assert", typ: &Builtin{_Assert, "assert", 1, false, true}})
|
def(NewFunc(token.NoPos, nil, "assert", &Builtin{_Assert, "assert", 1, false, true}))
|
||||||
def(&Func{name: "trace", typ: &Builtin{_Trace, "trace", 0, true, true}})
|
def(NewFunc(token.NoPos, nil, "trace", &Builtin{_Trace, "trace", 0, true, true}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// For easy debugging w/o changing the testing code,
|
// For easy debugging w/o changing the testing code,
|
||||||
|
@ -259,15 +259,16 @@ func writeType(buf *bytes.Buffer, typ Type) {
|
|||||||
case *Struct:
|
case *Struct:
|
||||||
buf.WriteString("struct{")
|
buf.WriteString("struct{")
|
||||||
if t.fields != nil {
|
if t.fields != nil {
|
||||||
for i, f := range t.fields {
|
for i, obj := range t.fields.entries {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buf.WriteString("; ")
|
buf.WriteString("; ")
|
||||||
}
|
}
|
||||||
if !f.IsAnonymous {
|
f := obj.(*Field)
|
||||||
buf.WriteString(f.Name)
|
if !f.anonymous {
|
||||||
|
buf.WriteString(f.name)
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
writeType(buf, f.Type)
|
writeType(buf, f.typ)
|
||||||
if tag := t.Tag(i); tag != "" {
|
if tag := t.Tag(i); tag != "" {
|
||||||
fmt.Fprintf(buf, " %q", tag)
|
fmt.Fprintf(buf, " %q", tag)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
|
|||||||
if len(field.Names) > 0 {
|
if len(field.Names) > 0 {
|
||||||
// named parameter
|
// named parameter
|
||||||
for _, name := range field.Names {
|
for _, name := range field.Names {
|
||||||
par := &Var{pos: name.Pos(), pkg: check.pkg, name: name.Name, typ: typ}
|
par := NewVar(name.Pos(), check.pkg, name.Name, typ)
|
||||||
check.declare(scope, name, par)
|
check.declare(scope, name, par)
|
||||||
|
|
||||||
last = par
|
last = par
|
||||||
@ -101,7 +101,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// anonymous parameter
|
// anonymous parameter
|
||||||
par := &Var{pkg: check.pkg, typ: typ}
|
par := NewVar(ftype.Pos(), check.pkg, "", typ)
|
||||||
check.callImplicitObj(field, par)
|
check.callImplicitObj(field, par)
|
||||||
|
|
||||||
last = nil // not accessible inside function
|
last = nil // not accessible inside function
|
||||||
@ -138,7 +138,7 @@ func (check *checker) collectMethods(scope *Scope, list *ast.FieldList) *Scope {
|
|||||||
// TODO(gri) provide correct declaration info and scope
|
// TODO(gri) provide correct declaration info and scope
|
||||||
// TODO(gri) with unified scopes (Scope, ObjSet) this can become
|
// TODO(gri) with unified scopes (Scope, ObjSet) this can become
|
||||||
// just a normal declaration
|
// just a normal declaration
|
||||||
obj := &Func{name.Pos(), check.pkg, nil, name.Name, sig, nil}
|
obj := NewFunc(name.Pos(), check.pkg, name.Name, sig)
|
||||||
if alt := methods.Insert(obj); alt != nil {
|
if alt := methods.Insert(obj); alt != nil {
|
||||||
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
|
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
|
||||||
if pos := alt.Pos(); pos.IsValid() {
|
if pos := alt.Pos(); pos.IsValid() {
|
||||||
@ -182,26 +182,24 @@ func (check *checker) tag(t *ast.BasicLit) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *checker) collectFields(scope *Scope, list *ast.FieldList, cycleOk bool) (fields []*Field, tags []string) {
|
func (check *checker) collectFields(scope *Scope, list *ast.FieldList, cycleOk bool) (tags []string) {
|
||||||
if list == nil {
|
if list == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var typ Type // current field typ
|
var typ Type // current field typ
|
||||||
var tag string // current field tag
|
var tag string // current field tag
|
||||||
add := func(field *ast.Field, ident *ast.Ident, name string, isAnonymous bool, pos token.Pos) {
|
add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) {
|
||||||
// TODO(gri): rethink this - at the moment we allocate only a prefix
|
// TODO(gri): rethink this - at the moment we allocate only a prefix
|
||||||
if tag != "" && tags == nil {
|
if tag != "" && tags == nil {
|
||||||
tags = make([]string, len(fields))
|
tags = make([]string, scope.NumEntries())
|
||||||
}
|
}
|
||||||
if tags != nil {
|
if tags != nil {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fld := &Var{pos: pos, pkg: check.pkg, name: name, typ: typ}
|
fld := NewField(pos, check.pkg, name, typ, anonymous)
|
||||||
check.declare(scope, ident, fld)
|
check.declare(scope, ident, fld)
|
||||||
|
|
||||||
fields = append(fields, &Field{check.pkg, name, typ, isAnonymous, fld})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range list.List {
|
for _, f := range list.List {
|
||||||
@ -1072,7 +1070,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
|
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *Package:
|
case *Package:
|
||||||
check.errorf(e.Pos(), "use of package %s not in selector", obj.Name)
|
check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
|
||||||
goto Error
|
goto Error
|
||||||
case *Const:
|
case *Const:
|
||||||
if obj.typ == Typ[Invalid] {
|
if obj.typ == Typ[Invalid] {
|
||||||
@ -1161,7 +1159,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
fields := utyp.fields
|
fields := utyp.fields
|
||||||
if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
|
if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
|
||||||
// all elements must have keys
|
// all elements must have keys
|
||||||
visited := make([]bool, len(fields))
|
visited := make([]bool, fields.NumEntries())
|
||||||
for _, e := range e.Elts {
|
for _, e := range e.Elts {
|
||||||
kv, _ := e.(*ast.KeyValueExpr)
|
kv, _ := e.(*ast.KeyValueExpr)
|
||||||
if kv == nil {
|
if kv == nil {
|
||||||
@ -1173,12 +1171,13 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
|
check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
i := utyp.fieldIndex(check.pkg, key.Name)
|
i := utyp.fields.Index(check.pkg, key.Name)
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
|
check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
check.callIdent(key, fields[i].obj)
|
fld := fields.At(i).(*Field)
|
||||||
|
check.callIdent(key, fld)
|
||||||
// 0 <= i < len(fields)
|
// 0 <= i < len(fields)
|
||||||
if visited[i] {
|
if visited[i] {
|
||||||
check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
|
check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
|
||||||
@ -1186,7 +1185,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
}
|
}
|
||||||
visited[i] = true
|
visited[i] = true
|
||||||
check.expr(x, kv.Value, nil, iota)
|
check.expr(x, kv.Value, nil, iota)
|
||||||
etyp := fields[i].Type
|
etyp := fld.typ
|
||||||
if !check.assignment(x, etyp) {
|
if !check.assignment(x, etyp) {
|
||||||
if x.mode != invalid {
|
if x.mode != invalid {
|
||||||
check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
|
check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
|
||||||
@ -1202,12 +1201,12 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
check.expr(x, e, nil, iota)
|
check.expr(x, e, nil, iota)
|
||||||
if i >= len(fields) {
|
if i >= fields.NumEntries() {
|
||||||
check.errorf(x.pos(), "too many values in struct literal")
|
check.errorf(x.pos(), "too many values in struct literal")
|
||||||
break // cannot continue
|
break // cannot continue
|
||||||
}
|
}
|
||||||
// i < len(fields)
|
// i < len(fields)
|
||||||
etyp := fields[i].Type
|
etyp := fields.At(i).Type()
|
||||||
if !check.assignment(x, etyp) {
|
if !check.assignment(x, etyp) {
|
||||||
if x.mode != invalid {
|
if x.mode != invalid {
|
||||||
check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
|
check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
|
||||||
@ -1215,7 +1214,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(e.Elts) < len(fields) {
|
if len(e.Elts) < fields.NumEntries() {
|
||||||
check.errorf(e.Rbrace, "too few values in struct literal")
|
check.errorf(e.Rbrace, "too few values in struct literal")
|
||||||
// ok to continue
|
// ok to continue
|
||||||
}
|
}
|
||||||
@ -1346,7 +1345,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
}
|
}
|
||||||
x.mode = value
|
x.mode = value
|
||||||
x.typ = &Signature{
|
x.typ = &Signature{
|
||||||
params: NewTuple(append([]*Var{{typ: x.typ}}, params...)...),
|
params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
|
||||||
results: sig.results,
|
results: sig.results,
|
||||||
isVariadic: sig.isVariadic,
|
isVariadic: sig.isVariadic,
|
||||||
}
|
}
|
||||||
@ -1703,9 +1702,9 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
|
|
||||||
case *ast.StructType:
|
case *ast.StructType:
|
||||||
scope := NewScope(check.topScope)
|
scope := NewScope(check.topScope)
|
||||||
fields, tags := check.collectFields(scope, e.Fields, cycleOk)
|
tags := check.collectFields(scope, e.Fields, cycleOk)
|
||||||
x.mode = typexpr
|
x.mode = typexpr
|
||||||
x.typ = &Struct{scope: scope, fields: fields, tags: tags}
|
x.typ = &Struct{fields: scope, tags: tags}
|
||||||
|
|
||||||
case *ast.FuncType:
|
case *ast.FuncType:
|
||||||
scope := NewScope(check.topScope)
|
scope := NewScope(check.topScope)
|
||||||
|
@ -206,7 +206,7 @@ func declConst(pkg *Package, name string) *Const {
|
|||||||
return obj.(*Const)
|
return obj.(*Const)
|
||||||
}
|
}
|
||||||
// otherwise create a new constant and insert it into the scope
|
// otherwise create a new constant and insert it into the scope
|
||||||
obj := &Const{pkg: pkg, name: name}
|
obj := NewConst(token.NoPos, pkg, name, nil, nil)
|
||||||
scope.Insert(obj)
|
scope.Insert(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ func declTypeName(pkg *Package, name string) *TypeName {
|
|||||||
if obj := scope.Lookup(nil, name); obj != nil {
|
if obj := scope.Lookup(nil, name); obj != nil {
|
||||||
return obj.(*TypeName)
|
return obj.(*TypeName)
|
||||||
}
|
}
|
||||||
obj := &TypeName{pkg: pkg, name: name}
|
obj := NewTypeName(token.NoPos, pkg, name, nil)
|
||||||
// a named type may be referred to before the underlying type
|
// a named type may be referred to before the underlying type
|
||||||
// is known - set it up
|
// is known - set it up
|
||||||
obj.typ = &Named{obj: obj}
|
obj.typ = &Named{obj: obj}
|
||||||
@ -229,7 +229,7 @@ func declVar(pkg *Package, name string) *Var {
|
|||||||
if obj := scope.Lookup(nil, name); obj != nil {
|
if obj := scope.Lookup(nil, name); obj != nil {
|
||||||
return obj.(*Var)
|
return obj.(*Var)
|
||||||
}
|
}
|
||||||
obj := &Var{pkg: pkg, name: name}
|
obj := NewVar(token.NoPos, pkg, name, nil)
|
||||||
scope.Insert(obj)
|
scope.Insert(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func declFunc(pkg *Package, name string) *Func {
|
|||||||
if obj := scope.Lookup(nil, name); obj != nil {
|
if obj := scope.Lookup(nil, name); obj != nil {
|
||||||
return obj.(*Func)
|
return obj.(*Func)
|
||||||
}
|
}
|
||||||
obj := &Func{pkg: pkg, name: name}
|
obj := NewFunc(token.NoPos, pkg, name, nil)
|
||||||
scope.Insert(obj)
|
scope.Insert(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@ -360,7 +360,7 @@ func (p *gcParser) getPkg(id, name string) *Package {
|
|||||||
}
|
}
|
||||||
pkg := p.imports[id]
|
pkg := p.imports[id]
|
||||||
if pkg == nil && name != "" {
|
if pkg == nil && name != "" {
|
||||||
pkg = &Package{name: name, path: id, scope: NewScope(nil)}
|
pkg = NewPackage(token.NoPos, id, name, NewScope(nil), nil, false)
|
||||||
p.imports[id] = pkg
|
p.imports[id] = pkg
|
||||||
}
|
}
|
||||||
return pkg
|
return pkg
|
||||||
@ -459,50 +459,55 @@ func (p *gcParser) parseName(materializePkg bool) (pkg *Package, name string) {
|
|||||||
// Field = Name Type [ string_lit ] .
|
// Field = Name Type [ string_lit ] .
|
||||||
//
|
//
|
||||||
func (p *gcParser) parseField() (*Field, string) {
|
func (p *gcParser) parseField() (*Field, string) {
|
||||||
var f Field
|
pkg, name := p.parseName(true)
|
||||||
f.Pkg, f.Name = p.parseName(true)
|
typ := p.parseType()
|
||||||
f.Type = p.parseType()
|
anonymous := false
|
||||||
|
if name == "" {
|
||||||
|
// anonymous field - typ must be T or *T and T must be a type name
|
||||||
|
switch typ := typ.Deref().(type) {
|
||||||
|
case *Basic: // basic types are named types
|
||||||
|
name = typ.name
|
||||||
|
case *Named:
|
||||||
|
name = typ.obj.name
|
||||||
|
default:
|
||||||
|
p.errorf("anonymous field expected")
|
||||||
|
}
|
||||||
|
anonymous = true
|
||||||
|
}
|
||||||
tag := ""
|
tag := ""
|
||||||
if p.tok == scanner.String {
|
if p.tok == scanner.String {
|
||||||
tag = p.expect(scanner.String)
|
tag = p.expect(scanner.String)
|
||||||
}
|
}
|
||||||
if f.Name == "" {
|
return NewField(token.NoPos, pkg, name, typ, anonymous), tag
|
||||||
// anonymous field - typ must be T or *T and T must be a type name
|
|
||||||
switch typ := f.Type.Deref().(type) {
|
|
||||||
case *Basic: // basic types are named types
|
|
||||||
f.Name = typ.name
|
|
||||||
case *Named:
|
|
||||||
f.Name = typ.obj.name
|
|
||||||
default:
|
|
||||||
p.errorf("anonymous field expected")
|
|
||||||
}
|
|
||||||
f.IsAnonymous = true
|
|
||||||
}
|
|
||||||
return &f, tag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructType = "struct" "{" [ FieldList ] "}" .
|
// StructType = "struct" "{" [ FieldList ] "}" .
|
||||||
// FieldList = Field { ";" Field } .
|
// FieldList = Field { ";" Field } .
|
||||||
//
|
//
|
||||||
func (p *gcParser) parseStructType() Type {
|
func (p *gcParser) parseStructType() Type {
|
||||||
var fields []*Field
|
var fields *Scope // lazily initialized
|
||||||
var tags []string
|
var tags []string
|
||||||
|
|
||||||
p.expectKeyword("struct")
|
p.expectKeyword("struct")
|
||||||
p.expect('{')
|
p.expect('{')
|
||||||
for p.tok != '}' {
|
for i := 0; p.tok != '}'; i++ {
|
||||||
if len(fields) > 0 {
|
if i > 0 {
|
||||||
p.expect(';')
|
p.expect(';')
|
||||||
}
|
}
|
||||||
fld, tag := p.parseField()
|
fld, tag := p.parseField()
|
||||||
// TODO(gri) same code in collectFields (expr.go) - factor?
|
// TODO(gri) same code in collectFields (expr.go) - factor?
|
||||||
if tag != "" && tags == nil {
|
if tag != "" && tags == nil {
|
||||||
tags = make([]string, len(fields))
|
tags = make([]string, i)
|
||||||
}
|
}
|
||||||
if tags != nil {
|
if tags != nil {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
fields = append(fields, fld)
|
if fields == nil {
|
||||||
|
fields = NewScope(nil)
|
||||||
|
}
|
||||||
|
if alt := fields.Insert(fld); alt != nil {
|
||||||
|
p.errorf("multiple fields named %s.%s", alt.Pkg().name, alt.Name())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.expect('}')
|
p.expect('}')
|
||||||
|
|
||||||
@ -525,7 +530,8 @@ func (p *gcParser) parseParameter() (par *Var, isVariadic bool) {
|
|||||||
if p.tok == scanner.String {
|
if p.tok == scanner.String {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
par = &Var{name: name, typ: typ} // Pkg == nil
|
// TODO(gri) should we provide a package?
|
||||||
|
par = NewVar(token.NoPos, nil, name, typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +599,7 @@ func (p *gcParser) parseInterfaceType() Type {
|
|||||||
if methods == nil {
|
if methods == nil {
|
||||||
methods = NewScope(nil)
|
methods = NewScope(nil)
|
||||||
}
|
}
|
||||||
if alt := methods.Insert(&Func{token.NoPos, pkg, nil, name, sig, nil}); alt != nil {
|
if alt := methods.Insert(NewFunc(token.NoPos, pkg, name, sig)); alt != nil {
|
||||||
p.errorf("multiple methods named %s.%s", alt.Pkg().name, alt.Name())
|
p.errorf("multiple methods named %s.%s", alt.Pkg().name, alt.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -885,7 +891,7 @@ func (p *gcParser) parseMethodDecl() {
|
|||||||
if base.methods == nil {
|
if base.methods == nil {
|
||||||
base.methods = NewScope(nil)
|
base.methods = NewScope(nil)
|
||||||
}
|
}
|
||||||
base.methods.Insert(&Func{token.NoPos, pkg, nil, name, sig, nil})
|
base.methods.Insert(NewFunc(token.NoPos, pkg, name, sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncDecl = "func" ExportedName Func .
|
// FuncDecl = "func" ExportedName Func .
|
||||||
|
@ -11,141 +11,136 @@ import (
|
|||||||
"code.google.com/p/go.tools/go/exact"
|
"code.google.com/p/go.tools/go/exact"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(gri) provide a complete set of factory functions!
|
|
||||||
// TODO(gri) All objects looks very similar now. Maybe just have single Object struct with an object kind?
|
// TODO(gri) All objects looks very similar now. Maybe just have single Object struct with an object kind?
|
||||||
|
// TODO(gri) Document factory, accessor methods, and fields.
|
||||||
|
|
||||||
// An Object describes a named language entity such as a package,
|
// An Object describes a named language entity such as a package,
|
||||||
// constant, type, variable, function (incl. methods), or label.
|
// constant, type, variable, function (incl. methods), or label.
|
||||||
// All objects implement the Object interface.
|
// All objects implement the Object interface.
|
||||||
//
|
//
|
||||||
type Object interface {
|
type Object interface {
|
||||||
Pkg() *Package // nil for objects in the Universe scope and labels
|
|
||||||
Parent() *Scope // the scope in which this object is declared
|
Parent() *Scope // the scope in which this object is declared
|
||||||
Name() string
|
|
||||||
Type() Type
|
|
||||||
Pos() token.Pos // position of object identifier in declaration
|
Pos() token.Pos // position of object identifier in declaration
|
||||||
// TODO(gri) provide String method!
|
Pkg() *Package // nil for objects in the Universe scope and labels
|
||||||
|
Name() string // the package local object name
|
||||||
|
Type() Type // the object type
|
||||||
|
|
||||||
setParent(*Scope)
|
setParent(*Scope)
|
||||||
|
|
||||||
|
// TODO(gri) provide String method!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An object implements the common parts of an Object.
|
||||||
|
type object struct {
|
||||||
|
parent *Scope
|
||||||
|
pos token.Pos
|
||||||
|
pkg *Package
|
||||||
|
name string
|
||||||
|
typ Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj *object) Parent() *Scope { return obj.parent }
|
||||||
|
func (obj *object) Pos() token.Pos { return obj.pos }
|
||||||
|
func (obj *object) Pkg() *Package { return obj.pkg }
|
||||||
|
func (obj *object) Name() string { return obj.name }
|
||||||
|
func (obj *object) Type() Type { return obj.typ }
|
||||||
|
|
||||||
|
func (obj *object) setParent(parent *Scope) { obj.parent = parent }
|
||||||
|
|
||||||
// A Package represents the contents (objects) of a Go package.
|
// A Package represents the contents (objects) of a Go package.
|
||||||
type Package struct {
|
type Package struct {
|
||||||
pos token.Pos // position of package import path or local package identifier, if present
|
object
|
||||||
name string
|
path string // import path, "" for current (non-imported) package
|
||||||
path string // import path, "" for current (non-imported) package
|
scope *Scope // imported objects
|
||||||
parent *Scope
|
|
||||||
scope *Scope // package-level scope
|
|
||||||
imports map[string]*Package // map of import paths to imported packages
|
imports map[string]*Package // map of import paths to imported packages
|
||||||
complete bool // if set, this package was imported completely
|
complete bool // if set, this package was imported completely
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPackage(path, name string) *Package {
|
func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package, complete bool) *Package {
|
||||||
return &Package{name: name, path: path, complete: true}
|
obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, complete}
|
||||||
|
obj.pkg = obj
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Package) Pkg() *Package { return obj }
|
|
||||||
func (obj *Package) Parent() *Scope { return obj.parent }
|
|
||||||
func (obj *Package) Scope() *Scope { return obj.scope }
|
|
||||||
func (obj *Package) Name() string { return obj.name }
|
|
||||||
func (obj *Package) Type() Type { return Typ[Invalid] }
|
|
||||||
func (obj *Package) Pos() token.Pos { return obj.pos }
|
|
||||||
func (obj *Package) Path() string { return obj.path }
|
func (obj *Package) Path() string { return obj.path }
|
||||||
|
func (obj *Package) Scope() *Scope { return obj.scope }
|
||||||
func (obj *Package) Imports() map[string]*Package { return obj.imports }
|
func (obj *Package) Imports() map[string]*Package { return obj.imports }
|
||||||
func (obj *Package) Complete() bool { return obj.complete }
|
func (obj *Package) Complete() bool { return obj.complete }
|
||||||
func (obj *Package) setParent(*Scope) { /* don't do anything - this is the package's scope */
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Const represents a declared constant.
|
// A Const represents a declared constant.
|
||||||
type Const struct {
|
type Const struct {
|
||||||
pos token.Pos // position of identifier in constant declaration
|
object
|
||||||
pkg *Package
|
val exact.Value
|
||||||
parent *Scope
|
|
||||||
name string
|
|
||||||
typ Type
|
|
||||||
val exact.Value
|
|
||||||
|
|
||||||
visited bool // for initialization cycle detection
|
visited bool // for initialization cycle detection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Const) Pkg() *Package { return obj.pkg }
|
func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
|
||||||
func (obj *Const) Parent() *Scope { return obj.parent }
|
return &Const{object{nil, pos, pkg, name, typ}, val, false}
|
||||||
func (obj *Const) Name() string { return obj.name }
|
}
|
||||||
func (obj *Const) Type() Type { return obj.typ }
|
|
||||||
func (obj *Const) Pos() token.Pos { return obj.pos }
|
func (obj *Const) Val() exact.Value { return obj.val }
|
||||||
func (obj *Const) Val() exact.Value { return obj.val }
|
|
||||||
func (obj *Const) setParent(s *Scope) { obj.parent = s }
|
|
||||||
|
|
||||||
// A TypeName represents a declared type.
|
// A TypeName represents a declared type.
|
||||||
type TypeName struct {
|
type TypeName struct {
|
||||||
pos token.Pos // position of identifier in type declaration
|
object
|
||||||
pkg *Package
|
|
||||||
parent *Scope
|
|
||||||
name string
|
|
||||||
typ Type // *Named or *Basic
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTypeName(pkg *Package, name string, typ Type) *TypeName {
|
func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
||||||
return &TypeName{token.NoPos, pkg, nil, name, typ}
|
return &TypeName{object{nil, pos, pkg, name, typ}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *TypeName) Pkg() *Package { return obj.pkg }
|
|
||||||
func (obj *TypeName) Parent() *Scope { return obj.parent }
|
|
||||||
func (obj *TypeName) Name() string { return obj.name }
|
|
||||||
func (obj *TypeName) Type() Type { return obj.typ }
|
|
||||||
func (obj *TypeName) Pos() token.Pos { return obj.pos }
|
|
||||||
func (obj *TypeName) setParent(s *Scope) { obj.parent = s }
|
|
||||||
|
|
||||||
// A Variable represents a declared variable (including function parameters and results).
|
// A Variable represents a declared variable (including function parameters and results).
|
||||||
type Var struct {
|
type Var struct {
|
||||||
pos token.Pos // position of identifier in variable declaration
|
object
|
||||||
pkg *Package // nil for parameters
|
|
||||||
parent *Scope
|
|
||||||
name string
|
|
||||||
typ Type
|
|
||||||
|
|
||||||
visited bool // for initialization cycle detection
|
visited bool // for initialization cycle detection
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVar(pkg *Package, name string, typ Type) *Var {
|
func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
||||||
return &Var{token.NoPos, pkg, nil, name, typ, false}
|
return &Var{object{nil, pos, pkg, name, typ}, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Var) Pkg() *Package { return obj.pkg }
|
// A Field represents a struct field.
|
||||||
func (obj *Var) Parent() *Scope { return obj.parent }
|
type Field struct {
|
||||||
func (obj *Var) Name() string { return obj.name }
|
object
|
||||||
func (obj *Var) Type() Type { return obj.typ }
|
anonymous bool
|
||||||
func (obj *Var) Pos() token.Pos { return obj.pos }
|
}
|
||||||
func (obj *Var) setParent(s *Scope) { obj.parent = s }
|
|
||||||
|
func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Field {
|
||||||
|
return &Field{object{nil, pos, pkg, name, typ}, anonymous}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj *Field) Anonymous() bool { return obj.anonymous }
|
||||||
|
|
||||||
|
func (f *Field) isMatch(pkg *Package, name string) bool {
|
||||||
|
// spec:
|
||||||
|
// "Two identifiers are different if they are spelled differently,
|
||||||
|
// or if they appear in different packages and are not exported.
|
||||||
|
// Otherwise, they are the same."
|
||||||
|
if name != f.name {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// f.Name == name
|
||||||
|
return ast.IsExported(name) || pkg.path == f.pkg.path
|
||||||
|
}
|
||||||
|
|
||||||
// A Func represents a declared function.
|
// A Func represents a declared function.
|
||||||
type Func struct {
|
type Func struct {
|
||||||
pos token.Pos
|
object
|
||||||
pkg *Package
|
|
||||||
parent *Scope
|
|
||||||
name string
|
|
||||||
typ Type // *Signature or *Builtin
|
|
||||||
|
|
||||||
decl *ast.FuncDecl // TODO(gri) can we get rid of this field?
|
decl *ast.FuncDecl // TODO(gri) can we get rid of this field?
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Func) Pkg() *Package { return obj.pkg }
|
func NewFunc(pos token.Pos, pkg *Package, name string, typ Type) *Func {
|
||||||
func (obj *Func) Parent() *Scope { return obj.parent }
|
return &Func{object{nil, pos, pkg, name, typ}, nil}
|
||||||
func (obj *Func) Name() string { return obj.name }
|
}
|
||||||
func (obj *Func) Type() Type { return obj.typ }
|
|
||||||
func (obj *Func) Pos() token.Pos { return obj.pos }
|
|
||||||
func (obj *Func) setParent(s *Scope) { obj.parent = s }
|
|
||||||
|
|
||||||
// A Label represents a declared label.
|
// A Label represents a declared label.
|
||||||
type Label struct {
|
type Label struct {
|
||||||
pos token.Pos
|
object
|
||||||
parent *Scope
|
|
||||||
name string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Label) Pkg() *Package { return nil }
|
func NewLabel(pos token.Pos, name string) *Label {
|
||||||
func (obj *Label) Parent() *Scope { return obj.parent }
|
return &Label{object{nil, pos, nil, name, nil}}
|
||||||
func (obj *Label) Name() string { return obj.name }
|
}
|
||||||
func (obj *Label) Type() Type { return nil }
|
|
||||||
func (obj *Label) Pos() token.Pos { return obj.pos }
|
|
||||||
func (obj *Label) setParent(s *Scope) { obj.parent = s }
|
|
||||||
|
@ -275,10 +275,14 @@ func lookupFieldBreadthFirst(list []embeddedType, pkg *Package, name string) (re
|
|||||||
switch t := typ.underlying.(type) {
|
switch t := typ.underlying.(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
// look for a matching field and collect embedded types
|
// look for a matching field and collect embedded types
|
||||||
for i, f := range t.fields {
|
if t.fields == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for i, obj := range t.fields.entries {
|
||||||
|
f := obj.(*Field)
|
||||||
if f.isMatch(pkg, name) {
|
if f.isMatch(pkg, name) {
|
||||||
assert(f.Type != nil)
|
assert(f.typ != nil)
|
||||||
if !potentialMatch(e.multiples, variable, f.Type) {
|
if !potentialMatch(e.multiples, variable, f.typ) {
|
||||||
return // name collision
|
return // name collision
|
||||||
}
|
}
|
||||||
var index []int
|
var index []int
|
||||||
@ -296,10 +300,10 @@ func lookupFieldBreadthFirst(list []embeddedType, pkg *Package, name string) (re
|
|||||||
// T is a named type. If typ appeared multiple times at
|
// T is a named type. If typ appeared multiple times at
|
||||||
// this level, f.Type appears multiple times at the next
|
// this level, f.Type appears multiple times at the next
|
||||||
// level.
|
// level.
|
||||||
if f.IsAnonymous && res.mode == invalid {
|
if f.anonymous && res.mode == invalid {
|
||||||
// Ignore embedded basic types - only user-defined
|
// Ignore embedded basic types - only user-defined
|
||||||
// named types can have methods or have struct fields.
|
// named types can have methods or have struct fields.
|
||||||
if t, _ := f.Type.Deref().(*Named); t != nil {
|
if t, _ := f.typ.Deref().(*Named); t != nil {
|
||||||
var index []int
|
var index []int
|
||||||
index = append(index, e.index...) // copy e.index
|
index = append(index, e.index...) // copy e.index
|
||||||
index = append(index, i)
|
index = append(index, i)
|
||||||
@ -370,18 +374,22 @@ func lookupField(typ Type, pkg *Package, name string) lookupResult {
|
|||||||
|
|
||||||
switch t := typ.(type) {
|
switch t := typ.(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
|
if t.fields == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
var next []embeddedType
|
var next []embeddedType
|
||||||
for i, f := range t.fields {
|
for i, obj := range t.fields.entries {
|
||||||
|
f := obj.(*Field)
|
||||||
if f.isMatch(pkg, name) {
|
if f.isMatch(pkg, name) {
|
||||||
return lookupResult{variable, f.Type, []int{i}}
|
return lookupResult{variable, f.typ, []int{i}}
|
||||||
}
|
}
|
||||||
if f.IsAnonymous {
|
if f.anonymous {
|
||||||
// Possible optimization: If the embedded type
|
// Possible optimization: If the embedded type
|
||||||
// is a pointer to the current type we could
|
// is a pointer to the current type we could
|
||||||
// ignore it.
|
// ignore it.
|
||||||
// Ignore embedded basic types - only user-defined
|
// Ignore embedded basic types - only user-defined
|
||||||
// named types can have methods or have struct fields.
|
// named types can have methods or have struct fields.
|
||||||
if t, _ := f.Type.Deref().(*Named); t != nil {
|
if t, _ := f.typ.Deref().(*Named); t != nil {
|
||||||
next = append(next, embeddedType{t, []int{i}, false})
|
next = append(next, embeddedType{t, []int{i}, false})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,9 +72,11 @@ func isComparable(typ Type) bool {
|
|||||||
// assumes types are equal for pointers and channels
|
// assumes types are equal for pointers and channels
|
||||||
return true
|
return true
|
||||||
case *Struct:
|
case *Struct:
|
||||||
for _, f := range t.fields {
|
if t.fields != nil {
|
||||||
if !isComparable(f.Type) {
|
for _, f := range t.fields.entries {
|
||||||
return false
|
if !isComparable(f.Type()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -126,14 +128,17 @@ func IsIdentical(x, y Type) bool {
|
|||||||
// and identical tags. Two anonymous fields are considered to have the same
|
// and identical tags. Two anonymous fields are considered to have the same
|
||||||
// name. Lower-case field names from different packages are always different.
|
// name. Lower-case field names from different packages are always different.
|
||||||
if y, ok := y.(*Struct); ok {
|
if y, ok := y.(*Struct); ok {
|
||||||
if len(x.fields) == len(y.fields) {
|
if x.NumFields() == y.NumFields() {
|
||||||
for i, f := range x.fields {
|
if x.fields != nil {
|
||||||
g := y.fields[i]
|
for i, obj := range x.fields.entries {
|
||||||
if f.IsAnonymous != g.IsAnonymous ||
|
f := obj.(*Field)
|
||||||
x.Tag(i) != y.Tag(i) ||
|
g := y.fields.At(i).(*Field)
|
||||||
!f.isMatch(g.Pkg, g.Name) ||
|
if f.anonymous != g.anonymous ||
|
||||||
!IsIdentical(f.Type, g.Type) {
|
x.Tag(i) != y.Tag(i) ||
|
||||||
return false
|
!f.isMatch(g.pkg, g.name) ||
|
||||||
|
!IsIdentical(f.typ, g.typ) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -119,7 +119,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
name = s.Name.Name
|
name = s.Name.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
imp2 := &Package{name: name, scope: imp.scope}
|
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil, imp.complete)
|
||||||
if s.Name != nil {
|
if s.Name != nil {
|
||||||
check.callIdent(s.Name, imp2)
|
check.callIdent(s.Name, imp2)
|
||||||
} else {
|
} else {
|
||||||
@ -155,7 +155,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
|
|
||||||
// declare all constants
|
// declare all constants
|
||||||
for i, name := range s.Names {
|
for i, name := range s.Names {
|
||||||
obj := &Const{pos: name.Pos(), pkg: pkg, name: name.Name, val: exact.MakeInt64(int64(iota))}
|
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
||||||
check.declare(pkg.scope, name, obj)
|
check.declare(pkg.scope, name, obj)
|
||||||
|
|
||||||
var init ast.Expr
|
var init ast.Expr
|
||||||
@ -181,7 +181,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
// declare all variables
|
// declare all variables
|
||||||
lhs := make([]*Var, len(s.Names))
|
lhs := make([]*Var, len(s.Names))
|
||||||
for i, name := range s.Names {
|
for i, name := range s.Names {
|
||||||
obj := &Var{pos: name.Pos(), pkg: pkg, name: name.Name}
|
obj := NewVar(name.Pos(), pkg, name.Name, nil)
|
||||||
lhs[i] = obj
|
lhs[i] = obj
|
||||||
check.declare(pkg.scope, name, obj)
|
check.declare(pkg.scope, name, obj)
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
obj := &TypeName{pos: s.Name.Pos(), pkg: pkg, name: s.Name.Name}
|
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||||
check.declare(pkg.scope, s.Name, obj)
|
check.declare(pkg.scope, s.Name, obj)
|
||||||
add(obj, s.Type, nil)
|
add(obj, s.Type, nil)
|
||||||
|
|
||||||
@ -233,7 +233,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
methods = append(methods, &mdecl{fileScope, d})
|
methods = append(methods, &mdecl{fileScope, d})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
obj := &Func{pos: d.Name.Pos(), pkg: pkg, name: d.Name.Name, decl: d}
|
obj := NewFunc(d.Name.Pos(), pkg, d.Name.Name, nil)
|
||||||
|
obj.decl = d
|
||||||
if obj.name == "init" {
|
if obj.name == "init" {
|
||||||
// init functions are not visible - don't declare them in package scope
|
// init functions are not visible - don't declare them in package scope
|
||||||
obj.parent = pkg.scope
|
obj.parent = pkg.scope
|
||||||
@ -309,7 +310,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) {
|
|||||||
scope = new(Scope)
|
scope = new(Scope)
|
||||||
check.methods[tname] = scope
|
check.methods[tname] = scope
|
||||||
}
|
}
|
||||||
fun := &Func{pos: m.Name.Pos(), pkg: check.pkg, name: m.Name.Name, decl: m}
|
fun := NewFunc(m.Name.Pos(), check.pkg, m.Name.Name, nil)
|
||||||
|
fun.decl = m
|
||||||
check.declare(scope, m.Name, fun)
|
check.declare(scope, m.Name, fun)
|
||||||
// HACK(gri) change method parent scope to file scope containing the declaration
|
// HACK(gri) change method parent scope to file scope containing the declaration
|
||||||
fun.parent = meth.file // remember the file scope
|
fun.parent = meth.file // remember the file scope
|
||||||
@ -478,9 +480,13 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, cycleOk bool) {
|
|||||||
switch t := named.underlying.(type) {
|
switch t := named.underlying.(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
// struct fields must not conflict with methods
|
// struct fields must not conflict with methods
|
||||||
for _, f := range t.fields {
|
if t.fields == nil {
|
||||||
if m := scope.Lookup(nil, f.Name); m != nil {
|
break
|
||||||
check.errorf(m.Pos(), "type %s has both field and method named %s", obj.name, f.Name)
|
}
|
||||||
|
for _, f := range t.fields.entries {
|
||||||
|
name := f.Name()
|
||||||
|
if m := scope.Lookup(nil, name); m != nil {
|
||||||
|
check.errorf(m.Pos(), "type %s has both field and method named %s", obj.name, name)
|
||||||
// ok to continue
|
// ok to continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -558,7 +564,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||||||
// declare all constants
|
// declare all constants
|
||||||
lhs := make([]*Const, len(s.Names))
|
lhs := make([]*Const, len(s.Names))
|
||||||
for i, name := range s.Names {
|
for i, name := range s.Names {
|
||||||
obj := &Const{pos: name.Pos(), pkg: pkg, name: name.Name, val: exact.MakeInt64(int64(iota))}
|
obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
|
||||||
check.callIdent(name, obj)
|
check.callIdent(name, obj)
|
||||||
lhs[i] = obj
|
lhs[i] = obj
|
||||||
|
|
||||||
@ -588,7 +594,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||||||
// declare all variables
|
// declare all variables
|
||||||
lhs := make([]*Var, len(s.Names))
|
lhs := make([]*Var, len(s.Names))
|
||||||
for i, name := range s.Names {
|
for i, name := range s.Names {
|
||||||
obj := &Var{pos: name.Pos(), pkg: pkg, name: name.Name}
|
obj := NewVar(name.Pos(), pkg, name.Name, nil)
|
||||||
check.callIdent(name, obj)
|
check.callIdent(name, obj)
|
||||||
lhs[i] = obj
|
lhs[i] = obj
|
||||||
}
|
}
|
||||||
@ -633,7 +639,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
obj := &TypeName{pos: s.Name.Pos(), pkg: pkg, name: s.Name.Name}
|
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||||
check.declare(check.topScope, s.Name, obj)
|
check.declare(check.topScope, s.Name, obj)
|
||||||
check.declareType(obj, s.Type, false)
|
check.declareType(obj, s.Type, false)
|
||||||
|
|
||||||
|
@ -18,12 +18,12 @@ func (ctxt *Context) alignof(typ Type) int64 {
|
|||||||
|
|
||||||
func (ctxt *Context) offsetsof(s *Struct) []int64 {
|
func (ctxt *Context) offsetsof(s *Struct) []int64 {
|
||||||
offsets := s.offsets
|
offsets := s.offsets
|
||||||
if offsets == nil {
|
if offsets == nil && s.NumFields() > 0 {
|
||||||
// compute offsets on demand
|
// compute offsets on demand
|
||||||
if f := ctxt.Offsetsof; f != nil {
|
if f := ctxt.Offsetsof; f != nil {
|
||||||
offsets = f(s.fields)
|
offsets = f(s.fields)
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if len(offsets) != len(s.fields) {
|
if len(offsets) != s.NumFields() {
|
||||||
panic("Context.Offsetsof returned the wrong number of offsets")
|
panic("Context.Offsetsof returned the wrong number of offsets")
|
||||||
}
|
}
|
||||||
for _, o := range offsets {
|
for _, o := range offsets {
|
||||||
@ -50,7 +50,7 @@ func (ctxt *Context) offsetof(typ Type, index []int) int64 {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
o += ctxt.offsetsof(s)[i]
|
o += ctxt.offsetsof(s)[i]
|
||||||
typ = s.fields[i].Type
|
typ = s.fields.At(i).Type()
|
||||||
}
|
}
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
@ -84,9 +84,12 @@ func DefaultAlignof(typ Type) int64 {
|
|||||||
// is the largest of the values unsafe.Alignof(x.f) for each
|
// is the largest of the values unsafe.Alignof(x.f) for each
|
||||||
// field f of x, but at least 1."
|
// field f of x, but at least 1."
|
||||||
max := int64(1)
|
max := int64(1)
|
||||||
for _, f := range t.fields {
|
if t.fields != nil {
|
||||||
if a := DefaultAlignof(f.Type); a > max {
|
for _, obj := range t.fields.entries {
|
||||||
max = a
|
f := obj.(*Field)
|
||||||
|
if a := DefaultAlignof(f.typ); a > max {
|
||||||
|
max = a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max
|
return max
|
||||||
@ -110,14 +113,19 @@ func align(x, a int64) int64 {
|
|||||||
|
|
||||||
// DefaultOffsetsof implements the default field offset computation
|
// DefaultOffsetsof implements the default field offset computation
|
||||||
// for unsafe.Offsetof. It is used if Context.Offsetsof == nil.
|
// for unsafe.Offsetof. It is used if Context.Offsetsof == nil.
|
||||||
func DefaultOffsetsof(fields []*Field) []int64 {
|
func DefaultOffsetsof(fields *Scope) []int64 {
|
||||||
offsets := make([]int64, len(fields))
|
n := fields.NumEntries()
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
offsets := make([]int64, n)
|
||||||
var o int64
|
var o int64
|
||||||
for i, f := range fields {
|
for i, obj := range fields.entries {
|
||||||
a := DefaultAlignof(f.Type)
|
f := obj.(*Field)
|
||||||
|
a := DefaultAlignof(f.typ)
|
||||||
o = align(o, a)
|
o = align(o, a)
|
||||||
offsets[i] = o
|
offsets[i] = o
|
||||||
o += DefaultSizeof(f.Type)
|
o += DefaultSizeof(f.typ)
|
||||||
}
|
}
|
||||||
return offsets
|
return offsets
|
||||||
}
|
}
|
||||||
@ -144,7 +152,7 @@ func DefaultSizeof(typ Type) int64 {
|
|||||||
case *Slice:
|
case *Slice:
|
||||||
return DefaultPtrSize * 3
|
return DefaultPtrSize * 3
|
||||||
case *Struct:
|
case *Struct:
|
||||||
n := len(t.fields)
|
n := t.NumFields()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -154,7 +162,7 @@ func DefaultSizeof(typ Type) int64 {
|
|||||||
offsets = DefaultOffsetsof(t.fields)
|
offsets = DefaultOffsetsof(t.fields)
|
||||||
t.offsets = offsets
|
t.offsets = offsets
|
||||||
}
|
}
|
||||||
return offsets[n-1] + DefaultSizeof(t.fields[n-1].Type)
|
return offsets[n-1] + DefaultSizeof(t.fields.At(n-1).Type())
|
||||||
case *Signature:
|
case *Signature:
|
||||||
return DefaultPtrSize * 2
|
return DefaultPtrSize * 2
|
||||||
}
|
}
|
||||||
|
@ -97,9 +97,9 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
|
|||||||
var obj Object
|
var obj Object
|
||||||
var typ Type
|
var typ Type
|
||||||
if isConst {
|
if isConst {
|
||||||
obj = &Const{pos: ident.Pos(), pkg: check.pkg, name: ident.Name}
|
obj = NewConst(ident.Pos(), check.pkg, ident.Name, nil, nil)
|
||||||
} else {
|
} else {
|
||||||
obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name}
|
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
|
||||||
}
|
}
|
||||||
defer check.declare(check.topScope, ident, obj)
|
defer check.declare(check.topScope, ident, obj)
|
||||||
|
|
||||||
@ -237,9 +237,9 @@ Error:
|
|||||||
|
|
||||||
var obj Object
|
var obj Object
|
||||||
if isConst {
|
if isConst {
|
||||||
obj = &Const{pos: ident.Pos(), pkg: check.pkg, name: ident.Name}
|
obj = NewConst(ident.Pos(), check.pkg, ident.Name, nil, nil)
|
||||||
} else {
|
} else {
|
||||||
obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name}
|
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
|
||||||
}
|
}
|
||||||
defer check.declare(check.topScope, ident, obj)
|
defer check.declare(check.topScope, ident, obj)
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
check.funcsig.labels = scope
|
check.funcsig.labels = scope
|
||||||
}
|
}
|
||||||
label := s.Label
|
label := s.Label
|
||||||
check.declare(scope, label, &Label{pos: label.Pos(), name: label.Name})
|
check.declare(scope, label, NewLabel(label.Pos(), label.Name))
|
||||||
check.stmt(s.Stmt)
|
check.stmt(s.Stmt)
|
||||||
|
|
||||||
case *ast.ExprStmt:
|
case *ast.ExprStmt:
|
||||||
@ -404,7 +404,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
var obj Object
|
var obj Object
|
||||||
if ident, ok := x.(*ast.Ident); ok {
|
if ident, ok := x.(*ast.Ident); ok {
|
||||||
// use the correct obj if the ident is redeclared
|
// use the correct obj if the ident is redeclared
|
||||||
obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name}
|
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
|
||||||
if alt := check.topScope.Lookup(nil, ident.Name); alt != nil {
|
if alt := check.topScope.Lookup(nil, ident.Name); alt != nil {
|
||||||
obj = alt
|
obj = alt
|
||||||
}
|
}
|
||||||
@ -412,7 +412,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
} else {
|
} else {
|
||||||
check.errorf(x.Pos(), "cannot declare %s", x)
|
check.errorf(x.Pos(), "cannot declare %s", x)
|
||||||
// create a dummy variable
|
// create a dummy variable
|
||||||
obj = &Var{pos: x.Pos(), pkg: check.pkg, name: "_"}
|
obj = NewVar(x.Pos(), check.pkg, "_", nil)
|
||||||
}
|
}
|
||||||
lhs[i] = obj
|
lhs[i] = obj
|
||||||
}
|
}
|
||||||
@ -655,7 +655,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
|
|
||||||
var obj Object
|
var obj Object
|
||||||
if lhs != nil {
|
if lhs != nil {
|
||||||
obj = &Var{pos: lhs.Pos(), pkg: check.pkg, name: lhs.Name, typ: x.typ}
|
obj = NewVar(lhs.Pos(), check.pkg, lhs.Name, x.typ)
|
||||||
check.declare(check.topScope, lhs, obj)
|
check.declare(check.topScope, lhs, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,7 +687,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
if lhs != nil {
|
if lhs != nil {
|
||||||
// A single-type case clause implicitly declares a new variable shadowing lhs.
|
// A single-type case clause implicitly declares a new variable shadowing lhs.
|
||||||
if len(clause.List) == 1 && typ != nil {
|
if len(clause.List) == 1 && typ != nil {
|
||||||
obj := &Var{pos: lhs.Pos(), pkg: check.pkg, name: lhs.Name, typ: typ}
|
obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, typ)
|
||||||
check.declare(check.topScope, nil, obj)
|
check.declare(check.topScope, nil, obj)
|
||||||
check.callImplicitObj(clause, obj)
|
check.callImplicitObj(clause, obj)
|
||||||
}
|
}
|
||||||
|
@ -130,32 +130,19 @@ func NewSlice(elem Type) *Slice { return &Slice{elem} }
|
|||||||
// Elem returns the element type of slice s.
|
// Elem returns the element type of slice s.
|
||||||
func (s *Slice) Elem() Type { return s.elt }
|
func (s *Slice) Elem() Type { return s.elt }
|
||||||
|
|
||||||
// A Field represents a field of a struct.
|
|
||||||
type Field struct {
|
|
||||||
Pkg *Package
|
|
||||||
Name string
|
|
||||||
Type Type
|
|
||||||
IsAnonymous bool
|
|
||||||
|
|
||||||
// TODO(gri) Temporary hack so we can report the correct *Var via Context.Ident.
|
|
||||||
// Make Field just this *Var and we can simplify a lot of struct code.
|
|
||||||
obj *Var
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Struct represents a struct type.
|
// A Struct represents a struct type.
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
scope *Scope
|
fields *Scope
|
||||||
fields []*Field
|
tags []string // field tags; nil if there are no tags
|
||||||
tags []string // field tags; nil of there are no tags
|
|
||||||
offsets []int64 // field offsets in bytes, lazily computed
|
offsets []int64 // field offsets in bytes, lazily computed
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStruct(fields []*Field, tags []string) *Struct {
|
func NewStruct(fields *Scope, tags []string) *Struct {
|
||||||
return &Struct{scope: nil, fields: fields, tags: tags}
|
return &Struct{fields: fields, tags: tags}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Struct) NumFields() int { return len(s.fields) }
|
func (s *Struct) NumFields() int { return s.fields.NumEntries() }
|
||||||
func (s *Struct) Field(i int) *Field { return s.fields[i] }
|
func (s *Struct) Field(i int) *Field { return s.fields.At(i).(*Field) }
|
||||||
func (s *Struct) Tag(i int) string {
|
func (s *Struct) Tag(i int) string {
|
||||||
if i < len(s.tags) {
|
if i < len(s.tags) {
|
||||||
return s.tags[i]
|
return s.tags[i]
|
||||||
@ -163,27 +150,6 @@ func (s *Struct) Tag(i int) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) isMatch(pkg *Package, name string) bool {
|
|
||||||
// spec:
|
|
||||||
// "Two identifiers are different if they are spelled differently,
|
|
||||||
// or if they appear in different packages and are not exported.
|
|
||||||
// Otherwise, they are the same."
|
|
||||||
if name != f.Name {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// f.Name == name
|
|
||||||
return ast.IsExported(name) || pkg.path == f.Pkg.path
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Struct) fieldIndex(pkg *Package, name string) int {
|
|
||||||
for i, f := range s.fields {
|
|
||||||
if f.isMatch(pkg, name) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Pointer represents a pointer type.
|
// A Pointer represents a pointer type.
|
||||||
type Pointer struct {
|
type Pointer struct {
|
||||||
base Type
|
base Type
|
||||||
|
@ -58,10 +58,10 @@ var aliases = [...]*Basic{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var predeclaredConstants = [...]*Const{
|
var predeclaredConstants = [...]*Const{
|
||||||
{name: "true", typ: Typ[UntypedBool], val: exact.MakeBool(true)},
|
NewConst(token.NoPos, nil, "true", Typ[UntypedBool], exact.MakeBool(true)),
|
||||||
{name: "false", typ: Typ[UntypedBool], val: exact.MakeBool(false)},
|
NewConst(token.NoPos, nil, "false", Typ[UntypedBool], exact.MakeBool(false)),
|
||||||
{name: "iota", typ: Typ[UntypedInt], val: exact.MakeInt64(0)},
|
NewConst(token.NoPos, nil, "iota", Typ[UntypedInt], exact.MakeInt64(0)),
|
||||||
{name: "nil", typ: Typ[UntypedNil], val: exact.MakeNil()},
|
NewConst(token.NoPos, nil, "nil", Typ[UntypedNil], exact.MakeNil()),
|
||||||
}
|
}
|
||||||
|
|
||||||
var predeclaredFunctions = [...]*Builtin{
|
var predeclaredFunctions = [...]*Builtin{
|
||||||
@ -88,23 +88,23 @@ var predeclaredFunctions = [...]*Builtin{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Universe = new(Scope)
|
Universe = new(Scope)
|
||||||
Unsafe = &Package{name: "unsafe", scope: new(Scope)}
|
Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(nil), nil, true)
|
||||||
|
|
||||||
// predeclared types
|
// predeclared types
|
||||||
for _, t := range Typ {
|
for _, t := range Typ {
|
||||||
def(&TypeName{name: t.name, typ: t})
|
def(NewTypeName(token.NoPos, nil, t.name, t))
|
||||||
}
|
}
|
||||||
for _, t := range aliases {
|
for _, t := range aliases {
|
||||||
def(&TypeName{name: t.name, typ: t})
|
def(NewTypeName(token.NoPos, nil, t.name, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
// error type
|
// error type
|
||||||
{
|
{
|
||||||
// Error has a nil package in its qualified name since it is in no package
|
// Error has a nil package in its qualified name since it is in no package
|
||||||
methods := NewScope(nil)
|
methods := NewScope(nil)
|
||||||
sig := &Signature{results: NewTuple(&Var{name: "", typ: Typ[String]})}
|
sig := &Signature{results: NewTuple(NewVar(token.NoPos, nil, "", Typ[String]))}
|
||||||
methods.Insert(&Func{token.NoPos, nil, nil, "Error", sig, nil})
|
methods.Insert(NewFunc(token.NoPos, nil, "Error", sig))
|
||||||
def(&TypeName{name: "error", typ: &Named{underlying: &Interface{methods: methods}}})
|
def(NewTypeName(token.NoPos, nil, "error", &Named{underlying: &Interface{methods: methods}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range predeclaredConstants {
|
for _, c := range predeclaredConstants {
|
||||||
@ -112,7 +112,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range predeclaredFunctions {
|
for _, f := range predeclaredFunctions {
|
||||||
def(&Func{name: f.name, typ: f})
|
def(NewFunc(token.NoPos, nil, f.name, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
universeIota = Universe.Lookup(nil, "iota").(*Const)
|
universeIota = Universe.Lookup(nil, "iota").(*Const)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"code.google.com/p/go.tools/go/exact"
|
"code.google.com/p/go.tools/go/exact"
|
||||||
"code.google.com/p/go.tools/go/types"
|
"code.google.com/p/go.tools/go/types"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -172,18 +173,18 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||||||
isVariadic = true
|
isVariadic = true
|
||||||
}
|
}
|
||||||
params = append(params,
|
params = append(params,
|
||||||
types.NewVar(nil, "", t0),
|
types.NewVar(token.NoPos, nil, "", t0),
|
||||||
types.NewVar(nil, "", t1))
|
types.NewVar(token.NoPos, nil, "", t1))
|
||||||
|
|
||||||
case "print", "println": // print{,ln}(any, ...interface{})
|
case "print", "println": // print{,ln}(any, ...interface{})
|
||||||
isVariadic = true
|
isVariadic = true
|
||||||
// Note, arg0 may have any type, not necessarily tEface.
|
// Note, arg0 may have any type, not necessarily tEface.
|
||||||
params = append(params,
|
params = append(params,
|
||||||
types.NewVar(nil, "", info.TypeOf(e.Args[0])),
|
types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])),
|
||||||
types.NewVar(nil, "", tEface))
|
types.NewVar(token.NoPos, nil, "", tEface))
|
||||||
|
|
||||||
case "close":
|
case "close":
|
||||||
params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0])))
|
params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))
|
||||||
|
|
||||||
case "copy":
|
case "copy":
|
||||||
// copy([]T, []T) int
|
// copy([]T, []T) int
|
||||||
@ -196,7 +197,7 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||||||
} else {
|
} else {
|
||||||
panic("cannot infer types in call to copy()")
|
panic("cannot infer types in call to copy()")
|
||||||
}
|
}
|
||||||
stvar := types.NewVar(nil, "", st)
|
stvar := types.NewVar(token.NoPos, nil, "", st)
|
||||||
params = append(params, stvar, stvar)
|
params = append(params, stvar, stvar)
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
@ -204,11 +205,11 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||||||
tmap := info.TypeOf(e.Args[0])
|
tmap := info.TypeOf(e.Args[0])
|
||||||
tkey := tmap.Underlying().(*types.Map).Key()
|
tkey := tmap.Underlying().(*types.Map).Key()
|
||||||
params = append(params,
|
params = append(params,
|
||||||
types.NewVar(nil, "", tmap),
|
types.NewVar(token.NoPos, nil, "", tmap),
|
||||||
types.NewVar(nil, "", tkey))
|
types.NewVar(token.NoPos, nil, "", tkey))
|
||||||
|
|
||||||
case "len", "cap":
|
case "len", "cap":
|
||||||
params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0])))
|
params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))
|
||||||
|
|
||||||
case "real", "imag":
|
case "real", "imag":
|
||||||
// Reverse conversion to "complex" case below.
|
// Reverse conversion to "complex" case below.
|
||||||
@ -223,7 +224,7 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||||||
default:
|
default:
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
params = append(params, types.NewVar(nil, "", argType))
|
params = append(params, types.NewVar(token.NoPos, nil, "", argType))
|
||||||
|
|
||||||
case "complex":
|
case "complex":
|
||||||
var argType types.Type
|
var argType types.Type
|
||||||
@ -237,11 +238,11 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||||||
default:
|
default:
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
v := types.NewVar(nil, "", argType)
|
v := types.NewVar(token.NoPos, nil, "", argType)
|
||||||
params = append(params, v, v)
|
params = append(params, v, v)
|
||||||
|
|
||||||
case "panic":
|
case "panic":
|
||||||
params = append(params, types.NewVar(nil, "", tEface))
|
params = append(params, types.NewVar(token.NoPos, nil, "", tEface))
|
||||||
|
|
||||||
case "recover":
|
case "recover":
|
||||||
// no params
|
// no params
|
||||||
|
@ -42,7 +42,7 @@ type opaqueType struct {
|
|||||||
func (t *opaqueType) String() string { return t.name }
|
func (t *opaqueType) String() string { return t.name }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
varOk = types.NewVar(nil, "ok", tBool)
|
varOk = types.NewVar(token.NoPos, nil, "ok", tBool)
|
||||||
|
|
||||||
// Type constants.
|
// Type constants.
|
||||||
tBool = types.Typ[types.Bool]
|
tBool = types.Typ[types.Bool]
|
||||||
@ -55,8 +55,8 @@ var (
|
|||||||
|
|
||||||
// The result type of a "select".
|
// The result type of a "select".
|
||||||
tSelect = types.NewTuple(
|
tSelect = types.NewTuple(
|
||||||
types.NewVar(nil, "index", tInt),
|
types.NewVar(token.NoPos, nil, "index", tInt),
|
||||||
types.NewVar(nil, "recv", tEface),
|
types.NewVar(token.NoPos, nil, "recv", tEface),
|
||||||
varOk)
|
varOk)
|
||||||
|
|
||||||
// SSA Value constants.
|
// SSA Value constants.
|
||||||
@ -253,7 +253,7 @@ func (b *builder) exprN(fn *Function, e ast.Expr) Value {
|
|||||||
tuple.(interface {
|
tuple.(interface {
|
||||||
setType(types.Type)
|
setType(types.Type)
|
||||||
}).setType(types.NewTuple(
|
}).setType(types.NewTuple(
|
||||||
types.NewVar(nil, "value", typ),
|
types.NewVar(token.NoPos, nil, "value", typ),
|
||||||
varOk,
|
varOk,
|
||||||
))
|
))
|
||||||
return tuple
|
return tuple
|
||||||
@ -358,7 +358,7 @@ func (b *builder) selector(fn *Function, e *ast.SelectorExpr, wantAddr, escaping
|
|||||||
index := -1
|
index := -1
|
||||||
for i, n := 0, st.NumFields(); i < n; i++ {
|
for i, n := 0, st.NumFields(); i < n; i++ {
|
||||||
f := st.Field(i)
|
f := st.Field(i)
|
||||||
if MakeId(f.Name, f.Pkg) == id {
|
if MakeId(f.Name(), f.Pkg()) == id {
|
||||||
index = i
|
index = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -389,11 +389,11 @@ func (b *builder) selector(fn *Function, e *ast.SelectorExpr, wantAddr, escaping
|
|||||||
func (b *builder) fieldAddr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos, escaping bool) Value {
|
func (b *builder) fieldAddr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos, escaping bool) Value {
|
||||||
var x Value
|
var x Value
|
||||||
if path != nil {
|
if path != nil {
|
||||||
switch path.field.Type.Underlying().(type) {
|
switch path.field.Type().Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
x = b.fieldAddr(fn, base, path.tail, path.index, path.field.Type, token.NoPos, escaping)
|
x = b.fieldAddr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos, escaping)
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type, token.NoPos)
|
x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch fn.Pkg.typeOf(base).Underlying().(type) {
|
switch fn.Pkg.typeOf(base).Underlying().(type) {
|
||||||
@ -422,7 +422,7 @@ func (b *builder) fieldAddr(fn *Function, base ast.Expr, path *anonFieldPath, in
|
|||||||
func (b *builder) fieldExpr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos) Value {
|
func (b *builder) fieldExpr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos) Value {
|
||||||
var x Value
|
var x Value
|
||||||
if path != nil {
|
if path != nil {
|
||||||
x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type, token.NoPos)
|
x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos)
|
||||||
} else {
|
} else {
|
||||||
x = b.expr(fn, base)
|
x = b.expr(fn, base)
|
||||||
}
|
}
|
||||||
@ -1254,7 +1254,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
|
|||||||
fname := kv.Key.(*ast.Ident).Name
|
fname := kv.Key.(*ast.Ident).Name
|
||||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||||
sf := t.Field(i)
|
sf := t.Field(i)
|
||||||
if sf.Name == fname {
|
if sf.Name() == fname {
|
||||||
fieldIndex = i
|
fieldIndex = i
|
||||||
e = kv.Value
|
e = kv.Value
|
||||||
break
|
break
|
||||||
@ -1266,7 +1266,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ
|
|||||||
X: addr,
|
X: addr,
|
||||||
Field: fieldIndex,
|
Field: fieldIndex,
|
||||||
}
|
}
|
||||||
faddr.setType(pointer(sf.Type))
|
faddr.setType(pointer(sf.Type()))
|
||||||
fn.emit(faddr)
|
fn.emit(faddr)
|
||||||
b.exprInPlace(fn, address{addr: faddr}, e)
|
b.exprInPlace(fn, address{addr: faddr}, e)
|
||||||
}
|
}
|
||||||
@ -1858,8 +1858,8 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
|
|||||||
}
|
}
|
||||||
okv.setType(types.NewTuple(
|
okv.setType(types.NewTuple(
|
||||||
varOk,
|
varOk,
|
||||||
types.NewVar(nil, "k", tk),
|
types.NewVar(token.NoPos, nil, "k", tk),
|
||||||
types.NewVar(nil, "v", tv),
|
types.NewVar(token.NoPos, nil, "v", tv),
|
||||||
))
|
))
|
||||||
fn.emit(okv)
|
fn.emit(okv)
|
||||||
|
|
||||||
@ -1903,7 +1903,7 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type) (k Value, loop
|
|||||||
CommaOk: true,
|
CommaOk: true,
|
||||||
}
|
}
|
||||||
recv.setType(types.NewTuple(
|
recv.setType(types.NewTuple(
|
||||||
types.NewVar(nil, "k", tk),
|
types.NewVar(token.NoPos, nil, "k", tk),
|
||||||
varOk,
|
varOk,
|
||||||
))
|
))
|
||||||
ko := fn.emit(recv)
|
ko := fn.emit(recv)
|
||||||
|
@ -279,7 +279,7 @@ func emitTypeTest(f *Function, x Value, t types.Type) Value {
|
|||||||
CommaOk: true,
|
CommaOk: true,
|
||||||
}
|
}
|
||||||
a.setType(types.NewTuple(
|
a.setType(types.NewTuple(
|
||||||
types.NewVar(nil, "value", t),
|
types.NewVar(token.NoPos, nil, "value", t),
|
||||||
varOk,
|
varOk,
|
||||||
))
|
))
|
||||||
return f.emit(a)
|
return f.emit(a)
|
||||||
|
@ -217,7 +217,7 @@ func zero(t types.Type) value {
|
|||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
s := make(structure, t.NumFields())
|
s := make(structure, t.NumFields())
|
||||||
for i := range s {
|
for i := range s {
|
||||||
s[i] = zero(t.Field(i).Type)
|
s[i] = zero(t.Field(i).Type())
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
|
@ -8,6 +8,7 @@ package interp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/token"
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ type opaqueType struct {
|
|||||||
func (t *opaqueType) String() string { return t.name }
|
func (t *opaqueType) String() string { return t.name }
|
||||||
|
|
||||||
// A bogus "reflect" type-checker package. Shared across interpreters.
|
// A bogus "reflect" type-checker package. Shared across interpreters.
|
||||||
var reflectTypesPackage = types.NewPackage("reflect", "reflect")
|
var reflectTypesPackage = types.NewPackage(token.NoPos, "reflect", "reflect", nil, nil, true)
|
||||||
|
|
||||||
// rtype is the concrete type the interpreter uses to implement the
|
// rtype is the concrete type the interpreter uses to implement the
|
||||||
// reflect.Type interface. Since its type is opaque to the target
|
// reflect.Type interface. Since its type is opaque to the target
|
||||||
@ -41,7 +42,7 @@ var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})
|
|||||||
var errorType = makeNamedType("error", &opaqueType{nil, "error"})
|
var errorType = makeNamedType("error", &opaqueType{nil, "error"})
|
||||||
|
|
||||||
func makeNamedType(name string, underlying types.Type) *types.Named {
|
func makeNamedType(name string, underlying types.Type) *types.Named {
|
||||||
obj := types.NewTypeName(reflectTypesPackage, name, nil)
|
obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil)
|
||||||
return types.NewNamed(obj, underlying, nil)
|
return types.NewNamed(obj, underlying, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +319,7 @@ func ext۰reflect۰Value۰Field(fn *ssa.Function, args []value) value {
|
|||||||
// Signature: func (v reflect.Value, i int) reflect.Value
|
// Signature: func (v reflect.Value, i int) reflect.Value
|
||||||
v := args[0]
|
v := args[0]
|
||||||
i := args[1].(int)
|
i := args[1].(int)
|
||||||
return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type, rV2V(v).(structure)[i])
|
return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
func ext۰reflect۰Value۰Interface(fn *ssa.Function, args []value) value {
|
func ext۰reflect۰Value۰Interface(fn *ssa.Function, args []value) value {
|
||||||
@ -393,7 +394,7 @@ func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function
|
|||||||
// that is needed is the "pointerness" of Recv.Type, and for
|
// that is needed is the "pointerness" of Recv.Type, and for
|
||||||
// now, we'll set it to always be false since we're only
|
// now, we'll set it to always be false since we're only
|
||||||
// concerned with rtype. Encapsulate this better.
|
// concerned with rtype. Encapsulate this better.
|
||||||
sig := types.NewSignature(types.NewVar(nil, "recv", recvType), nil, nil, false)
|
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
|
||||||
fn := ssa.NewFunction(name, sig)
|
fn := ssa.NewFunction(name, sig)
|
||||||
fn.Pkg = pkg
|
fn.Pkg = pkg
|
||||||
fn.Prog = pkg.Prog
|
fn.Prog = pkg.Prog
|
||||||
|
@ -229,7 +229,7 @@ func (v *FieldAddr) String() string {
|
|||||||
// Be robust against a bad index.
|
// Be robust against a bad index.
|
||||||
name := "?"
|
name := "?"
|
||||||
if 0 <= v.Field && v.Field < st.NumFields() {
|
if 0 <= v.Field && v.Field < st.NumFields() {
|
||||||
name = st.Field(v.Field).Name
|
name = st.Field(v.Field).Name()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
|
return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func (v *Field) String() string {
|
|||||||
// Be robust against a bad index.
|
// Be robust against a bad index.
|
||||||
name := "?"
|
name := "?"
|
||||||
if 0 <= v.Field && v.Field < st.NumFields() {
|
if 0 <= v.Field && v.Field < st.NumFields() {
|
||||||
name = st.Field(v.Field).Name
|
name = st.Field(v.Field).Name()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
|
return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func (p *anonFieldPath) reverse() []*anonFieldPath {
|
|||||||
// isIndirect returns true if the path indirects a pointer.
|
// isIndirect returns true if the path indirects a pointer.
|
||||||
func (p *anonFieldPath) isIndirect() bool {
|
func (p *anonFieldPath) isIndirect() bool {
|
||||||
for ; p != nil; p = p.tail {
|
for ; p != nil; p = p.tail {
|
||||||
if isPointer(p.field.Type) {
|
if isPointer(p.field.Type()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ func (c candidate) String() string {
|
|||||||
s := ""
|
s := ""
|
||||||
// Inefficient!
|
// Inefficient!
|
||||||
for p := c.path; p != nil; p = p.tail {
|
for p := c.path; p != nil; p = p.tail {
|
||||||
s = "." + p.field.Name + s
|
s = "." + p.field.Name() + s
|
||||||
}
|
}
|
||||||
return "@" + s + "." + c.method.Name()
|
return "@" + s + "." + c.method.Name()
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ func buildMethodSet(prog *Program, typ types.Type) MethodSet {
|
|||||||
for _, node := range list {
|
for _, node := range list {
|
||||||
t := typ // first time only
|
t := typ // first time only
|
||||||
if node != nil {
|
if node != nil {
|
||||||
t = node.field.Type
|
t = node.field.Type()
|
||||||
}
|
}
|
||||||
t = t.Deref()
|
t = t.Deref()
|
||||||
|
|
||||||
@ -168,10 +168,10 @@ func buildMethodSet(prog *Program, typ types.Type) MethodSet {
|
|||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||||
f := t.Field(i)
|
f := t.Field(i)
|
||||||
nextcands[MakeId(f.Name, f.Pkg)] = nil // a field: block id
|
nextcands[MakeId(f.Name(), f.Pkg())] = nil // a field: block id
|
||||||
// Queue up anonymous fields for next iteration.
|
// Queue up anonymous fields for next iteration.
|
||||||
// Break cycles to ensure termination.
|
// Break cycles to ensure termination.
|
||||||
if f.IsAnonymous && !node.contains(f) {
|
if f.Anonymous() && !node.contains(f) {
|
||||||
next = append(next, &anonFieldPath{node, i, f})
|
next = append(next, &anonFieldPath{node, i, f})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ func addCandidate(m map[Id]*candidate, id Id, method *types.Func, concrete *Func
|
|||||||
//
|
//
|
||||||
func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function {
|
func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function {
|
||||||
old := cand.method.Type().(*types.Signature)
|
old := cand.method.Type().(*types.Signature)
|
||||||
sig := types.NewSignature(types.NewVar(nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
|
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
|
||||||
|
|
||||||
if prog.mode&LogSource != 0 {
|
if prog.mode&LogSource != 0 {
|
||||||
defer logStack("makeBridgeMethod %s, %s, type %s", typ, cand, sig)()
|
defer logStack("makeBridgeMethod %s, %s, type %s", typ, cand, sig)()
|
||||||
@ -299,9 +299,9 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
|
|||||||
X: v,
|
X: v,
|
||||||
Field: p.index,
|
Field: p.index,
|
||||||
}
|
}
|
||||||
sel.setType(pointer(p.field.Type))
|
sel.setType(pointer(p.field.Type()))
|
||||||
v = fn.emit(sel)
|
v = fn.emit(sel)
|
||||||
if isPointer(p.field.Type) {
|
if isPointer(p.field.Type()) {
|
||||||
v = emitLoad(fn, v)
|
v = emitLoad(fn, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,7 +458,7 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) {
|
|||||||
var list, next []*anonFieldPath
|
var list, next []*anonFieldPath
|
||||||
for i, n := 0, st.NumFields(); i < n; i++ {
|
for i, n := 0, st.NumFields(); i < n; i++ {
|
||||||
f := st.Field(i)
|
f := st.Field(i)
|
||||||
if f.IsAnonymous {
|
if f.Anonymous() {
|
||||||
list = append(list, &anonFieldPath{nil, i, f})
|
list = append(list, &anonFieldPath{nil, i, f})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,7 +468,7 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) {
|
|||||||
for {
|
for {
|
||||||
// look for name in all types at this level
|
// look for name in all types at this level
|
||||||
for _, node := range list {
|
for _, node := range list {
|
||||||
typ := node.field.Type.Deref().(*types.Named)
|
typ := node.field.Type().Deref().(*types.Named)
|
||||||
if visited[typ] {
|
if visited[typ] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -478,13 +478,13 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) {
|
|||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
for i, n := 0, typ.NumFields(); i < n; i++ {
|
for i, n := 0, typ.NumFields(); i < n; i++ {
|
||||||
f := typ.Field(i)
|
f := typ.Field(i)
|
||||||
if MakeId(f.Name, f.Pkg) == id {
|
if MakeId(f.Name(), f.Pkg()) == id {
|
||||||
return node, i
|
return node, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, n := 0, typ.NumFields(); i < n; i++ {
|
for i, n := 0, typ.NumFields(); i < n; i++ {
|
||||||
f := typ.Field(i)
|
f := typ.Field(i)
|
||||||
if f.IsAnonymous {
|
if f.Anonymous() {
|
||||||
next = append(next, &anonFieldPath{node, i, f})
|
next = append(next, &anonFieldPath{node, i, f})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user