Skip to content

Commit

Permalink
cmd/compile, go/types: allow any anywhere (as a type)
Browse files Browse the repository at this point in the history
Adjust types2 and go/types and some test cases.

Because `any` is not treated specially anymore in constraint
position we get additional errors in constraints if `any` is
used before Go1.18 (in addition to the error that type parameter
lists are not permitted before Go1.18).

Fixes #33232.

Change-Id: I85590c6094b07c3e494fef319e3a38d0217cf6f0
Reviewed-on: https://go-review.googlesource.com/c/go/+/351456
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
griesemer committed Sep 22, 2021
1 parent 7a03ca6 commit 1e57748
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 80 deletions.
8 changes: 1 addition & 7 deletions src/cmd/compile/internal/types2/decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,7 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
// This also preserves the grouped output of type parameter lists
// when printing type strings.
if i == 0 || f.Type != list[i-1].Type {
// The predeclared identifier "any" is visible only as a type bound in a type parameter list.
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
if name, _ := unparen(f.Type).(*syntax.Name); name != nil && name.Value == "any" && check.lookup("any") == universeAny {
bound = universeAny.Type()
} else {
bound = check.typ(f.Type)
}
bound = check.typ(f.Type)
}
tparams[i].bound = bound
}
Expand Down
8 changes: 3 additions & 5 deletions src/cmd/compile/internal/types2/testdata/check/typeparams.go2
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ package p

// import "io" // for type assertion tests

// The predeclared identifier "any" can only be used as a constraint
// in a type parameter list.
var _ any // ERROR cannot use any outside constraint position
func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) {
var _ any /* ERROR constraint */
var _ any // ok to use any anywhere
func _[_ any, _ interface{any}](any) {
var _ any
}

func identity[T any](x T) T { return x }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ type (
_ interface{int|~ /* ERROR overlapping terms ~int */ int }
_ interface{~int|~ /* ERROR overlapping terms ~int */ int }
_ interface{~int|MyInt /* ERROR overlapping terms p.MyInt and ~int */ }
_ interface{int|interface{}}
_ interface{int|any}
_ interface{int|~string|union}
_ interface{int|~string|interface{int}}
_ interface{union|union /* ERROR overlapping terms p.union and p.union */ }

// For now we do not permit interfaces with methods in unions.
_ interface{~ /* ERROR invalid use of ~ */ interface{}}
_ interface{~ /* ERROR invalid use of ~ */ any}
_ interface{int|interface /* ERROR cannot use .* in union */ { m() }}
)

type (
// Tilde is not permitted on defined types or interfaces.
foo int
bar interface{}
bar any
_ interface{foo}
_ interface{~ /* ERROR invalid use of ~ */ foo }
_ interface{~ /* ERROR invalid use of ~ */ bar }
Expand Down
8 changes: 4 additions & 4 deletions src/cmd/compile/internal/types2/testdata/examples/types.go2
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ type I1[T any] interface{
}

// There is no such thing as a variadic generic type.
type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
type _[T ... /* ERROR invalid use of ... */ any] struct{}

// Generic interfaces may be embedded as one would expect.
type I2 interface {
Expand Down Expand Up @@ -213,9 +213,9 @@ func Sum[T Adder[T]](list []T) T {
}

// Valid and invalid variations.
type B0 interface {}
type B1[_ any] interface{}
type B2[_, _ any] interface{}
type B0 any
type B1[_ any] any
type B2[_, _ any] any

func _[T1 B0]() {}
func _[T1 B1[T1]]() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

package go1_17

type T[P /* ERROR type parameters require go1\.18 or later */ any] struct{}
type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}

// for init (and main, but we're not in package main) we should only get one error
func init[P /* ERROR func init must have no type parameters */ any]() {}
func main[P /* ERROR type parameters require go1\.18 or later */ any]() {}
func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}

func f[P /* ERROR type parameters require go1\.18 or later */ any](x P) {
func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
Expand Down
6 changes: 0 additions & 6 deletions src/cmd/compile/internal/types2/typexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,10 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
}
return
case universeAny, universeComparable:
// complain if necessary
if !check.allowVersion(check.pkg, 1, 18) {
check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
return // avoid follow-on errors
}
if obj == universeAny {
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
check.softErrorf(e, "cannot use any outside constraint position")
// ok to continue
}
}
check.recordUse(e, obj)

Expand Down
25 changes: 8 additions & 17 deletions src/go/types/decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,27 +668,18 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
*dst = bindTParams(tparams)

