func (check *checker) comparison(x, y *operand, op token.Token) { // spec: "In any comparison, the first operand must be assignable // to the type of the second operand, or vice versa." err := "" if x.isAssignableTo(check.conf, y.typ) || y.isAssignableTo(check.conf, x.typ) { defined := false switch op { case token.EQL, token.NEQ: // spec: "The equality operators == and != apply to operands that are comparable." defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ) case token.LSS, token.LEQ, token.GTR, token.GEQ: // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered." defined = isOrdered(x.typ) default: unreachable() } if !defined { typ := x.typ if x.isNil() { typ = y.typ } err = check.sprintf("operator %s not defined for %s", op, typ) } } else { err = check.sprintf("mismatched types %s and %s", x.typ, y.typ) } if err != "" { check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err) x.mode = invalid return } if x.mode == constant && y.mode == constant { x.val = exact.MakeBool(exact.Compare(x.val, op, y.val)) // The operands are never materialized; no need to update // their types. } else { x.mode = value // The operands have now their final types, which at run- // time will be materialized. Update the expression trees. // If the current types are untyped, the materialized type // is the respective default type. check.updateExprType(x.expr, defaultType(x.typ), true) check.updateExprType(y.expr, defaultType(y.typ), true) } // spec: "Comparison operators compare two operands and yield // an untyped boolean value." x.typ = Typ[UntypedBool] }
// Error has a nil package in its qualified name since it is in no package res := NewVar(token.NoPos, nil, "", Typ[String]) sig := &Signature{Results: []*Var{res}} err := NewFunc(token.NoPos, nil, "Error", sig) typ := &Named{UnderlyingT: NewInterface([]*Func{err}, nil), complete: true} sig.Recv = NewVar(token.NoPos, nil, "", typ) def(NewTypeName(token.NoPos, nil, "error", typ)) } var predeclaredConsts = [...]struct { name string kind BasicKind val exact.Value }{ {"true", UntypedBool, exact.MakeBool(true)}, {"false", UntypedBool, exact.MakeBool(false)}, {"iota", UntypedInt, exact.MakeInt64(0)}, } func defPredeclaredConsts() { for _, c := range predeclaredConsts { def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val)) } } func defPredeclaredNil() { def(&Nil{object{Name: "nil", Type: Typ[UntypedNil]}}) } // A builtinId is the id of a builtin function.