[dev.typeparams] cmd/compile/internal/types2: "comparable" must not be visible before Go 1.18

While at it, clean up the setup of comparable in universe.go.

Fixes #46090

Change-Id: I9655b3e137a03763d677d9a2a730c5570ccff6dc
Reviewed-on: https://go-review.googlesource.com/c/go/+/331517
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-06-28 19:41:29 -07:00
parent 706c580ee1
commit 1cd505c353
3 changed files with 32 additions and 40 deletions

View file

@ -0,0 +1,9 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The predeclared type comparable is not visible before Go 1.18.
package go1_17
type _ comparable // ERROR undeclared

View file

@ -25,7 +25,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
// Note that we cannot use check.lookup here because the returned scope
// may be different from obj.Parent(). See also Scope.LookupParent doc.
scope, obj := check.scope.LookupParent(e.Value, check.pos)
if obj == nil {
if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) {
if e.Value == "_" {
check.error(e, "cannot use _ as value or type")
} else {

View file

@ -20,11 +20,12 @@ var Universe *Scope
var Unsafe *Package
var (
universeIota *Const
universeByte *Basic // uint8 alias, but has name "byte"
universeRune *Basic // int32 alias, but has name "rune"
universeAny *Interface
universeError *Named
universeIota *Const
universeByte *Basic // uint8 alias, but has name "byte"
universeRune *Basic // int32 alias, but has name "rune"
universeAny *Interface
universeError *Named
universeComparable Object
)
// Typ contains the predeclared *Basic types indexed by their
@ -77,21 +78,30 @@ func defPredeclaredTypes() {
def(NewTypeName(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.)
// type any = interface{}
// 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.
def(NewTypeName(nopos, nil, "any", &emptyInterface))
// Error has a nil package in its qualified name since it is in no package
// type error interface{ Error() string }
{
res := NewVar(nopos, nil, "", Typ[String])
sig := &Signature{results: NewTuple(res)}
sig := NewSignature(nil, nil, NewTuple(res), false)
err := NewFunc(nopos, nil, "Error", sig)
typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil)}
sig.recv = NewVar(nopos, nil, "", typ)
def(NewTypeName(nopos, nil, "error", typ))
}
// type comparable interface{ ==() }
{
sig := NewSignature(nil, nil, nil, false)
eql := NewFunc(nopos, nil, "==", sig)
typ := &Named{underlying: NewInterfaceType([]*Func{eql}, nil)}
sig.recv = NewVar(nopos, nil, "", typ)
def(NewTypeName(nopos, nil, "comparable", typ))
}
}
var predeclaredConsts = [...]struct {
@ -200,33 +210,6 @@ 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(nopos, nil, "==", sig)
iface := NewInterfaceType([]*Func{eql}, nil)
// set up the defined type for the interface
obj := NewTypeName(nopos, nil, "comparable", nil)
named := NewNamed(obj, iface, nil)
obj.color_ = black
sig.recv = NewVar(nopos, nil, "", named) // complete == signature
def(obj)
}
func init() {
Universe = NewScope(nil, nopos, nopos, "universe")
Unsafe = NewPackage("unsafe", "unsafe")
@ -236,13 +219,13 @@ 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.(*Interface)
universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)
universeComparable = Universe.Lookup("comparable")
// "any" is only visible as constraint in a type parameter list
delete(Universe.elems, "any")