index := 0
var bound Type
var bounds []Type
var posns []positioner // bound positions
for _, f := range list.List {
if f.Type == nil {
goto next
}
// The predeclared identifier "any" is visible only as a type bound in a type parameter list.
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
if name, _ := unparen(f.Type).(*ast.Ident); name != nil && name.Name == "any" && check.lookup("any") == universeAny {
bound = universeAny.Type()
} else {
bound = check.typ(f.Type)
}
bounds = append(bounds, bound)
posns = append(posns, f.Type)
for i := range f.Names {
tparams[index+i].bound = bound
// TODO(rfindley) we should be able to rely on f.Type != nil at this point
if f.Type != nil {
bound := check.typ(f.Type)
bounds = append(bounds, bound)
posns = append(posns, f.Type)
for i := range f.Names {
tparams[index+i].bound = bound
}
}

next:
index += len(f.Names)
}

Expand Down
8 changes: 3 additions & 5 deletions src/go/types/testdata/check/typeparams.go2
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ package p

// import "io" // for type assertion tests

// The predeclared identifier "any" can only be used as a constraint
// in a type parameter list.
var _ any // ERROR cannot use any outside constraint position
func _[_ any /* ok here */ , _ interface{any /* ERROR constraint */ }](any /* ERROR constraint */ ) {
var _ any /* ERROR constraint */
var _ any // ok to use any anywhere
func _[_ any, _ interface{any}](any) {
var _ any
}

func identity[T any](x T) T { return x }
Expand Down
6 changes: 3 additions & 3 deletions src/go/types/testdata/examples/constraints.go2
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ type (
_ interface{int|~ /* ERROR overlapping terms ~int */ int }
_ interface{~int|~ /* ERROR overlapping terms ~int */ int }
_ interface{~int|MyInt /* ERROR overlapping terms p.MyInt and ~int */ }
_ interface{int|interface{}}
_ interface{int|any}
_ interface{int|~string|union}
_ interface{int|~string|interface{int}}
_ interface{union|union /* ERROR overlapping terms p.union and p.union */ }

// For now we do not permit interfaces with methods in unions.
_ interface{~ /* ERROR invalid use of ~ */ interface{}}
_ interface{~ /* ERROR invalid use of ~ */ any}
_ interface{int|interface /* ERROR cannot use .* in union */ { m() }}
)

type (
// Tilde is not permitted on defined types or interfaces.
foo int
bar interface{}
bar any
_ interface{foo}
_ interface{~ /* ERROR invalid use of ~ */ foo }
_ interface{~ /* ERROR invalid use of ~ */ bar }
Expand Down
8 changes: 4 additions & 4 deletions src/go/types/testdata/examples/types.go2
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ type I1[T any] interface{
}

// There is no such thing as a variadic generic type.
type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
type _[T ... /* ERROR invalid use of ... */ any] struct{}

// Generic interfaces may be embedded as one would expect.
type I2 interface {
Expand Down Expand Up @@ -219,9 +219,9 @@ func Sum[T Adder[T]](list []T) T {
}

// Valid and invalid variations.
type B0 interface {}
type B1[_ any] interface{}
type B2[_, _ any] interface{}
type B0 any
type B1[_ any] any
type B2[_, _ any] any

func _[T1 B0]() {}
func _[T1 B1[T1]]() {}
Expand Down
8 changes: 4 additions & 4 deletions src/go/types/testdata/fixedbugs/issue47818.go2
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

package go1_17

type T[P /* ERROR type parameters require go1\.18 or later */ any] struct{}
type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}

// for init (and main, but we're not in package main) we should only get one error
func init[P /* ERROR func init must have no type parameters */ any]() {}
func main[P /* ERROR type parameters require go1\.18 or later */ any]() {}
func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}

func f[P /* ERROR type parameters require go1\.18 or later */ any](x P) {
func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
Expand Down
6 changes: 0 additions & 6 deletions src/go/types/typexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,10 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
}
return
case universeAny, universeComparable:
// complain if necessary
if !check.allowVersion(check.pkg, 1, 18) {
check.errorf(e, _UndeclaredName, "undeclared name: %s (requires version go1.18 or later)", e.Name)
return // avoid follow-on errors
}
if obj == universeAny {
// If we allow "any" for general use, this if-statement can be removed (issue #33232).
check.softErrorf(e, _Todo, "cannot use any outside constraint position")
// ok to continue
}
}
check.recordUse(e, obj)

Expand Down
5 changes: 3 additions & 2 deletions test/fixedbugs/issue14652.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// errorcheck
// compile

// Copyright 2016 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.

package p

var x any // ERROR "undefined: any|undefined type .*any.*|cannot use any outside constraint position"
// any is now permitted instead of interface{}
var x any
19 changes: 9 additions & 10 deletions test/typeparam/tparam1.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@

package tparam1

// The predeclared identifier "any" is only visible as a constraint
// in a type parameter list.
var _ any // ERROR "cannot use any outside constraint position"
func _(_ any) // ERROR "cannot use any outside constraint position"
type _[_ any /* ok here */] struct{}
// The predeclared identifier "any" may be used in place of interface{}.
var _ any
func _(_ any)
type _[_ any] struct{}

const N = 10

Expand All @@ -24,16 +23,16 @@ type (
_[T1, T2 any, T3 any] struct{}
)

func _[T any]() {}
func _[T, T any]() {} // ERROR "T redeclared"
func _[T any]() {}
func _[T, T any]() {} // ERROR "T redeclared"
func _[T1, T2 any](x T1) T2 { panic(0) }

// Type parameters are visible from opening [ to end of function.
type C interface{}

func _[T interface{}]() {}
func _[T C]() {}
func _[T struct{}]() {}// ERROR "not an interface"
func _[T interface{}]() {}
func _[T C]() {}
func _[T struct{}]() {} // ERROR "not an interface"
func _[T interface{ m() T }]() {}
func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() {
var _ T1
Expand Down

0 comments on commit 1e57748

Please sign in to comment.