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:
parent
5bd8c92427
commit
3040f067c3
@ -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)"),
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user