Commit 458e23e1 authored by Austin Clements's avatar Austin Clements

Implement type compatibility and fix places where I thought

types were supposed to be identical but only needed to be
compatible.  This gets rid of the Type.literal method.  I
renamed the Type.rep method to Type.lit because I believe it
corresponds to the term "literal" as used in the spec.

R=rsc
APPROVED=rsc
DELTA=228  (57 added, 35 deleted, 136 changed)
OCL=32606
CL=32608
parent d11173d4
...@@ -16,15 +16,17 @@ import ( ...@@ -16,15 +16,17 @@ import (
type Value interface type Value interface
type Type interface { type Type interface {
// literal returns this type with all names recursively // compat returns whether this type is compatible with another
// stripped. This should only be used when determining // type. If conv is false, this is normal compatibility,
// assignment compatibility. To strip a named type for use in // where two named types are compatible only if they are the
// a type switch, use .rep(). // same named type. If conv if true, this is conversion
literal() Type; // compatibility, where two named types are conversion
// rep returns the representative type. If this is a named // compatible if their definitions are conversion compatible.
// type, this is the unnamed underlying type. Otherwise, this compat(o Type, conv bool) bool;
// is an identity operation. // lit returns this type's literal. If this is a named type,
rep() Type; // this is the unnamed underlying type. Otherwise, this is an
// identity operation.
lit() Type;
// isBoolean returns true if this is a boolean type. // isBoolean returns true if this is a boolean type.
isBoolean() bool; isBoolean() bool;
// isInteger returns true if this is an integer type. // isInteger returns true if this is an integer type.
......
This diff is collapsed.
...@@ -86,7 +86,7 @@ func (b *block) DefineType(name string, pos token.Position, t Type) Type { ...@@ -86,7 +86,7 @@ func (b *block) DefineType(name string, pos token.Position, t Type) Type {
} }
// We take the representative type of t because multiple // We take the representative type of t because multiple
// levels of naming are useless. // levels of naming are useless.
nt := &NamedType{pos, name, t.rep()}; nt := &NamedType{pos, name, t.lit()};
b.defs[name] = nt; b.defs[name] = nt;
return nt; return nt;
} }
......
...@@ -127,11 +127,12 @@ type boolType struct { ...@@ -127,11 +127,12 @@ type boolType struct {
var BoolType = universe.DefineType("bool", universePos, &boolType{}); var BoolType = universe.DefineType("bool", universePos, &boolType{});
func (t *boolType) literal() Type { func (t *boolType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*boolType);
return ok;
} }
func (t *boolType) rep() Type { func (t *boolType) lit() Type {
return t; return t;
} }
...@@ -181,11 +182,12 @@ func init() { ...@@ -181,11 +182,12 @@ func init() {
universe.defs["byte"] = universe.defs["uint8"]; universe.defs["byte"] = universe.defs["uint8"];
} }
func (t *uintType) literal() Type { func (t *uintType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*uintType);
return ok && t == t2;;
} }
func (t *uintType) rep() Type { func (t *uintType) lit() Type {
return t; return t;
} }
...@@ -241,11 +243,12 @@ var ( ...@@ -241,11 +243,12 @@ var (
IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"}); IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"});
) )
func (t *intType) literal() Type { func (t *intType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*intType);
return ok && t == t2;
} }
func (t *intType) rep() Type { func (t *intType) lit() Type {
return t; return t;
} }
...@@ -285,11 +288,12 @@ type idealIntType struct { ...@@ -285,11 +288,12 @@ type idealIntType struct {
var IdealIntType Type = &idealIntType{} var IdealIntType Type = &idealIntType{}
func (t *idealIntType) literal() Type { func (t *idealIntType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*idealIntType);
return ok;
} }
func (t *idealIntType) rep() Type { func (t *idealIntType) lit() Type {
return t; return t;
} }
...@@ -326,11 +330,12 @@ var ( ...@@ -326,11 +330,12 @@ var (
FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"}); FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
) )
func (t *floatType) literal() Type { func (t *floatType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*floatType);
return ok && t == t2;
} }
func (t *floatType) rep() Type { func (t *floatType) lit() Type {
return t; return t;
} }
...@@ -389,11 +394,12 @@ type idealFloatType struct { ...@@ -389,11 +394,12 @@ type idealFloatType struct {
var IdealFloatType Type = &idealFloatType{}; var IdealFloatType Type = &idealFloatType{};
func (t *idealFloatType) literal() Type { func (t *idealFloatType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*idealFloatType);
return ok;
} }
func (t *idealFloatType) rep() Type { func (t *idealFloatType) lit() Type {
return t; return t;
} }
...@@ -421,11 +427,12 @@ type stringType struct { ...@@ -421,11 +427,12 @@ type stringType struct {
var StringType = universe.DefineType("string", universePos, &stringType{}); var StringType = universe.DefineType("string", universePos, &stringType{});
func (t *stringType) literal() Type { func (t *stringType) compat(o Type, conv bool) bool {
return t; t2, ok := o.lit().(*stringType);
return ok;
} }
func (t *stringType) rep() Type { func (t *stringType) lit() Type {
return t; return t;
} }
...@@ -443,15 +450,14 @@ type ArrayType struct { ...@@ -443,15 +450,14 @@ type ArrayType struct {
commonType; commonType;
Len int64; Len int64;
Elem Type; Elem Type;
lit Type;
} }
var arrayTypes = make(map[int64] map[Type] *ArrayType); var arrayTypes = make(map[int64] map[Type] *ArrayType);
func NewArrayType(len int64, elem Type) *ArrayType { // Two array types are identical if they have identical element types
// Two array types are identical if they have identical // and the same array length.
// element types and the same array length.
func NewArrayType(len int64, elem Type) *ArrayType {
ts, ok := arrayTypes[len]; ts, ok := arrayTypes[len];
if !ok { if !ok {
ts = make(map[Type] *ArrayType); ts = make(map[Type] *ArrayType);
...@@ -459,20 +465,21 @@ func NewArrayType(len int64, elem Type) *ArrayType { ...@@ -459,20 +465,21 @@ func NewArrayType(len int64, elem Type) *ArrayType {
} }
t, ok := ts[elem]; t, ok := ts[elem];
if !ok { if !ok {
t = &ArrayType{commonType{}, len, elem, nil}; t = &ArrayType{commonType{}, len, elem};
ts[elem] = t; ts[elem] = t;
} }
return t; return t;
} }
func (t *ArrayType) literal() Type { func (t *ArrayType) compat(o Type, conv bool) bool {
if t.lit == nil { t2, ok := o.lit().(*ArrayType);
t.lit = NewArrayType(t.Len, t.Elem.literal()); if !ok {
return false;
} }
return t.lit; return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv);
} }
func (t *ArrayType) rep() Type { func (t *ArrayType) lit() Type {
return t; return t;
} }
...@@ -489,31 +496,30 @@ func (t *ArrayType) Zero() Value ...@@ -489,31 +496,30 @@ func (t *ArrayType) Zero() Value
type PtrType struct { type PtrType struct {
commonType; commonType;
Elem Type; Elem Type;
lit Type;
} }
var ptrTypes = make(map[Type] *PtrType) var ptrTypes = make(map[Type] *PtrType)
func NewPtrType(elem Type) *PtrType { // Two pointer types are identical if they have identical base types.
// Two pointer types are identical if they have identical base
// types.
func NewPtrType(elem Type) *PtrType {
t, ok := ptrTypes[elem]; t, ok := ptrTypes[elem];
if !ok { if !ok {
t = &PtrType{commonType{}, elem, nil}; t = &PtrType{commonType{}, elem};
ptrTypes[elem] = t; ptrTypes[elem] = t;
} }
return t; return t;
} }
func (t *PtrType) literal() Type { func (t *PtrType) compat(o Type, conv bool) bool {
if t.lit == nil { t2, ok := o.lit().(*PtrType);
t.lit = NewPtrType(t.Elem.literal()); if !ok {
return false;
} }
return t.lit; return t.Elem.compat(t2.Elem, conv);
} }
func (t *PtrType) rep() Type { func (t *PtrType) lit() Type {
return t; return t;
} }
...@@ -533,19 +539,17 @@ type FuncType struct { ...@@ -533,19 +539,17 @@ type FuncType struct {
In []Type; In []Type;
Variadic bool; Variadic bool;
Out []Type; Out []Type;
lit Type;
} }
var funcTypes = newTypeArrayMap(); var funcTypes = newTypeArrayMap();
var variadicFuncTypes = newTypeArrayMap(); var variadicFuncTypes = newTypeArrayMap();
func NewFuncType(in []Type, variadic bool, out []Type) *FuncType { // Two function types are identical if they have the same number of
// Two function types are identical if they have the same // parameters and result values and if corresponding parameter and
// number of parameters and result values and if corresponding // result types are identical. All "..." parameters have identical
// parameter and result types are identical. All "..." // type. Parameter and result names are not required to match.
// parameters have identical type. Parameter and result names
// are not required to match.
func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
inMap := funcTypes; inMap := funcTypes;
if variadic { if variadic {
inMap = variadicFuncTypes; inMap = variadicFuncTypes;
...@@ -562,29 +566,33 @@ func NewFuncType(in []Type, variadic bool, out []Type) *FuncType { ...@@ -562,29 +566,33 @@ func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
return tI.(*FuncType); return tI.(*FuncType);
} }
t := &FuncType{commonType{}, in, variadic, out, nil}; t := &FuncType{commonType{}, in, variadic, out};
outMap.Put(out, t); outMap.Put(out, t);
return t; return t;
} }
func (t *FuncType) literal() Type { func (t *FuncType) compat(o Type, conv bool) bool {
if t.lit == nil { t2, ok := o.lit().(*FuncType);
in := make([]Type, len(t.In)); if !ok {
for i := 0; i < len(in); i++ { return false;
in[i] = t.In[i].literal();
} }
if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
out := make([]Type, len(t.Out)); return false;
for i := 0; i < len(out); i++ { }
out[i] = t.Out[i].literal(); for i := range t.In {
if !t.In[i].compat(t2.In[i], conv) {
return false;
}
}
for i := range t.Out {
if !t.Out[i].compat(t2.Out[i], conv) {
return false;
} }
t.lit = NewFuncType(in, t.Variadic, out);
} }
return t.lit; return true;
} }
func (t *FuncType) rep() Type { func (t *FuncType) lit() Type {
return t; return t;
} }
...@@ -683,12 +691,28 @@ type NamedType struct { ...@@ -683,12 +691,28 @@ type NamedType struct {
//methods map[string] XXX; //methods map[string] XXX;
} }
func (t *NamedType) literal() Type { func (t *NamedType) compat(o Type, conv bool) bool {
return t.def.literal(); t2, ok := o.(*NamedType);
if ok {
if conv {
// Two named types are conversion compatible
// if their literals are conversion
// compatible.
return t.def.compat(t2.def, conv);
} else {
// Two named types are compatible if their
// type names originate in the same type
// declaration.
return t == t2;
}
}
// A named and an unnamed type are compatible if the
// respective type literals are compatible.
return o.compat(t.def, conv);
} }
func (t *NamedType) rep() Type { func (t *NamedType) lit() Type {
return t.def.rep(); return t.def.lit();
} }
func (t *NamedType) isBoolean() bool { func (t *NamedType) isBoolean() bool {
...@@ -725,7 +749,6 @@ func (t *NamedType) Zero() Value { ...@@ -725,7 +749,6 @@ func (t *NamedType) Zero() Value {
type MultiType struct { type MultiType struct {
commonType; commonType;
Elems []Type; Elems []Type;
lit Type;
} }
var multiTypes = newTypeArrayMap() var multiTypes = newTypeArrayMap()
...@@ -735,26 +758,30 @@ func NewMultiType(elems []Type) *MultiType { ...@@ -735,26 +758,30 @@ func NewMultiType(elems []Type) *MultiType {
return t.(*MultiType); return t.(*MultiType);
} }
t := &MultiType{commonType{}, elems, nil}; t := &MultiType{commonType{}, elems};
multiTypes.Put(elems, t); multiTypes.Put(elems, t);
return t; return t;
} }
var EmptyType Type = NewMultiType([]Type{}); func (t *MultiType) compat(o Type, conv bool) bool {
t2, ok := o.lit().(*MultiType);
func (t *MultiType) literal() Type { if !ok {
if t.lit == nil { return false;
elems := make([]Type, len(t.Elems)); }
for i, e := range t.Elems { if len(t.Elems) != len(t2.Elems) {
elems[i] = e.literal(); return false;
}
for i := range t.Elems {
if !t.Elems[i].compat(t2.Elems[i], conv) {
return false;
} }
t.lit = NewMultiType(elems);
} }
return t.lit; return true;
} }
func (t *MultiType) rep() Type { var EmptyType Type = NewMultiType([]Type{});
func (t *MultiType) lit() Type {
return t; return t;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment