Skip to content

Commit 502198c

Browse files
committed
[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 <[email protected]> Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 82c3f0a commit 502198c

File tree

3 files changed

+58
-11
lines changed

3 files changed

+58
-11
lines changed

src/cmd/compile/internal/types2/api_test.go

+55-9
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ func TestValuesInfo(t *testing.T) {
182182
}
183183

184184
func TestTypesInfo(t *testing.T) {
185+
// Test sources that are not expected to typecheck must start with the broken prefix.
186+
const broken = "package broken_"
187+
185188
var tests = []struct {
186189
src string
187190
expr string // expression
@@ -194,6 +197,39 @@ func TestTypesInfo(t *testing.T) {
194197
{`package b3; var x interface{} = 0i`, `0i`, `complex128`},
195198
{`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
196199

200+
// uses of nil
201+
{`package n0; var _ *int = nil`, `nil`, `untyped nil`},
202+
{`package n1; var _ func() = nil`, `nil`, `untyped nil`},
203+
{`package n2; var _ []byte = nil`, `nil`, `untyped nil`},
204+
{`package n3; var _ map[int]int = nil`, `nil`, `untyped nil`},
205+
{`package n4; var _ chan int = nil`, `nil`, `untyped nil`},
206+
{`package n5; var _ interface{} = nil`, `nil`, `untyped nil`},
207+
{`package n6; import "unsafe"; var _ unsafe.Pointer = nil`, `nil`, `untyped nil`},
208+
209+
{`package n10; var (x *int; _ = x == nil)`, `nil`, `untyped nil`},
210+
{`package n11; var (x func(); _ = x == nil)`, `nil`, `untyped nil`},
211+
{`package n12; var (x []byte; _ = x == nil)`, `nil`, `untyped nil`},
212+
{`package n13; var (x map[int]int; _ = x == nil)`, `nil`, `untyped nil`},
213+
{`package n14; var (x chan int; _ = x == nil)`, `nil`, `untyped nil`},
214+
{`package n15; var (x interface{}; _ = x == nil)`, `nil`, `untyped nil`},
215+
{`package n15; import "unsafe"; var (x unsafe.Pointer; _ = x == nil)`, `nil`, `untyped nil`},
216+
217+
{`package n20; var _ = (*int)(nil)`, `nil`, `untyped nil`},
218+
{`package n21; var _ = (func())(nil)`, `nil`, `untyped nil`},
219+
{`package n22; var _ = ([]byte)(nil)`, `nil`, `untyped nil`},
220+
{`package n23; var _ = (map[int]int)(nil)`, `nil`, `untyped nil`},
221+
{`package n24; var _ = (chan int)(nil)`, `nil`, `untyped nil`},
222+
{`package n25; var _ = (interface{})(nil)`, `nil`, `untyped nil`},
223+
{`package n26; import "unsafe"; var _ = unsafe.Pointer(nil)`, `nil`, `untyped nil`},
224+
225+
{`package n30; func f(*int) { f(nil) }`, `nil`, `untyped nil`},
226+
{`package n31; func f(func()) { f(nil) }`, `nil`, `untyped nil`},
227+
{`package n32; func f([]byte) { f(nil) }`, `nil`, `untyped nil`},
228+
{`package n33; func f(map[int]int) { f(nil) }`, `nil`, `untyped nil`},
229+
{`package n34; func f(chan int) { f(nil) }`, `nil`, `untyped nil`},
230+
{`package n35; func f(interface{}) { f(nil) }`, `nil`, `untyped nil`},
231+
{`package n35; import "unsafe"; func f(unsafe.Pointer) { f(nil) }`, `nil`, `untyped nil`},
232+
197233
// comma-ok expressions
198234
{`package p0; var x interface{}; var _, _ = x.(int)`,
199235
`x.(int)`,
@@ -275,33 +311,43 @@ func TestTypesInfo(t *testing.T) {
275311
},
276312

277313
// tests for broken code that doesn't parse or type-check
278-
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
279-
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
280-
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
281-
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
314+
{broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
315+
{broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
316+
{broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
317+
{broken + `x3; var x = panic("");`, `panic`, `func(interface{})`},
282318
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
283-
{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
319+
{broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
284320

285321
// parameterized functions
286322
{`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ any](T₁)`},
287323
{`package p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
288-
{`package p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
289-
{`package p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`},
324+
{`package p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ any](T₁)`},
325+
{`package p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
290326

291327
// type parameters
292328
{`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
293329
{`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`},
294330
{`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`},
295331
{`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`},
296-
{`package t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `t4.t[P₁, Q₂ interface{m()}]`},
332+
{broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P₁, Q₂ interface{m()}]`},
297333

298334
// instantiated types must be sanitized
299335
{`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
300336
}
301337

302338
for _, test := range tests {
303339
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
304-
name, _ := mayTypecheck(t, "TypesInfo", test.src, &info)
340+
var name string
341+
if strings.HasPrefix(test.src, broken) {
342+
var err error
343+
name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
344+
if err == nil {
345+
t.Errorf("package %s: expected to fail but passed", name)
346+
continue
347+
}
348+
} else {
349+
name = mustTypecheck(t, "TypesInfo", test.src, &info)
350+
}
305351

306352
// look for expression type
307353
var typ Type

src/cmd/compile/internal/types2/conversions.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ func (check *Checker) conversion(x *operand, T Type) {
5656
// - Keep untyped nil for untyped nil arguments.
5757
// - For integer to string conversions, keep the argument type.
5858
// (See also the TODO below.)
59-
if IsInterface(T) || constArg && !isConstType(T) {
60-
final = Default(x.typ)
59+
if IsInterface(T) || constArg && !isConstType(T) || x.isNil() {
60+
final = Default(x.typ) // default type of untyped nil is untyped nil
6161
} else if isInteger(x.typ) && isString(T) {
6262
final = x.typ
6363
}

src/cmd/compile/internal/types2/expr.go

+1
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
667667
if !hasNil(target) {
668668
goto Error
669669
}
670+
target = Typ[UntypedNil]
670671
default:
671672
goto Error
672673
}

0 commit comments

Comments
 (0)