mirror of
https://github.com/golang/go
synced 2024-11-26 12:09:04 -07:00
[dev.typeparams] cmd/compile/internal/types2: consistently report nil type as "untyped nil"
This fixes an inconsistency where the type for nil in code such as var x unsafe.Pointer = nil and in conversions of the form T(nil) (where T is a pointer, function, slice, map, channel, interface, or unsafe.Pointer) was reported as (converted to) the respective type. For all other operations that accept a nil value, we don't do this conversion for nil. (We never change the type of the untyped nil value, in contrast to other untyped values where we give the values context-specific types.) It may still be useful to change this behavior and - consistently - report a converted nil type like we do for any other type, but for now this CL simply fixes the existing inconsistency. Added tests and fixed existing test harness. Updates #13061. Change-Id: Ia82832845c096e3cbc4a239ba3d6c8b9a9d274c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/284052 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
82c3f0a358
commit
502198c8dc
@ -182,6 +182,9 @@ func TestValuesInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTypesInfo(t *testing.T) {
|
func TestTypesInfo(t *testing.T) {
|
||||||
|
// Test sources that are not expected to typecheck must start with the broken prefix.
|
||||||
|
const broken = "package broken_"
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
src string
|
src string
|
||||||
expr string // expression
|
expr string // expression
|
||||||
@ -194,6 +197,39 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
{`package b3; var x interface{} = 0i`, `0i`, `complex128`},
|
{`package b3; var x interface{} = 0i`, `0i`, `complex128`},
|
||||||
{`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
|
{`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
|
||||||
|
|
||||||
|
// uses of nil
|
||||||
|
{`package n0; var _ *int = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n1; var _ func() = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n2; var _ []byte = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n3; var _ map[int]int = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n4; var _ chan int = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n5; var _ interface{} = nil`, `nil`, `untyped nil`},
|
||||||
|
{`package n6; import "unsafe"; var _ unsafe.Pointer = nil`, `nil`, `untyped nil`},
|
||||||
|
|
||||||
|
{`package n10; var (x *int; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n11; var (x func(); _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n12; var (x []byte; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n13; var (x map[int]int; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n14; var (x chan int; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n15; var (x interface{}; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n15; import "unsafe"; var (x unsafe.Pointer; _ = x == nil)`, `nil`, `untyped nil`},
|
||||||
|
|
||||||
|
{`package n20; var _ = (*int)(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n21; var _ = (func())(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n22; var _ = ([]byte)(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n23; var _ = (map[int]int)(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n24; var _ = (chan int)(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n25; var _ = (interface{})(nil)`, `nil`, `untyped nil`},
|
||||||
|
{`package n26; import "unsafe"; var _ = unsafe.Pointer(nil)`, `nil`, `untyped nil`},
|
||||||
|
|
||||||
|
{`package n30; func f(*int) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n31; func f(func()) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n32; func f([]byte) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n33; func f(map[int]int) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n34; func f(chan int) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n35; func f(interface{}) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
{`package n35; import "unsafe"; func f(unsafe.Pointer) { f(nil) }`, `nil`, `untyped nil`},
|
||||||
|
|
||||||
// comma-ok expressions
|
// comma-ok expressions
|
||||||
{`package p0; var x interface{}; var _, _ = x.(int)`,
|
{`package p0; var x interface{}; var _, _ = x.(int)`,
|
||||||
`x.(int)`,
|
`x.(int)`,
|
||||||
@ -275,25 +311,25 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// tests for broken code that doesn't parse or type-check
|
// tests for broken code that doesn't parse or type-check
|
||||||
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
{broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
||||||
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
{broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
||||||
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
|
{broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
|
||||||
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
|
{broken + `x3; var x = panic("");`, `panic`, `func(interface{})`},
|
||||||
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
||||||
{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
|
{broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
|
||||||
|
|
||||||
// parameterized functions
|
// parameterized functions
|
||||||
{`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ any](T₁)`},
|
{`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ any](T₁)`},
|
||||||
{`package p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
|
{`package p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
|
||||||
{`package p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
|
{`package p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ any](T₁)`},
|
||||||
{`package p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`},
|
{`package p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
|
||||||
|
|
||||||
// type parameters
|
// type parameters
|
||||||
{`package t0; type t[] int; var _ t`, `t`, `t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
|
{`package t0; type t[] int; var _ t`, `t`, `t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
|
||||||
{`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`},
|
{`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`},
|
||||||
{`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`},
|
{`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`},
|
||||||
{`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`},
|
{`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`},
|
||||||
{`package t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `t4.t[P₁, Q₂ interface{m()}]`},
|
{broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P₁, Q₂ interface{m()}]`},
|
||||||
|
|
||||||
// instantiated types must be sanitized
|
// instantiated types must be sanitized
|
||||||
{`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
|
{`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
|
||||||
@ -301,7 +337,17 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
|
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
|
||||||
name, _ := mayTypecheck(t, "TypesInfo", test.src, &info)
|
var name string
|
||||||
|
if strings.HasPrefix(test.src, broken) {
|
||||||
|
var err error
|
||||||
|
name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("package %s: expected to fail but passed", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name = mustTypecheck(t, "TypesInfo", test.src, &info)
|
||||||
|
}
|
||||||
|
|
||||||
// look for expression type
|
// look for expression type
|
||||||
var typ Type
|
var typ Type
|
||||||
|
@ -56,8 +56,8 @@ func (check *Checker) conversion(x *operand, T Type) {
|
|||||||
// - Keep untyped nil for untyped nil arguments.
|
// - Keep untyped nil for untyped nil arguments.
|
||||||
// - For integer to string conversions, keep the argument type.
|
// - For integer to string conversions, keep the argument type.
|
||||||
// (See also the TODO below.)
|
// (See also the TODO below.)
|
||||||
if IsInterface(T) || constArg && !isConstType(T) {
|
if IsInterface(T) || constArg && !isConstType(T) || x.isNil() {
|
||||||
final = Default(x.typ)
|
final = Default(x.typ) // default type of untyped nil is untyped nil
|
||||||
} else if isInteger(x.typ) && isString(T) {
|
} else if isInteger(x.typ) && isString(T) {
|
||||||
final = x.typ
|
final = x.typ
|
||||||
}
|
}
|
||||||
|
@ -667,6 +667,7 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
|
|||||||
if !hasNil(target) {
|
if !hasNil(target) {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
target = Typ[UntypedNil]
|
||||||
default:
|
default:
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user