mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
[dev.typeparams] go/types: more consistent handling of predeclared "any"
This is a port of CL 334911 to go/types. Change-Id: I2cafdc76cb4d06ba82188c530f35952c1f77d292 Reviewed-on: https://go-review.googlesource.com/c/go/+/335569 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
7e714f448e
commit
6bf2667d4e
|
@ -678,8 +678,9 @@ func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident)
|
||||||
// The type must be an interface, including the predeclared type "any".
|
// The type must be an interface, including the predeclared type "any".
|
||||||
func (check *Checker) boundType(e ast.Expr) Type {
|
func (check *Checker) boundType(e ast.Expr) Type {
|
||||||
// The predeclared identifier "any" is visible only as a type bound in a type parameter list.
|
// The predeclared identifier "any" is visible only as a type bound in a type parameter list.
|
||||||
if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == nil {
|
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
|
||||||
return universeAny
|
if name, _ := unparen(e).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny {
|
||||||
|
return universeAny.Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
bound := check.typ(e)
|
bound := check.typ(e)
|
||||||
|
|
|
@ -22,7 +22,7 @@ func TestIsAlias(t *testing.T) {
|
||||||
check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false)
|
check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false)
|
||||||
for _, name := range Universe.Names() {
|
for _, name := range Universe.Names() {
|
||||||
if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
|
if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
|
||||||
check(obj, name == "byte" || name == "rune")
|
check(obj, name == "any" || name == "byte" || name == "rune")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
src/go/types/testdata/check/typeparams.go2
vendored
8
src/go/types/testdata/check/typeparams.go2
vendored
|
@ -6,11 +6,11 @@ package p
|
||||||
|
|
||||||
// import "io" // for type assertion tests
|
// import "io" // for type assertion tests
|
||||||
|
|
||||||
// The predeclared identifier "any" is only visible as a constraint
|
// The predeclared identifier "any" can only be used as a constraint
|
||||||
// in a type parameter list.
|
// in a type parameter list.
|
||||||
var _ any // ERROR undeclared
|
var _ any // ERROR cannot use any outside constraint position
|
||||||
func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) {
|
func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) {
|
||||||
var _ any /* ERROR undeclared */
|
var _ any /* ERROR constraint */
|
||||||
}
|
}
|
||||||
|
|
||||||
func identity[T any](x T) T { return x }
|
func identity[T any](x T) T { return x }
|
||||||
|
|
|
@ -27,13 +27,24 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
|
||||||
// Note that we cannot use check.lookup here because the returned scope
|
// Note that we cannot use check.lookup here because the returned scope
|
||||||
// may be different from obj.Parent(). See also Scope.LookupParent doc.
|
// may be different from obj.Parent(). See also Scope.LookupParent doc.
|
||||||
scope, obj := check.scope.LookupParent(e.Name, check.pos)
|
scope, obj := check.scope.LookupParent(e.Name, check.pos)
|
||||||
if obj == nil || obj == universeComparable && !check.allowVersion(check.pkg, 1, 18) {
|
switch obj {
|
||||||
|
case nil:
|
||||||
if e.Name == "_" {
|
if e.Name == "_" {
|
||||||
check.errorf(e, _InvalidBlank, "cannot use _ as value or type")
|
check.error(e, _InvalidBlank, "cannot use _ as value or type")
|
||||||
} else {
|
} else {
|
||||||
check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name)
|
check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case universeAny, universeComparable:
|
||||||
|
if !check.allowVersion(check.pkg, 1, 18) {
|
||||||
|
check.errorf(e, _UndeclaredName, "undeclared name: %s (requires version go1.18 or later)", e.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
|
||||||
|
if obj == universeAny {
|
||||||
|
check.error(e, _Todo, "cannot use any outside constraint position")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
check.recordUse(e, obj)
|
check.recordUse(e, obj)
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,11 @@ var Universe *Scope
|
||||||
var Unsafe *Package
|
var Unsafe *Package
|
||||||
|
|
||||||
var (
|
var (
|
||||||
universeIota *Const
|
universeIota Object
|
||||||
universeByte *Basic // uint8 alias, but has name "byte"
|
universeByte Type // uint8 alias, but has name "byte"
|
||||||
universeRune *Basic // int32 alias, but has name "rune"
|
universeRune Type // int32 alias, but has name "rune"
|
||||||
universeAny *Interface
|
universeAny Object
|
||||||
universeError *Named
|
universeError Type
|
||||||
universeComparable Object
|
universeComparable Object
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,9 +80,6 @@ func defPredeclaredTypes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// type any = interface{}
|
// 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(token.NoPos, nil, "any", &emptyInterface))
|
def(NewTypeName(token.NoPos, nil, "any", &emptyInterface))
|
||||||
|
|
||||||
// type error interface{ Error() string }
|
// type error interface{ Error() string }
|
||||||
|
@ -225,15 +222,12 @@ func init() {
|
||||||
defPredeclaredNil()
|
defPredeclaredNil()
|
||||||
defPredeclaredFuncs()
|
defPredeclaredFuncs()
|
||||||
|
|
||||||
universeIota = Universe.Lookup("iota").(*Const)
|
universeIota = Universe.Lookup("iota")
|
||||||
universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
|
universeByte = Universe.Lookup("byte").Type()
|
||||||
universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
|
universeRune = Universe.Lookup("rune").Type()
|
||||||
universeAny = Universe.Lookup("any").(*TypeName).typ.(*Interface)
|
universeAny = Universe.Lookup("any")
|
||||||
universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)
|
universeError = Universe.Lookup("error").Type()
|
||||||
universeComparable = Universe.Lookup("comparable")
|
universeComparable = Universe.Lookup("comparable")
|
||||||
|
|
||||||
// "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
|
// Objects with names containing blanks are internal and not entered into
|
||||||
|
|
Loading…
Reference in a new issue