-// UNREVIEWED
// Copyright 2013 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.
panic("unimplemented")
}
+// genericPkg is a source prefix for packages that contain generic code.
+const genericPkg = "package generic_"
+
+// brokenPkg is a source prefix for packages that are not expected to parse
+// or type-check cleanly. They are always parsed assuming that they contain
+// generic code.
+const brokenPkg = "package broken_"
+
func parseSrc(path, src string) (*syntax.File, error) {
+ var mode syntax.Mode
+ if strings.HasPrefix(src, genericPkg) || strings.HasPrefix(src, brokenPkg) {
+ mode = syntax.AllowGenerics
+ }
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
- return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+ return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, mode)
}
func pkgFor(path, source string, info *Info) (*Package, error) {
}
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 {
src string
expr string // expression
},
// tests for broken code that doesn't parse or type-check
- {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
- {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
- {broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
- {broken + `x3; var x = panic("");`, `panic`, `func(interface{})`},
+ {brokenPkg + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
+ {brokenPkg + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
+ {brokenPkg + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
+ {brokenPkg + `x3; var x = panic("");`, `panic`, `func(interface{})`},
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
- {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
+ {brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
// parameterized functions
- {`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](T₁)`},
- {`package p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
- {`package p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`},
- {`package p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
+ {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](T₁)`},
+ {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
+ {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`},
+ {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
// 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 t1; type t[P any] int; var _ t[int]`, `t`, `t1.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{}]`},
- {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P₁, Q₂ interface{m()}]`},
+ {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
+ {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P₁ interface{}]`},
+ {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P₁ interface{}]`},
+ {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P₁, Q₂ interface{}]`},
+ {brokenPkg + `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
- {`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
+ {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
// issue 45096
- {`package issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `T₁`},
+ {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `T₁`},
}
for _, test := range tests {
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
var name string
- if strings.HasPrefix(test.src, broken) {
+ if strings.HasPrefix(test.src, brokenPkg) {
var err error
name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
if err == nil {
targs []string
sig string
}{
- {`package p0; func f[T any](T); func _() { f(42) }`,
+ {genericPkg + `p0; func f[T any](T); func _() { f(42) }`,
`f`,
[]string{`int`},
`func(int)`,
},
- {`package p1; func f[T any](T) T; func _() { f('@') }`,
+ {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`,
`f`,
[]string{`rune`},
`func(rune) rune`,
},
- {`package p2; func f[T any](...T) T; func _() { f(0i) }`,
+ {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`,
`f`,
[]string{`complex128`},
`func(...complex128) complex128`,
},
- {`package p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
+ {genericPkg + `p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
`f`,
[]string{`float64`, `string`, `byte`},
`func(float64, *string, []byte)`,
},
- {`package p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
+ {genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
`f`,
[]string{`float64`, `byte`},
`func(float64, *byte, ...[]byte)`,
},
// we don't know how to translate these but we can type-check them
- {`package q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
+ {genericPkg + `q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
`x.m`,
[]string{`int`},
`func(int)`,
},
- {`package q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
+ {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
`x.m`,
[]string{`int`},
`func(int) int`,
},
- {`package q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
+ {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
`x.m`,
[]string{`int`},
`func(...int) int`,
},
- {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
+ {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
`x.m`,
[]string{`float64`, `string`, `byte`},
`func(float64, *string, []byte)`,
},
- {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
+ {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
`x.m`,
[]string{`float64`, `byte`},
`func(float64, *byte, ...[]byte)`,
},
- {`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`,
+ {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`,
`x.m`,
[]string{`int`},
`func(int)`,
},
// TODO(gri) record method type parameters in syntax.FuncType so we can check this
- // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
+ // {genericPkg + `r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
// `x.m`,
// []string{`float64`},
// `func(float64)`,
// },
- {`package s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
+ {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
`f`,
[]string{`string`, `*string`},
`func(x string)`,
},
- {`package s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
+ {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
`f`,
[]string{`int`, `*int`},
`func(x []int)`,
},
- {`package s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
+ {genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
`f`,
[]string{`int`, `chan<- int`},
`func(x []int)`,
},
- {`package s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
+ {genericPkg + `s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
`f`,
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
`func(x []int)`,
},
- {`package t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
+ {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
`f`,
[]string{`string`, `*string`},
`func() string`,
},
- {`package t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
+ {genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
`f`,
[]string{`int`, `chan<- int`},
`func() []int`,
},
- {`package t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
+ {genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
`f`,
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
`func() []int`,
// generic types must be sanitized
// (need to use sufficiently nested types to provoke unexpanded types)
- {`package g0; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
- {`package g1; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
- {`package g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
- {`package g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var g3.g func(x struct{f g3.t[string]})`},
+ {genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
+ {genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
+ {genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
+ {genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
}
for _, test := range tests {
// generic types must be sanitized
// (need to use sufficiently nested types to provoke unexpanded types)
- {`package g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
- {`package g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
- {`package g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
- {`package g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func g3.f(x struct{f g3.t[string]})`},
+ {genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
+ {genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
+ {genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
+ {genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
}
for _, test := range tests {
}
}
+func TestConvertibleTo(t *testing.T) {
+ for _, test := range []struct {
+ v, t Type
+ want bool
+ }{
+ {Typ[Int], Typ[Int], true},
+ {Typ[Int], Typ[Float32], true},
+ {newDefined(Typ[Int]), Typ[Int], true},
+ {newDefined(new(Struct)), new(Struct), true},
+ {newDefined(Typ[Int]), new(Struct), false},
+ {Typ[UntypedInt], Typ[Int], true},
+ // Untyped string values are not permitted by the spec, so the below
+ // behavior is undefined.
+ {Typ[UntypedString], Typ[String], true},
+ } {
+ if got := ConvertibleTo(test.v, test.t); got != test.want {
+ t.Errorf("ConvertibleTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+ }
+ }
+}
+
+func TestAssignableTo(t *testing.T) {
+ for _, test := range []struct {
+ v, t Type
+ want bool
+ }{
+ {Typ[Int], Typ[Int], true},
+ {Typ[Int], Typ[Float32], false},
+ {newDefined(Typ[Int]), Typ[Int], false},
+ {newDefined(new(Struct)), new(Struct), true},
+ {Typ[UntypedBool], Typ[Bool], true},
+ {Typ[UntypedString], Typ[Bool], false},
+ // Neither untyped string nor untyped numeric assignments arise during
+ // normal type checking, so the below behavior is technically undefined by
+ // the spec.
+ {Typ[UntypedString], Typ[String], true},
+ {Typ[UntypedInt], Typ[Int], true},
+ } {
+ if got := AssignableTo(test.v, test.t); got != test.want {
+ t.Errorf("AssignableTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+ }
+ }
+}
+
func TestIdentical_issue15173(t *testing.T) {
// Identical should allow nil arguments and be symmetric.
for _, test := range []struct {