1
0
mirror of https://github.com/golang/go synced 2024-11-25 21:07:56 -07:00

Interface types, values, and type compiler. This does not yet

implement any type checking or semantics for interfaces.

R=rsc
APPROVED=rsc
DELTA=305  (289 added, 10 deleted, 6 changed)
OCL=35889
CL=35995
This commit is contained in:
Austin Clements 2009-10-22 08:59:18 -07:00
parent 5bd8c92427
commit 3040f067c3
4 changed files with 292 additions and 13 deletions

View File

@ -123,6 +123,12 @@ var stmtTests = []test {
Run("type T func(int, int) (int, int)"), Run("type T func(int, int) (int, int)"),
CErr("type T func(x); type U T", "undefined"), CErr("type T func(x); type U T", "undefined"),
CErr("type T func(a T)", "recursive"), CErr("type T func(a T)", "recursive"),
// Interface types
Run("type T interface {x(a, b int) int}"),
Run("type T interface {x(a, b int) int}; type U interface {T; y(c int)}"),
CErr("type T interface {x(a int); x()}", "method x redeclared"),
CErr("type T interface {x()}; type U interface {T; x()}", "method x redeclared"),
CErr("type T int; type U interface {T}", "embedded type"),
// Parens // Parens
Run("type T (int)"), Run("type T (int)"),

View File

@ -10,6 +10,7 @@ import (
"go/token"; "go/token";
"log"; "log";
"reflect"; "reflect";
"sort";
"unsafe"; // For Sizeof "unsafe"; // For Sizeof
) )
@ -882,28 +883,207 @@ type FuncDecl struct {
} }
func (t *FuncDecl) String() string { func (t *FuncDecl) String() string {
args := typeListString(t.Type.In, t.InNames);
if t.Type.Variadic {
if len(args) > 0 {
args += ", ";
}
args += "...";
}
s := "func"; s := "func";
if t.Name != nil { if t.Name != nil {
s += " " + t.Name.Value; s += " " + t.Name.Value;
} }
s += "(" + args + ")"; s += funcTypeString(t.Type, t.InNames, t.OutNames);
if len(t.Type.Out) > 0 { return s;
s += " (" + typeListString(t.Type.Out, t.OutNames) + ")"; }
func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string {
s := "(";
s += typeListString(ft.In, ins);
if ft.Variadic {
if len(ft.In) > 0 {
s += ", ";
}
s += "...";
}
s += ")";
if len(ft.Out) > 0 {
s += " (" + typeListString(ft.Out, outs) + ")";
} }
return s; return s;
} }
/* /*
* Interface
*/
// TODO(austin) Interface values, types, and type compilation are
// implemented, but none of the type checking or semantics of
// interfaces are.
type InterfaceType struct { type InterfaceType struct {
// TODO(austin) commonType;
// TODO(austin) This should be a map from names to
// *FuncType's. We only need the sorted list for generating
// the type map key. It's detrimental for everything else.
methods []IMethod;
} }
type IMethod struct {
Name string;
Type *FuncType;
}
var interfaceTypes = newTypeArrayMap()
func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType {
// Count methods of embedded interfaces
nMethods := len(methods);
for _, e := range embeds {
nMethods += len(e.methods);
}
// Combine methods
allMethods := make([]IMethod, nMethods);
for i, m := range methods {
allMethods[i] = m;
}
n := len(methods);
for _, e := range embeds {
for _, m := range e.methods {
allMethods[n] = m;
n++;
}
}
// Sort methods
sort.Sort(iMethodSorter(allMethods));
mts := make([]Type, len(allMethods));
for i, m := range methods {
mts[i] = m.Type;
}
tMapI := interfaceTypes.Get(mts);
if tMapI == nil {
tMapI = interfaceTypes.Put(mts, make(map[string] *InterfaceType));
}
tMap := tMapI.(map[string] *InterfaceType);
key := "";
for _, m := range allMethods {
key += m.Name + " ";
}
t, ok := tMap[key];
if !ok {
t = &InterfaceType{commonType{}, allMethods};
tMap[key] = t;
}
return t;
}
type iMethodSorter []IMethod
func (s iMethodSorter) Less(a, b int) bool {
return s[a].Name < s[b].Name;
}
func (s iMethodSorter) Swap(a, b int) {
s[a], s[b] = s[b], s[a];
}
func (s iMethodSorter) Len() int {
return len(s);
}
func (t *InterfaceType) compat(o Type, conv bool) bool {
t2, ok := o.lit().(*InterfaceType);
if !ok {
return false;
}
if len(t.methods) != len(t2.methods) {
return false;
}
for i, e := range t.methods {
e2 := t2.methods[i];
if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) {
return false;
}
}
return true;
}
func (t *InterfaceType) lit() Type {
return t;
}
func (t *InterfaceType) String() string {
// TODO(austin) Instead of showing embedded interfaces, this
// shows their methods.
s := "interface {";
for i, m := range t.methods {
if i > 0 {
s += "; ";
}
s += m.Name + funcTypeString(m.Type, nil, nil);
}
return s + "}";
}
// implementedBy tests if o implements t, returning nil, true if it does.
// Otherwise, it returns a method of t that o is missing and false.
func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) {
if len(t.methods) == 0 {
return nil, true;
}
// The methods of a named interface types are those of the
// underlying type.
if it, ok := o.lit().(*InterfaceType); ok {
o = it;
}
// XXX(Spec) Interface types: "A type implements any interface
// comprising any subset of its methods" It's unclear if
// methods must have identical or compatible types. 6g
// requires identical types.
switch o := o.(type) {
case *NamedType:
for _, tm := range t.methods {
sm, ok := o.methods[tm.Name];
if !ok || sm.decl.Type != tm.Type {
return &tm, false;
}
}
return nil, true;
case *InterfaceType:
var ti, oi int;
for ti < len(t.methods) && oi < len(o.methods) {
tm, om := &t.methods[ti], &o.methods[oi];
switch {
case tm.Name == om.Name:
if tm.Type != om.Type {
return tm, false;
}
ti++;
oi++;
case tm.Name > om.Name:
oi++;
default:
return tm, false;
}
}
if ti < len(t.methods) {
return &t.methods[ti], false;
}
return nil, true;
}
return &t.methods[0], false;
}
func (t *InterfaceType) Zero() Value {
return &interfaceV{};
}
/*
* Slice
*/ */
type SliceType struct { type SliceType struct {

View File

@ -233,6 +233,61 @@ func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl
return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames}; return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames};
} }
func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
ts, names, poss, bad := a.compileFields(x.Methods, allowRec);
methods := make([]IMethod, len(ts));
nameSet := make(map[string] token.Position, len(ts));
embeds := make([]*InterfaceType, len(ts));
var nm, ne int;
for i := range ts {
if ts[i] == nil {
continue;
}
if names[i] != nil {
name := names[i].Value;
methods[nm].Name = name;
methods[nm].Type = ts[i].(*FuncType);
nm++;
if prev, ok := nameSet[name]; ok {
a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", name, &prev);
bad = true;
continue;
}
nameSet[name] = poss[i];
} else {
// Embedded interface
it, ok := ts[i].lit().(*InterfaceType);
if !ok {
a.diagAt(&poss[i], "embedded type must be an interface");
bad = true;
continue;
}
embeds[ne] = it;
ne++;
for _, m := range it.methods {
if prev, ok := nameSet[m.Name]; ok {
a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, &prev);
bad = true;
continue;
}
nameSet[m.Name] = poss[i];
}
}
}
if bad {
return nil;
}
methods = methods[0:nm];
embeds = embeds[0:ne];
return NewInterfaceType(methods, embeds);
}
func (a *typeCompiler) compileMapType(x *ast.MapType) Type { func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
key := a.compileType(x.Key, true); key := a.compileType(x.Key, true);
val := a.compileType(x.Value, true); val := a.compileType(x.Value, true);
@ -282,7 +337,7 @@ func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
return fd.Type; return fd.Type;
case *ast.InterfaceType: case *ast.InterfaceType:
goto notimpl; return a.compileInterfaceType(x, allowRec);
case *ast.MapType: case *ast.MapType:
return a.compileMapType(x); return a.compileMapType(x);

View File

@ -96,6 +96,17 @@ type FuncValue interface {
Set(*Thread, Func); Set(*Thread, Func);
} }
type Interface struct {
Type Type;
Value Value;
}
type InterfaceValue interface {
Value;
Get(*Thread) Interface;
Set(*Thread, Interface);
}
type Slice struct { type Slice struct {
Base ArrayValue; Base ArrayValue;
Len, Cap int64; Len, Cap int64;
@ -598,6 +609,33 @@ func (v *funcV) Set(t *Thread, x Func) {
v.target = x; v.target = x;
} }
/*
* Interfaces
*/
type interfaceV struct {
Interface;
}
func (v *interfaceV) String() string {
if v.Type == nil || v.Value == nil {
return "<nil>";
}
return v.Value.String();
}
func (v *interfaceV) Assign(t *Thread, o Value) {
v.Interface = o.(InterfaceValue).Get(t);
}
func (v *interfaceV) Get(*Thread) Interface {
return v.Interface;
}
func (v *interfaceV) Set(t *Thread, x Interface) {
v.Interface = x;
}
/* /*
* Slices * Slices
*/ */