}
// Check bounds
- if t, ok := t.rep().(BoundedType); ok {
+ if t, ok := t.lit().(BoundedType); ok {
if rat.Cmp(t.minVal()) < 0 {
a.diag("constant %v underflows %v", ratToString(rat), t);
return nil;
// Convert rat to type t.
res := a.copy();
res.t = t;
- switch t := t.rep().(type) {
+ switch t := t.lit().(type) {
case *uintType:
n, d := rat.Value();
f := n.Quo(bignum.MakeInt(false, d));
rt = a.rs[i].t;
}
- if lt.literal() != rt.literal() {
+ if !lt.compat(rt, false) {
if len(a.rs) == 1 {
a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt);
} else {
}
// Type check object
- if lt, ok := l.t.rep().(*PtrType); ok {
- if et, ok := lt.Elem.rep().(*ArrayType); ok {
+ if lt, ok := l.t.lit().(*PtrType); ok {
+ if et, ok := lt.Elem.lit().(*ArrayType); ok {
// Automatic dereference
nl := l.copy();
nl.t = et;
intIndex := false;
var maxIndex int64 = -1;
- switch lt := l.t.rep().(type) {
+ switch lt := l.t.lit().(type) {
case *ArrayType:
at = lt.Elem;
intIndex = true;
// XXX(Spec) It's unclear if ideal floats with no
// fractional part are allowed here. 6g allows it. I
// believe that's wrong.
- switch _ := r.t.rep().(type) {
+ switch _ := r.t.lit().(type) {
case *idealIntType:
val := r.asIdealInt()();
if val.IsNeg() || (maxIndex != -1 && val.Cmp(bignum.Int(maxIndex)) >= 0) {
a.t = at;
// Compile
- switch lt := l.t.rep().(type) {
+ switch lt := l.t.lit().(type) {
case *ArrayType:
a.t = lt.Elem;
// TODO(austin) Bounds check
// type of that type is still whatever it's defined to. Thus,
// in "type Foo int", Foo is still an integer type and in
// "type Foo func()", Foo is a function type.
- lt, ok := l.t.rep().(*FuncType);
+ lt, ok := l.t.lit().(*FuncType);
if !ok {
a.diag("cannot call non-function type %v", l.t);
return;
return;
}
- switch vt := v.t.rep().(type) {
+ switch vt := v.t.lit().(type) {
case *PtrType:
a.t = vt.Elem;
a.genStarOp(v);
}
}
- // XXX(Spec) "The operand types in binary operations must be
- // compatible" should say the types must be *identical*.
-
// Useful type predicates
- same := func() bool {
- return l.t == r.t;
+ compat := func() bool {
+ return l.t.compat(r.t, false);
};
integers := func() bool {
return l.t.isInteger() && r.t.isInteger();
// Type check
switch op {
case token.ADD:
- if !same() || (!integers() && !floats() && !strings()) {
+ if !compat() || (!integers() && !floats() && !strings()) {
a.diagOpTypes(op, origlt, origrt);
return;
}
a.t = l.t;
case token.SUB, token.MUL, token.QUO:
- if !same() || (!integers() && !floats()) {
+ if !compat() || (!integers() && !floats()) {
a.diagOpTypes(op, origlt, origrt);
return;
}
a.t = l.t;
case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
- if !same() || !integers() {
+ if !compat() || !integers() {
a.diagOpTypes(op, origlt, origrt);
return;
}
log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed");
}
}
- } else if _, ok := r.t.rep().(*uintType); !ok {
+ } else if _, ok := r.t.lit().(*uintType); !ok {
a.diag("right operand of shift must be unsigned");
return;
}
// to everything except arrays and structs, and there
// are some restrictions on when it applies to slices.
- if !same() || (!integers() && !floats() && !strings()) {
+ if !compat() || (!integers() && !floats() && !strings()) {
a.diagOpTypes(op, origlt, origrt);
return;
}
// is very difficult to parse. It's explained much
// better in the Comparison Compatibility section.
- // XXX(Spec) Comparison compatibility: "Values of any
- // type may be compared to other values of compatible
- // static type." Should be *identical* static type.
-
// XXX(Spec) Comparison compatibility: "Function
// values are equal if they refer to the same
// function." is rather vague. It should probably be
// TODO(austin) Deal with remaining special cases
- if !same() {
+ if !compat() {
a.diagOpTypes(op, origlt, origrt);
return;
}
}
}
- switch _ := lenExpr.t.rep().(type) {
+ switch _ := lenExpr.t.lit().(type) {
case *intType:
return lenExpr.evalInt(nil), true;
case *uintType:
if ec == nil {
return nil, errors.GetError(scanner.Sorted);
}
- switch t := ec.t.rep().(type) {
+ switch t := ec.t.lit().(type) {
case *boolType:
return &Expr{t, func(f *Frame, out Value) { out.(BoolValue).Set(ec.evalBool(f)) }}, nil;
case *uintType:
*/
func (a *exprCompiler) genConstant(v Value) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
val := v.(BoolValue).Get();
a.evalBool = func(f *Frame) bool { return val };
func (a *exprCompiler) genIdentOp(level int, index int) {
a.evalAddr = func(f *Frame) Value { return f.Get(level, index) };
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
a.evalBool = func(f *Frame) bool { return f.Get(level, index).(BoolValue).Get() };
case *uintType:
func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) {
lf := l.asArray();
rf := r.asInt();
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
a.evalBool = func(f *Frame) bool { return lf(f).Elem(rf(f)).(BoolValue).Get() };
case *uintType:
func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) {
a.exec = func(f *Frame) { call(f) };
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
a.evalBool = func(f *Frame) bool { return call(f)[0].(BoolValue).Get() };
case *uintType:
func (a *exprCompiler) genStarOp(v *exprCompiler) {
vf := v.asPtr();
a.evalAddr = func(f *Frame) Value { return vf(f) };
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
a.evalBool = func(f *Frame) bool { return vf(f).(BoolValue).Get() };
case *uintType:
}
func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
vf := v.asUint();
a.evalUint = func(f *Frame) uint64 { return -vf(f) };
}
func (a *exprCompiler) genUnaryOpNot(v *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *boolType:
vf := v.asBool();
a.evalBool = func(f *Frame) bool { return !vf(f) };
}
func (a *exprCompiler) genUnaryOpXor(v *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
vf := v.asUint();
a.evalUint = func(f *Frame) uint64 { return ^vf(f) };
}
func (a *exprCompiler) genBinOpAdd(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpSub(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpMul(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpQuo(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpRem(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpAnd(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpOr(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpXor(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpAndNot(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpShl(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpShr(l *exprCompiler, r *exprCompiler) {
- switch _ := a.t.rep().(type) {
+ switch _ := a.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpLss(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpGtr(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpLeq(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpGeq(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *uintType:
lf := l.asUint();
rf := r.asUint();
}
func (a *exprCompiler) genBinOpEql(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *boolType:
lf := l.asBool();
rf := r.asBool();
}
func (a *exprCompiler) genBinOpNeq(l *exprCompiler, r *exprCompiler) {
- switch _ := l.t.rep().(type) {
+ switch _ := l.t.lit().(type) {
case *boolType:
lf := l.asBool();
rf := r.asBool();
}
func genAssign(lt Type, r *exprCompiler) (func(lv Value, f *Frame)) {
- switch _ := lt.rep().(type) {
+ switch _ := lt.lit().(type) {
case *boolType:
rf := r.asBool();
return func(lv Value, f *Frame) { lv.(BoolValue).Set(rf(f)) };
var BoolType = universe.DefineType("bool", universePos, &boolType{});
-func (t *boolType) literal() Type {
- return t;
+func (t *boolType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*boolType);
+ return ok;
}
-func (t *boolType) rep() Type {
+func (t *boolType) lit() Type {
return t;
}
universe.defs["byte"] = universe.defs["uint8"];
}
-func (t *uintType) literal() Type {
- return t;
+func (t *uintType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*uintType);
+ return ok && t == t2;;
}
-func (t *uintType) rep() Type {
+func (t *uintType) lit() Type {
return t;
}
IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"});
)
-func (t *intType) literal() Type {
- return t;
+func (t *intType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*intType);
+ return ok && t == t2;
}
-func (t *intType) rep() Type {
+func (t *intType) lit() Type {
return t;
}
var IdealIntType Type = &idealIntType{}
-func (t *idealIntType) literal() Type {
- return t;
+func (t *idealIntType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*idealIntType);
+ return ok;
}
-func (t *idealIntType) rep() Type {
+func (t *idealIntType) lit() Type {
return t;
}
FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
)
-func (t *floatType) literal() Type {
- return t;
+func (t *floatType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*floatType);
+ return ok && t == t2;
}
-func (t *floatType) rep() Type {
+func (t *floatType) lit() Type {
return t;
}
var IdealFloatType Type = &idealFloatType{};
-func (t *idealFloatType) literal() Type {
- return t;
+func (t *idealFloatType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*idealFloatType);
+ return ok;
}
-func (t *idealFloatType) rep() Type {
+func (t *idealFloatType) lit() Type {
return t;
}
var StringType = universe.DefineType("string", universePos, &stringType{});
-func (t *stringType) literal() Type {
- return t;
+func (t *stringType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*stringType);
+ return ok;
}
-func (t *stringType) rep() Type {
+func (t *stringType) lit() Type {
return t;
}
commonType;
Len int64;
Elem Type;
- lit Type;
}
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 and the same array length.
+// Two array types are identical if they have identical element types
+// and the same array length.
+func NewArrayType(len int64, elem Type) *ArrayType {
ts, ok := arrayTypes[len];
if !ok {
ts = make(map[Type] *ArrayType);
}
t, ok := ts[elem];
if !ok {
- t = &ArrayType{commonType{}, len, elem, nil};
+ t = &ArrayType{commonType{}, len, elem};
ts[elem] = t;
}
return t;
}
-func (t *ArrayType) literal() Type {
- if t.lit == nil {
- t.lit = NewArrayType(t.Len, t.Elem.literal());
+func (t *ArrayType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*ArrayType);
+ 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;
}
type PtrType struct {
commonType;
Elem Type;
- lit Type;
}
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];
if !ok {
- t = &PtrType{commonType{}, elem, nil};
+ t = &PtrType{commonType{}, elem};
ptrTypes[elem] = t;
}
return t;
}
-func (t *PtrType) literal() Type {
- if t.lit == nil {
- t.lit = NewPtrType(t.Elem.literal());
+func (t *PtrType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*PtrType);
+ 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;
}
In []Type;
Variadic bool;
Out []Type;
- lit Type;
}
var funcTypes = 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 parameters and result values and if corresponding
- // parameter and result types are identical. All "..."
- // parameters have identical type. Parameter and result names
- // are not required to match.
+// Two function types are identical if they have the same number of
+// parameters and result values and if corresponding parameter and
+// result types are identical. All "..." parameters have identical
+// type. Parameter and result names are not required to match.
+func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
inMap := funcTypes;
if variadic {
inMap = variadicFuncTypes;
return tI.(*FuncType);
}
- t := &FuncType{commonType{}, in, variadic, out, nil};
+ t := &FuncType{commonType{}, in, variadic, out};
outMap.Put(out, t);
return t;
}
-func (t *FuncType) literal() Type {
- if t.lit == nil {
- in := make([]Type, len(t.In));
- for i := 0; i < len(in); i++ {
- in[i] = t.In[i].literal();
+func (t *FuncType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*FuncType);
+ if !ok {
+ return false;
+ }
+ if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
+ return false;
+ }
+ for i := range t.In {
+ if !t.In[i].compat(t2.In[i], conv) {
+ return false;
}
-
- out := make([]Type, len(t.Out));
- for i := 0; i < len(out); i++ {
- out[i] = t.Out[i].literal();
+ }
+ 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;
}
//methods map[string] XXX;
}
-func (t *NamedType) literal() Type {
- return t.def.literal();
+func (t *NamedType) compat(o Type, conv bool) bool {
+ 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 {
- return t.def.rep();
+func (t *NamedType) lit() Type {
+ return t.def.lit();
}
func (t *NamedType) isBoolean() bool {
type MultiType struct {
commonType;
Elems []Type;
- lit Type;
}
var multiTypes = newTypeArrayMap()
return t.(*MultiType);
}
- t := &MultiType{commonType{}, elems, nil};
+ t := &MultiType{commonType{}, elems};
multiTypes.Put(elems, t);
return t;
}
-var EmptyType Type = NewMultiType([]Type{});
-
-func (t *MultiType) literal() Type {
- if t.lit == nil {
- elems := make([]Type, len(t.Elems));
- for i, e := range t.Elems {
- elems[i] = e.literal();
+func (t *MultiType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*MultiType);
+ if !ok {
+ return false;
+ }
+ if len(t.Elems) != len(t2.Elems) {
+ 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;
}