diff --git a/src/go/types/universe.go b/src/go/types/universe.go index ff5b89118ad..f2f444fd9d1 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -24,6 +24,7 @@ var ( universeIota *Const universeByte *Basic // uint8 alias, but has name "byte" universeRune *Basic // int32 alias, but has name "rune" + universeAny *Named universeError *Named ) @@ -77,13 +78,24 @@ func defPredeclaredTypes() { def(NewTypeName(token.NoPos, nil, t.name, t)) } + // any + // (Predeclared and entered into universe scope so we do all the + // usual checks; but removed again from scope later since it's + // only visible as constraint in a type parameter list.) + { + typ := &Named{underlying: &emptyInterface} + def(NewTypeName(token.NoPos, nil, "any", typ)) + } + // 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: NewTuple(res)} - err := NewFunc(token.NoPos, nil, "Error", sig) - typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()} - sig.recv = NewVar(token.NoPos, nil, "", typ) - def(NewTypeName(token.NoPos, nil, "error", typ)) + { + res := NewVar(token.NoPos, nil, "", Typ[String]) + sig := &Signature{results: NewTuple(res)} + err := NewFunc(token.NoPos, nil, "Error", sig) + typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()} + sig.recv = NewVar(token.NoPos, nil, "", typ) + def(NewTypeName(token.NoPos, nil, "error", typ)) + } } var predeclaredConsts = [...]struct { @@ -188,6 +200,33 @@ func DefPredeclaredTestFuncs() { def(newBuiltin(_Trace)) } +func defPredeclaredComparable() { + // The "comparable" interface can be imagined as defined like + // + // type comparable interface { + // == () untyped bool + // != () untyped bool + // } + // + // == and != cannot be user-declared but we can declare + // a magic method == and check for its presence when needed. + + // Define interface { == () }. We don't care about the signature + // for == so leave it empty except for the receiver, which is + // set up later to match the usual interface method assumptions. + sig := new(Signature) + eql := NewFunc(token.NoPos, nil, "==", sig) + iface := NewInterfaceType([]*Func{eql}, nil).Complete() + + // set up the defined type for the interface + obj := NewTypeName(token.NoPos, nil, "comparable", nil) + named := NewNamed(obj, iface, nil) + obj.color_ = black + sig.recv = NewVar(token.NoPos, nil, "", named) // complete == signature + + def(obj) +} + func init() { Universe = NewScope(nil, token.NoPos, token.NoPos, "universe") Unsafe = NewPackage("unsafe", "unsafe") @@ -197,11 +236,16 @@ func init() { defPredeclaredConsts() defPredeclaredNil() defPredeclaredFuncs() + defPredeclaredComparable() universeIota = Universe.Lookup("iota").(*Const) universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) + universeAny = Universe.Lookup("any").(*TypeName).typ.(*Named) universeError = Universe.Lookup("error").(*TypeName).typ.(*Named) + + // "any" is only visible as constraint in a type parameter list + delete(Universe.elems, "any") } // Objects with names containing blanks are internal and not entered into @@ -215,7 +259,7 @@ func def(obj Object) { return // nothing to do } // fix Obj link for named types - if typ, ok := obj.Type().(*Named); ok { + if typ := asNamed(obj.Type()); typ != nil { typ.obj = obj.(*TypeName) } // exported identifiers go into package unsafe