diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 025dcbf2c84..3aa06e8939f 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -72,7 +72,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) { // A generic (non-instantiated) function value cannot be assigned to a variable. if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { - check.errorf(x, 0, "cannot use generic function %s without instantiation in %s", x, context) + check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context) } // spec: "If a left-hand side is the blank identifier, any typed or diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 17916c6b0c6..28697d90870 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -589,7 +589,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Alignof: // unsafe.Alignof(x T) uintptr if asTypeParam(x.typ) != nil { - check.invalidOp(call, 0, "unsafe.Alignof undefined for %s", x) + check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x) return } check.assignment(x, nil, "argument to unsafe.Alignof") @@ -650,7 +650,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Sizeof: // unsafe.Sizeof(x T) uintptr if asTypeParam(x.typ) != nil { - check.invalidOp(call, 0, "unsafe.Sizeof undefined for %s", x) + check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x) return } check.assignment(x, nil, "argument to unsafe.Sizeof") diff --git a/src/go/types/call.go b/src/go/types/call.go index 97a9d0ea8f3..d9a7b440ec1 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -62,7 +62,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKi if t := asInterface(T); t != nil { check.completeInterface(token.NoPos, t) if t.IsConstraint() { - check.errorf(call, 0, "cannot use interface %s in conversion (contains type list or is comparable)", T) + check.errorf(call, _Todo, "cannot use interface %s in conversion (contains type list or is comparable)", T) break } } @@ -117,7 +117,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKi // check number of type arguments if n > len(sig.tparams) { - check.errorf(args[n-1], 0, "got %d type arguments but want %d", n, len(sig.tparams)) + check.errorf(args[n-1], _Todo, "got %d type arguments but want %d", n, len(sig.tparams)) x.mode = invalid x.expr = orig return expression @@ -423,7 +423,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper assert(targs[failed] == nil) tpar := sig.tparams[failed] ppos := check.fset.Position(tpar.pos).String() - check.errorf(inNode(call, call.Rparen), 0, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs) + check.errorf(inNode(call, call.Rparen), _Todo, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs) return } } @@ -821,7 +821,7 @@ func (check *Checker) useLHS(arg ...ast.Expr) { // instantiatedOperand reports an error of x is an uninstantiated (generic) type and sets x.typ to Typ[Invalid]. func (check *Checker) instantiatedOperand(x *operand) { if x.mode == typexpr && isGeneric(x.typ) { - check.errorf(x, 0, "cannot use generic type %s without instantiation", x.typ) + check.errorf(x, _Todo, "cannot use generic type %s without instantiation", x.typ) x.typ = Typ[Invalid] } } diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 66943d676ca..51eae052f37 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -68,11 +68,11 @@ func splitError(err error) (pos, msg string) { return } -func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) { +func parseFiles(t *testing.T, filenames []string, mode parser.Mode) ([]*ast.File, []error) { var files []*ast.File var errlist []error for _, filename := range filenames { - file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + file, err := parser.ParseFile(fset, filename, nil, mode) if file == nil { t.Fatalf("%s: %s", filename, err) } @@ -191,8 +191,17 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { } func checkFiles(t *testing.T, sources []string) { + if len(sources) == 0 { + t.Fatal("no source files") + } + + mode := parser.AllErrors + if strings.HasSuffix(sources[0], ".go2") { + mode |= parser.ParseTypeParams + } + // parse files and collect parser errors - files, errlist := parseFiles(t, sources) + files, errlist := parseFiles(t, sources, mode) pkgName := "" if len(files) > 0 { @@ -208,7 +217,6 @@ func checkFiles(t *testing.T, sources []string) { // typecheck and collect typechecker errors var conf Config - // TODO(rFindley) parse generics when given a .go2 suffix. // special case for importC.src if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") { @@ -274,11 +282,8 @@ func TestCheck(t *testing.T) { checkFiles(t, strings.Split(*testFiles, " ")) } -func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "testdata") } - -// TODO(rFindley) add go2 examples. -// func TestExamples(t *testing.T) { testDir(t, "examples") } - +func TestTestdata(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "testdata") } +func TestExamples(t *testing.T) { testDir(t, "examples") } func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") } func testDir(t *testing.T, dir string) { @@ -290,20 +295,18 @@ func testDir(t *testing.T, dir string) { return } - for count, fi := range fis { + for _, fi := range fis { path := filepath.Join(dir, fi.Name()) // if fi is a directory, its files make up a single package + var files []string if fi.IsDir() { - if testing.Verbose() { - fmt.Printf("%3d %s\n", count, path) - } fis, err := ioutil.ReadDir(path) if err != nil { t.Error(err) continue } - files := make([]string, len(fis)) + files = make([]string, len(fis)) for i, fi := range fis { // if fi is a directory, checkFiles below will complain files[i] = filepath.Join(path, fi.Name()) @@ -311,14 +314,11 @@ func testDir(t *testing.T, dir string) { fmt.Printf("\t%s\n", files[i]) } } + } else { + files = []string{path} + } + t.Run(filepath.Base(path), func(t *testing.T) { checkFiles(t, files) - continue - } - - // otherwise, fi is a stand-alone file - if testing.Verbose() { - fmt.Printf("%3d %s\n", count, path) - } - checkFiles(t, []string{path}) + }) } } diff --git a/src/go/types/decl.go b/src/go/types/decl.go index e62edfadb2b..bd2c5466617 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -740,7 +740,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam setBoundAt(index+i, bound) } } else if bound != Typ[Invalid] { - check.errorf(f.Type, 0, "%s is not an interface", bound) + check.errorf(f.Type, _Todo, "%s is not an interface", bound) } next: diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go index 2c5a291660a..7e620915585 100644 --- a/src/go/types/errorcodes.go +++ b/src/go/types/errorcodes.go @@ -1311,4 +1311,8 @@ const ( // return i // } _InvalidGo + + // _Todo is a placeholder for error codes that have not been decided. + // TODO(rFindley) remove this error code after deciding on errors for generics code. + _Todo ) diff --git a/src/go/types/examples/functions.go2 b/src/go/types/examples/functions.go2 new file mode 100644 index 00000000000..c6ad511bd63 --- /dev/null +++ b/src/go/types/examples/functions.go2 @@ -0,0 +1,214 @@ +// Copyright 2019 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. + +// This file shows some examples of type-parameterized functions. + +package p + +// Reverse is a generic function that takes a []T argument and +// reverses that slice in place. +func Reverse[T any](list []T) { + i := 0 + j := len(list)-1 + for i < j { + list[i], list[j] = list[j], list[i] + i++ + j-- + } +} + +func _() { + // Reverse can be called with an explicit type argument. + Reverse[int](nil) + Reverse[string]([]string{"foo", "bar"}) + Reverse[struct{x, y int}]([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) + + // Since the type parameter is used for an incoming argument, + // it can be inferred from the provided argument's type. + Reverse([]string{"foo", "bar"}) + Reverse([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}}) + + // But the incoming argument must have a type, even if it's a + // default type. An untyped nil won't work. + // Reverse(nil) // this won't type-check + + // A typed nil will work, though. + Reverse([]int(nil)) +} + +// Certain functions, such as the built-in `new` could be written using +// type parameters. +func new[T any]() *T { + var x T + return &x +} + +// When calling our own `new`, we need to pass the type parameter +// explicitly since there is no (value) argument from which the +// result type could be inferred. We don't try to infer the +// result type from the assignment to keep things simple and +// easy to understand. +var _ = new[int]() +var _ *float64 = new(float64)() // the result type is indeed *float64 + +// A function may have multiple type parameters, of course. +func foo[A, B, C any](a A, b []B, c *C) B { + // do something here + return b[0] +} + +// As before, we can pass type parameters explicitly. +var s = foo[int, string, float64](1, []string{"first"}, new(float64)()) + +// Or we can use type inference. +var _ float64 = foo(42, []float64{1.0}, &s) + +// Type inference works in a straight-forward manner even +// for variadic functions. +func variadic[A, B any](A, B, ...B) int + +// var _ = variadic(1) // ERROR not enough arguments +var _ = variadic(1, 2.3) +var _ = variadic(1, 2.3, 3.4, 4.5) +var _ = variadic[int, float64](1, 2.3, 3.4, 4) + +// Type inference also works in recursive function calls where +// the inferred type is the type parameter of the caller. +func f1[T any](x T) { + f1(x) +} + +func f2a[T any](x, y T) { + f2a(x, y) +} + +func f2b[T any](x, y T) { + f2b(y, x) +} + +func g2a[P, Q any](x P, y Q) { + g2a(x, y) +} + +func g2b[P, Q any](x P, y Q) { + g2b(y, x) +} + +// Here's an example of a recursive function call with variadic +// arguments and type inference inferring the type parameter of +// the caller (i.e., itself). +func max[T interface{ type int }](x ...T) T { + var x0 T + if len(x) > 0 { + x0 = x[0] + } + if len(x) > 1 { + x1 := max(x[1:]...) + if x1 > x0 { + return x1 + } + } + return x0 +} + +// When inferring channel types, the channel direction is ignored +// for the purpose of type inference. Once the type has been in- +// fered, the usual parameter passing rules are applied. +// Thus even if a type can be inferred successfully, the function +// call may not be valid. + +func fboth[T any](chan T) +func frecv[T any](<-chan T) +func fsend[T any](chan<- T) + +func _() { + var both chan int + var recv <-chan int + var send chan<-int + + fboth(both) + fboth(recv /* ERROR cannot use */ ) + fboth(send /* ERROR cannot use */ ) + + frecv(both) + frecv(recv) + frecv(send /* ERROR cannot use */ ) + + fsend(both) + fsend(recv /* ERROR cannot use */) + fsend(send) +} + +func ffboth[T any](func(chan T)) +func ffrecv[T any](func(<-chan T)) +func ffsend[T any](func(chan<- T)) + +func _() { + var both func(chan int) + var recv func(<-chan int) + var send func(chan<- int) + + ffboth(both) + ffboth(recv /* ERROR cannot use */ ) + ffboth(send /* ERROR cannot use */ ) + + ffrecv(both /* ERROR cannot use */ ) + ffrecv(recv) + ffrecv(send /* ERROR cannot use */ ) + + ffsend(both /* ERROR cannot use */ ) + ffsend(recv /* ERROR cannot use */ ) + ffsend(send) +} + +// When inferring elements of unnamed composite parameter types, +// if the arguments are defined types, use their underlying types. +// Even though the matching types are not exactly structurally the +// same (one is a type literal, the other a named type), because +// assignment is permitted, parameter passing is permitted as well, +// so type inference should be able to handle these cases well. + +func g1[T any]([]T) +func g2[T any]([]T, T) +func g3[T any](*T, ...T) + +func _() { + type intSlize []int + g1([]int{}) + g1(intSlize{}) + g2(nil, 0) + + type myString string + var s1 string + g3(nil, "1", myString("2"), "3") + g3(&s1, "1", myString /* ERROR does not match */ ("2"), "3") + + type myStruct struct{x int} + var s2 myStruct + g3(nil, struct{x int}{}, myStruct{}) + g3(&s2, struct{x int}{}, myStruct{}) + g3(nil, myStruct{}, struct{x int}{}) + g3(&s2, myStruct{}, struct{x int}{}) +} + +// Here's a realistic example. + +func append[T any](s []T, t ...T) []T + +func _() { + var f func() + type Funcs []func() + var funcs Funcs + _ = append(funcs, f) +} + +// Generic type declarations cannot have empty type parameter lists +// (that would indicate a slice type). Thus, generic functions cannot +// have empty type parameter lists, either. This is a syntax error. + +func h[] /* ERROR empty type parameter list */ () + +func _() { + h[] /* ERROR operand */ () +} diff --git a/src/go/types/examples/methods.go2 b/src/go/types/examples/methods.go2 new file mode 100644 index 00000000000..c294627837f --- /dev/null +++ b/src/go/types/examples/methods.go2 @@ -0,0 +1,96 @@ +// Copyright 2019 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. + +// This file shows some examples of methods on type-parameterized types. + +package p + +// Parameterized types may have methods. +type T1[A any] struct{ a A } + +// When declaring a method for a parameterized type, the "instantiated" +// receiver type acts as an implicit declaration of the type parameters +// for the receiver type. In the example below, method m1 on type T1 has +// the receiver type T1[A] which declares the type parameter A for use +// with this method. That is, within the method m1, A stands for the +// actual type argument provided to an instantiated T1. +func (t T1[A]) m1() A { return t.a } + +// For instance, if T1 is instantiated with the type int, the type +// parameter A in m1 assumes that type (int) as well and we can write +// code like this: +var x T1[int] +var _ int = x.m1() + +// Because the type parameter provided to a parameterized receiver type +// is declared through that receiver declaration, it must be an identifier. +// It cannot possibly be some other type because the receiver type is not +// instantiated with concrete types, it is standing for the parameterized +// receiver type. +func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} + +// Note that using what looks like a predeclared identifier, say int, +// as type parameter in this situation is deceptive and considered bad +// style. In m3 below, int is the name of the local receiver type parameter +// and it shadows the predeclared identifier int which then cannot be used +// anymore as expected. +// This is no different from locally redelaring a predeclared identifier +// and usually should be avoided. There are some notable exceptions; e.g., +// sometimes it makes sense to use the identifier "copy" which happens to +// also be the name of a predeclared built-in function. +func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot use 42 .* as int */ } + +// The names of the type parameters used in a parameterized receiver +// type don't have to match the type parameter names in the the declaration +// of the type used for the receiver. In our example, even though T1 is +// declared with type parameter named A, methods using that receiver type +// are free to use their own name for that type parameter. That is, the +// name of type parameters is always local to the declaration where they +// are introduced. In our example we can write a method m2 and use the +// name X instead of A for the type parameter w/o any difference. +func (t T1[X]) m4() X { return t.a } + +// If the receiver type is parameterized, type parameters must always be +// provided: this simply follows from the general rule that a parameterized +// type must be instantiated before it can be used. A method receiver +// declaration using a parameterized receiver type is no exception. It is +// simply that such receiver type expressions perform two tasks simultaneously: +// they declare the (local) type parameters and then use them to instantiate +// the receiver type. Forgetting to provide a type parameter leads to an error. +func (t T1 /* ERROR generic type .* without instantiation */ ) m5() {} + +// However, sometimes we don't need the type parameter, and thus it is +// inconvenient to have to choose a name. Since the receiver type expression +// serves as a declaration for its type parameters, we are free to choose the +// blank identifier: +func (t T1[_]) m6() {} + +// Naturally, these rules apply to any number of type parameters on the receiver +// type. Here are some more complex examples. +type T2[A, B, C any] struct { + a A + b B + c C +} + +// Naming of the type parameters is local and has no semantic impact: +func (t T2[A, B, C]) m1() (A, B, C) { return t.a, t.b, t.c } +func (t T2[C, B, A]) m2() (C, B, A) { return t.a, t.b, t.c } +func (t T2[X, Y, Z]) m3() (X, Y, Z) { return t.a, t.b, t.c } + +// Type parameters may be left blank if they are not needed: +func (t T2[A, _, C]) m4() (A, C) { return t.a, t.c } +func (t T2[_, _, X]) m5() X { return t.c } +func (t T2[_, _, _]) m6() {} + +// As usual, blank names may be used for any object which we don't care about +// using later. For instance, we may write an unnamed method with a receiver +// that cannot be accessed: +func (_ T2[_, _, _]) _() int { return 42 } + +// Because a receiver parameter list is simply a parameter list, we can +// leave the receiver argument away for receiver types. +type T0 struct{} +func (T0) _() {} +func (T1[A]) _() {} diff --git a/src/go/types/examples/types.go2 b/src/go/types/examples/types.go2 new file mode 100644 index 00000000000..5aa624c1318 --- /dev/null +++ b/src/go/types/examples/types.go2 @@ -0,0 +1,266 @@ +// Copyright 2019 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. + +// This file shows some examples of generic types. + +package p + +// List is just what it says - a slice of E elements. +type List[E any] []E + +// A generic (parameterized) type must always be instantiated +// before it can be used to designate the type of a variable +// (including a struct field, or function parameter); though +// for the latter cases, the provided type may be another type +// parameter. So: +var _ List[byte] = []byte{} + +// A generic binary tree might be declared as follows. +type Tree[E any] struct { + left, right *Tree[E] + payload E +} + +// A simple instantiation of Tree: +var root1 Tree[int] + +// The actual type parameter provided may be a generic type itself: +var root2 Tree[List[int]] + +// A couple of more complex examples. +// We don't need extra parentheses around the element type of the slices on +// the right (unlike when we use ()'s rather than []'s for type parameters). +var _ List[List[int]] = []List[int]{} +var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{} + +// Type parameters act like type aliases when used in generic types +// in the sense that we can "emulate" a specific type instantiation +// with type aliases. +type T1[P any] struct { + f P +} + +type T2[P any] struct { + f struct { + g P + } +} + +var x1 T1[struct{ g int }] +var x2 T2[int] + +func _() { + // This assignment is invalid because the types of x1, x2 are T1(...) + // and T2(...) respectively, which are two different defined types. + x1 = x2 // ERROR assignment + + // This assignment is valid because the types of x1.f and x2.f are + // both struct { g int }; the type parameters act like type aliases + // and their actual names don't come into play here. + x1.f = x2.f +} + +// We can verify this behavior using type aliases instead: +type T1a struct { + f A1 +} +type A1 = struct { g int } + +type T2a struct { + f struct { + g A2 + } +} +type A2 = int + +var x1a T1a +var x2a T2a + +func _() { + x1a = x2a // ERROR assignment + x1a.f = x2a.f +} + +// Another interesting corner case are generic types that don't use +// their type arguments. For instance: +type T[P any] struct{} + +var xint T[int] +var xbool T[bool] + +// Are these two variables of the same type? After all, their underlying +// types are identical. We consider them to be different because each type +// instantiation creates a new named type, in this case T and T +// even if their underlying types are identical. This is sensible because +// we might still have methods that have different signatures or behave +// differently depending on the type arguments, and thus we can't possibly +// consider such types identical. Consequently: +func _() { + xint = xbool // ERROR assignment +} + +// Generic types cannot be used without instantiation. +var _ T // ERROR cannot use generic type T + +// In type context, generic (parameterized) types cannot be parenthesized before +// being instantiated. See also NOTES entry from 12/4/2019. +var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR expected ';' */ int] + +// All types may be parameterized, including interfaces. +type I1[T any] interface{ + m1(T) +} + +// Generic interfaces may be embedded as one would expect. +type I2 interface { + I1(int) // method! + I1[string] // embedded I1 +} + +func _() { + var x I2 + x.I1(0) + x.m1("foo") +} + +type I0 interface { + m0() +} + +type I3 interface { + I0 + I1[bool] + m(string) +} + +func _() { + var x I3 + x.m0() + x.m1(true) + x.m("foo") +} + +// We accept parenthesized embedded struct fields so we can distinguish between +// a named field with a parenthesized type foo (T) and an embedded parameterized +// type (foo(T)), similarly to interace embedding. +// They still need to be valid embedded types after the parentheses are stripped +// (i.e., in contrast to interfaces, we cannot embed a struct literal). The name +// of the embedded field is derived as before, after stripping parentheses. +// (7/14/2020: See comment above. We probably will revert this generalized ability +// if we go with [] for type parameters.) +type _ struct { + int8 + *int16 + *List[int] + + int8 /* ERROR int8 redeclared */ + * /* ERROR List redeclared */ List[int] +} + +// It's possible to declare local types whose underlying types +// are type parameters. As with ordinary type definitions, the +// types underlying properties are "inherited" but the methods +// are not. +func _[T interface{ m(); type int }]() { + type L T + var x L + + // m is not defined on L (it is not "inherited" from + // its underlying type). + x.m /* ERROR x.m undefined */ () + + // But the properties of T, such that as that it supports + // the operations of the types given by its type bound, + // are also the properties of L. + x++ + _ = x - x + + // On the other hand, if we define a local alias for T, + // that alias stands for T as expected. + type A = T + var y A + y.m() + _ = y < 0 +} + +// As a special case, an explicit type argument may be omitted +// from a type parameter bound if the type bound expects exactly +// one type argument. In that case, the type argument is the +// respective type parameter to which the type bound applies. +// Note: We may not permit this syntactic sugar at first. +// Note: This is now disabled. All examples below are adjusted. +type Adder[T any] interface { + Add(T) T +} + +// We don't need to explicitly instantiate the Adder bound +// if we have exactly one type parameter. +func Sum[T Adder[T]](list []T) T { + var sum T + for _, x := range list { + sum = sum.Add(x) + } + return sum +} + +// Valid and invalid variations. +type B0 interface {} +type B1[_ any] interface{} +type B2[_, _ any] interface{} + +func _[T1 B0]() +func _[T1 B1[T1]]() +func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() + +func _[T1, T2 B0]() +func _[T1 B1[T1], T2 B1[T2]]() +func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() + +func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2 + +// When the type argument is left away, the type bound is +// instantiated for each type parameter with that type +// parameter. +// Note: We may not permit this syntactic sugar at first. +func _[A Adder[A], B Adder[B], C Adder[A]]() { + var a A // A's type bound is Adder[A] + a = a.Add(a) + var b B // B's type bound is Adder[B] + b = b.Add(b) + var c C // C's type bound is Adder[A] + a = c.Add(a) +} + +// The type of variables (incl. parameters and return values) cannot +// be an interface with type constraints or be/embed comparable. +type I interface { + type int +} + +var ( + _ interface /* ERROR contains type constraints */ {type int} + _ I /* ERROR contains type constraints */ +) + +func _(I /* ERROR contains type constraints */ ) +func _(x, y, z I /* ERROR contains type constraints */ ) +func _() I /* ERROR contains type constraints */ + +func _() { + var _ I /* ERROR contains type constraints */ +} + +type C interface { + comparable +} + +var _ comparable /* ERROR comparable */ +var _ C /* ERROR comparable */ + +func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ ) + +func _() { + var _ comparable /* ERROR comparable */ + var _ C /* ERROR comparable */ +} diff --git a/src/go/types/fixedbugs/issue39634.go2 b/src/go/types/fixedbugs/issue39634.go2 new file mode 100644 index 00000000000..249542d5411 --- /dev/null +++ b/src/go/types/fixedbugs/issue39634.go2 @@ -0,0 +1,91 @@ +// Copyright 2020 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. + +// Examples adjusted to match new [T any] syntax for type parameters. +// Also, previously permitted empty type parameter lists and instantiations +// are now syntax errors. + +package p + +// crash 1 +type nt1[_ any]interface{g /* ERROR undeclared name */ } +type ph1[e nt1[e],g(d /* ERROR undeclared name */ )]s /* ERROR undeclared name */ +func(*ph1[e,e /* ERROR redeclared */ ])h(d /* ERROR undeclared name */ ) + +// crash 2 +// Disabled: empty []'s are now syntax errors. This example leads to too many follow-on errors. +// type Numeric2 interface{t2 /* ERROR not a type */ } +// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}} + +// crash 3 +type t3 *interface{ t3.p /* ERROR no field or method p */ } + +// crash 4 +type Numeric4 interface{t4 /* ERROR not a type */ } +func t4[T Numeric4](s[]T){if( /* ERROR non-boolean */ 0){*s /* ERROR cannot indirect */ [0]}} + +// crash 7 +type foo7 interface { bar() } +type x7[A any] struct{ foo7 } +func main7() { var _ foo7 = x7[int]{} } + +// crash 8 +type foo8[A any] interface { type A } +func bar8[A foo8[A]](a A) {} +func main8() {} + +// crash 9 +type foo9[A any] interface { type foo9 /* ERROR interface contains type constraints */ [A] } +func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) } + +// crash 12 +var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len)]c /* ERROR undeclared */ /* ERROR undeclared */ + +// crash 15 +func y15() { var a /* ERROR declared but not used */ interface{ p() } = G15[string]{} } +type G15[X any] s /* ERROR undeclared name */ +func (G15 /* ERROR generic type .* without instantiation */ ) p() + +// crash 16 +type Foo16[T any] r16 /* ERROR not a type */ +func r16[T any]() Foo16[Foo16[T]] + +// crash 17 +type Y17 interface{ c() } +type Z17 interface { + c() Y17 + Y17 /* ERROR duplicate method */ +} +func F17[T Z17](T) + +// crash 18 +type o18[T any] []func(_ o18[[]_ /* ERROR cannot use _ */ ]) + +// crash 19 +type Z19 [][[]Z19{}[0][0]]c19 /* ERROR undeclared */ + +// crash 20 +type Z20 /* ERROR illegal cycle */ interface{ Z20 } +func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) } + +// crash 21 +type Z21 /* ERROR illegal cycle */ interface{ Z21 } +func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) } + +// crash 24 +type T24[P any] P +func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() } + +// crash 25 +type T25[A any] int +func (t T25[A]) m1() {} +var x T25 /* ERROR without instantiation */ .m1 + +// crash 26 +type T26 = interface{ F26[ /* ERROR methods cannot have type parameters */ Z any]() } +func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ } + +// crash 27 +func e27[T any]() interface{ x27 /* ERROR not a type */ } +func x27() { e27() /* ERROR cannot infer T */ } diff --git a/src/go/types/fixedbugs/issue39664.go2 b/src/go/types/fixedbugs/issue39664.go2 new file mode 100644 index 00000000000..3b3ec56980e --- /dev/null +++ b/src/go/types/fixedbugs/issue39664.go2 @@ -0,0 +1,15 @@ +// Copyright 2020 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 + +type T[_ any] struct {} + +func (T /* ERROR instantiation */ ) m() + +func _() { + var x interface { m() } + x = T[int]{} + _ = x +} diff --git a/src/go/types/fixedbugs/issue39680.go2 b/src/go/types/fixedbugs/issue39680.go2 new file mode 100644 index 00000000000..9bc26f35461 --- /dev/null +++ b/src/go/types/fixedbugs/issue39680.go2 @@ -0,0 +1,27 @@ +// Copyright 2020 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 + +import "fmt" + +// Minimal test case. +func _[T interface{type T}](x T) T{ + return x +} + +// Test case from issue. +type constr[T any] interface { + type T +} + +func Print[T constr[T]](s []T) { + for _, v := range s { + fmt.Print(v) + } +} + +func f() { + Print([]string{"Hello, ", "playground\n"}) +} diff --git a/src/go/types/fixedbugs/issue39693.go2 b/src/go/types/fixedbugs/issue39693.go2 new file mode 100644 index 00000000000..316ab1982e8 --- /dev/null +++ b/src/go/types/fixedbugs/issue39693.go2 @@ -0,0 +1,14 @@ +// Copyright 2020 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 + +type Number interface { + int /* ERROR int is not an interface */ + float64 /* ERROR float64 is not an interface */ +} + +func Add[T Number](a, b T) T { + return a /* ERROR not defined */ + b +} diff --git a/src/go/types/fixedbugs/issue39699.go2 b/src/go/types/fixedbugs/issue39699.go2 new file mode 100644 index 00000000000..75491e7e26f --- /dev/null +++ b/src/go/types/fixedbugs/issue39699.go2 @@ -0,0 +1,29 @@ +// Copyright 2020 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 + +type T0 interface{ +} + +type T1 interface{ + type int +} + +type T2 interface{ + comparable +} + +type T3 interface { + T0 + T1 + T2 +} + +func _() { + _ = T0(0) + _ = T1 /* ERROR cannot use interface T1 in conversion */ (1) + _ = T2 /* ERROR cannot use interface T2 in conversion */ (2) + _ = T3 /* ERROR cannot use interface T3 in conversion */ (3) +} diff --git a/src/go/types/fixedbugs/issue39711.go2 b/src/go/types/fixedbugs/issue39711.go2 new file mode 100644 index 00000000000..df621a4c173 --- /dev/null +++ b/src/go/types/fixedbugs/issue39711.go2 @@ -0,0 +1,11 @@ +// Copyright 2020 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 + +// Do not report a duplicate type error for this type list. +// (Check types after interfaces have been completed.) +type _ interface { + type interface{ Error() string }, interface{ String() string } +} diff --git a/src/go/types/fixedbugs/issue39723.go2 b/src/go/types/fixedbugs/issue39723.go2 new file mode 100644 index 00000000000..55464e6b775 --- /dev/null +++ b/src/go/types/fixedbugs/issue39723.go2 @@ -0,0 +1,9 @@ +// Copyright 2020 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 + +// A constraint must be an interface; it cannot +// be a type parameter, for instance. +func _[A interface{ type interface{} }, B A /* ERROR not an interface */ ]() diff --git a/src/go/types/fixedbugs/issue39725.go2 b/src/go/types/fixedbugs/issue39725.go2 new file mode 100644 index 00000000000..e19b6770bfe --- /dev/null +++ b/src/go/types/fixedbugs/issue39725.go2 @@ -0,0 +1,16 @@ +// Copyright 2020 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 + +func f1[T1, T2 any](T1, T2, struct{a T1; b T2}) +func _() { + f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{}) +} + +// simplified test case from issue +func f2[T any](_ []T, _ func(T)) +func _() { + f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {}) +} diff --git a/src/go/types/fixedbugs/issue39754.go2 b/src/go/types/fixedbugs/issue39754.go2 new file mode 100644 index 00000000000..2ed84dc8abe --- /dev/null +++ b/src/go/types/fixedbugs/issue39754.go2 @@ -0,0 +1,20 @@ +// Copyright 2020 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 + +type Optional[T any] struct {} + +func (_ Optional[T]) Val() (T, bool) + +type Box[T any] interface { + Val() (T, bool) +} + +func f[V interface{}, A, B Box[V]]() {} + +func _() { + f[int, Optional[int], Optional[int]]() + // f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]() +} diff --git a/src/go/types/fixedbugs/issue39755.go2 b/src/go/types/fixedbugs/issue39755.go2 new file mode 100644 index 00000000000..b7ab68818e9 --- /dev/null +++ b/src/go/types/fixedbugs/issue39755.go2 @@ -0,0 +1,23 @@ +// Copyright 2020 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 + +func _[T interface{type map[string]int}](x T) { + _ = x == nil +} + +// simplified test case from issue + +type PathParamsConstraint interface { + type map[string]string, []struct{key, value string} +} + +type PathParams[T PathParamsConstraint] struct { + t T +} + +func (pp *PathParams[T]) IsNil() bool { + return pp.t == nil // this must succeed +} diff --git a/src/go/types/fixedbugs/issue39768.go2 b/src/go/types/fixedbugs/issue39768.go2 new file mode 100644 index 00000000000..abac141d7f0 --- /dev/null +++ b/src/go/types/fixedbugs/issue39768.go2 @@ -0,0 +1,20 @@ +// Copyright 2020 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 + +type T[P any] P +type A = T +var x A[int] +var _ A /* ERROR cannot use generic type */ + +type B = T[int] +var y B = x +var _ B /* ERROR not a generic type */ [int] + +// test case from issue + +type Vector[T any] []T +type VectorAlias = Vector +var v Vector[int] diff --git a/src/go/types/fixedbugs/issue39938.go2 b/src/go/types/fixedbugs/issue39938.go2 new file mode 100644 index 00000000000..76e7e369ca1 --- /dev/null +++ b/src/go/types/fixedbugs/issue39938.go2 @@ -0,0 +1,50 @@ +// Copyright 2020 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. + +// Check "infinite expansion" cycle errors across instantiated types. + +package p + +type E0[P any] P +type E1[P any] *P +type E2[P any] struct{ P } +type E3[P any] struct{ *P } + +type T0 /* ERROR illegal cycle */ struct { + _ E0[T0] +} + +type T0_ /* ERROR illegal cycle */ struct { + E0[T0_] +} + +type T1 struct { + _ E1[T1] +} + +type T2 /* ERROR illegal cycle */ struct { + _ E2[T2] +} + +type T3 struct { + _ E3[T3] +} + +// some more complex cases + +type T4 /* ERROR illegal cycle */ struct { + _ E0[E2[T4]] +} + +type T5 struct { + _ E0[E2[E0[E1[E2[[10]T5]]]]] +} + +type T6 /* ERROR illegal cycle */ struct { + _ E0[[10]E2[E0[E2[E2[T6]]]]] +} + +type T7 struct { + _ E0[[]E2[E0[E2[E2[T6]]]]] +} diff --git a/src/go/types/fixedbugs/issue39948.go2 b/src/go/types/fixedbugs/issue39948.go2 new file mode 100644 index 00000000000..c2b460902cc --- /dev/null +++ b/src/go/types/fixedbugs/issue39948.go2 @@ -0,0 +1,9 @@ +// Copyright 2020 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 + +type T[P any] interface{ + P // ERROR P is a type parameter, not an interface +} diff --git a/src/go/types/fixedbugs/issue39976.go2 b/src/go/types/fixedbugs/issue39976.go2 new file mode 100644 index 00000000000..3db4eae0123 --- /dev/null +++ b/src/go/types/fixedbugs/issue39976.go2 @@ -0,0 +1,16 @@ +// Copyright 2020 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 + +type policy[K, V any] interface{} +type LRU[K, V any] struct{} + +func NewCache[K, V any](p policy[K, V]) + +func _() { + var lru LRU[int, string] + NewCache[int, string](&lru) + NewCache(& /* ERROR does not match policy\[K, V\] \(cannot infer K and V\) */ lru) +} diff --git a/src/go/types/fixedbugs/issue39982.go2 b/src/go/types/fixedbugs/issue39982.go2 new file mode 100644 index 00000000000..9810b6386a9 --- /dev/null +++ b/src/go/types/fixedbugs/issue39982.go2 @@ -0,0 +1,36 @@ +// Copyright 2020 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 + +type ( + T[_ any] struct{} + S[_ any] struct { + data T[*T[int]] + } +) + +func _() { + _ = S[int]{ + data: T[*T[int]]{}, + } +} + +// full test case from issue + +type ( + Element[TElem any] struct{} + + entry[K comparable] struct{} + + Cache[K comparable] struct { + data map[K]*Element[*entry[K]] + } +) + +func _() { + _ = Cache[int]{ + data: make(map[int](*Element[*entry[int]])), + } +} diff --git a/src/go/types/fixedbugs/issue40038.go2 b/src/go/types/fixedbugs/issue40038.go2 new file mode 100644 index 00000000000..8948d61caa4 --- /dev/null +++ b/src/go/types/fixedbugs/issue40038.go2 @@ -0,0 +1,15 @@ +// Copyright 2020 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 + +type A[T any] int + +func (A[T]) m(A[T]) + +func f[P interface{m(P)}]() + +func _() { + _ = f[A[int]] +} \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue40056.go2 b/src/go/types/fixedbugs/issue40056.go2 new file mode 100644 index 00000000000..71074be67e2 --- /dev/null +++ b/src/go/types/fixedbugs/issue40056.go2 @@ -0,0 +1,15 @@ +// Copyright 2020 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 + +func _() { + NewS() /* ERROR cannot infer T */ .M() +} + +type S struct {} + +func NewS[T any]() *S + +func (_ *S /* ERROR S is not a generic type */ [T]) M() \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue40057.go2 b/src/go/types/fixedbugs/issue40057.go2 new file mode 100644 index 00000000000..fdc8fb1c00a --- /dev/null +++ b/src/go/types/fixedbugs/issue40057.go2 @@ -0,0 +1,17 @@ +// Copyright 2020 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 + +func _() { + var x interface{} + switch t := x.(type) { + case S /* ERROR cannot use generic type */ : + t.m() + } +} + +type S[T any] struct {} + +func (_ S[T]) m() diff --git a/src/go/types/fixedbugs/issue40301.go2 b/src/go/types/fixedbugs/issue40301.go2 new file mode 100644 index 00000000000..5d97855f8a1 --- /dev/null +++ b/src/go/types/fixedbugs/issue40301.go2 @@ -0,0 +1,12 @@ +// Copyright 2020 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 + +import "unsafe" + +func _[T any](x T) { + _ = unsafe /* ERROR undefined */ .Alignof(x) + _ = unsafe /* ERROR undefined */ .Sizeof(x) +} diff --git a/src/go/types/fixedbugs/issue40684.go2 b/src/go/types/fixedbugs/issue40684.go2 new file mode 100644 index 00000000000..0269c3a62ce --- /dev/null +++ b/src/go/types/fixedbugs/issue40684.go2 @@ -0,0 +1,15 @@ +// Copyright 2020 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 + +type T[_ any] int + +func f[_ any]() +func g[_, _ any]() + +func _() { + _ = f[T /* ERROR without instantiation */ ] + _ = g[T /* ERROR without instantiation */ , T /* ERROR without instantiation */ ] +} \ No newline at end of file diff --git a/src/go/types/fixedbugs/issue41124.go2 b/src/go/types/fixedbugs/issue41124.go2 new file mode 100644 index 00000000000..61f766bcbd7 --- /dev/null +++ b/src/go/types/fixedbugs/issue41124.go2 @@ -0,0 +1,91 @@ +// Copyright 2020 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 + +// Test case from issue. + +type Nat interface { + type Zero, Succ +} + +type Zero struct{} +type Succ struct{ + Nat // ERROR interface contains type constraints +} + +// Struct tests. + +type I1 interface { + comparable +} + +type I2 interface { + type int +} + +type I3 interface { + I1 + I2 +} + +type _ struct { + f I1 // ERROR interface is .* comparable +} + +type _ struct { + comparable // ERROR interface is .* comparable +} + +type _ struct{ + I1 // ERROR interface is .* comparable +} + +type _ struct{ + I2 // ERROR interface contains type constraints +} + +type _ struct{ + I3 // ERROR interface contains type constraints +} + +// General composite types. + +type ( + _ [10]I1 // ERROR interface is .* comparable + _ [10]I2 // ERROR interface contains type constraints + + _ []I1 // ERROR interface is .* comparable + _ []I2 // ERROR interface contains type constraints + + _ *I3 // ERROR interface contains type constraints + _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints + _ chan I3 // ERROR interface contains type constraints + _ func(I1 /* ERROR interface is .* comparable */ ) + _ func() I2 // ERROR interface contains type constraints +) + +// Other cases. + +var _ = [...]I3 /* ERROR interface contains type constraints */ {} + +func _(x interface{}) { + _ = x.(I3 /* ERROR interface contains type constraints */ ) +} + +type T1[_ any] struct{} +type T3[_, _, _ any] struct{} +var _ T1[I2 /* ERROR interface contains type constraints */ ] +var _ T3[int, I2 /* ERROR interface contains type constraints */ , float32] + +func f1[_ any]() int +var _ = f1[I2 /* ERROR interface contains type constraints */ ]() +func f3[_, _, _ any]() int +var _ = f3[int, I2 /* ERROR interface contains type constraints */ , float32]() + +func _(x interface{}) { + switch x.(type) { + case I2 /* ERROR interface contains type constraints */ : + } +} diff --git a/src/go/types/fixedbugs/issue42758.go2 b/src/go/types/fixedbugs/issue42758.go2 new file mode 100644 index 00000000000..698cb8a16ba --- /dev/null +++ b/src/go/types/fixedbugs/issue42758.go2 @@ -0,0 +1,33 @@ +// Copyright 2020 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 + +func _[T any](x interface{}){ + switch x.(type) { + case T: // ok to use a type parameter + case int: + } + + switch x.(type) { + case T: + case T /* ERROR duplicate case */ : + } +} + +type constraint interface { + type int +} + +func _[T constraint](x interface{}){ + switch x.(type) { + case T: // ok to use a type parameter even if type list contains int + case int: + } +} + +func _(x constraint /* ERROR contains type constraints */ ) { + switch x /* ERROR contains type constraints */ .(type) { + } +} diff --git a/src/go/types/infer.go b/src/go/types/infer.go index c0b1a4b71a5..95bd3cb378d 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -39,7 +39,7 @@ func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) } } if allFailed { - check.errorf(arg, 0, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams)) + check.errorf(arg, _Todo, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams)) return } } @@ -47,7 +47,7 @@ func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) // TODO(rFindley): pass a positioner here, rather than arg.Pos(). inferred := check.subst(arg.Pos(), tpar, smap) if inferred != tpar { - check.errorf(arg, 0, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar) + check.errorf(arg, _Todo, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar) } else { check.errorf(arg, 0, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar) } diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 9cd13987beb..639ed121175 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -400,9 +400,12 @@ func (check *Checker) collectObjects() { } } else { // method - if d.decl.Type.TParams != nil { - check.invalidAST(d.decl.Type.TParams, "method must have no type parameters") - } + + // TODO(rFindley) earlier versions of this code checked that methods + // have no type parameters, but this is checked later + // when type checking the function type. Confirm that + // we don't need to check tparams here. + ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false) // (Methods with invalid receiver cannot be associated to a type, and // methods with blank _ names are never found; no need to collect any @@ -496,7 +499,7 @@ L: // unpack receiver type case nil: check.invalidAST(ptyp, "parameterized receiver contains nil parameters") default: - check.errorf(arg, 0, "receiver type parameter %s must be an identifier", arg) + check.errorf(arg, _Todo, "receiver type parameter %s must be an identifier", arg) } if par == nil { par = &ast.Ident{NamePos: arg.Pos(), Name: "_"} diff --git a/src/go/types/subst.go b/src/go/types/subst.go index ca9462dfda3..ed274885034 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -109,7 +109,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message - check.errorf(atPos(pos), 0, "got %d arguments but %d type parameters", len(targs), len(tparams)) + check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams)) return Typ[Invalid] } @@ -163,7 +163,8 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist } else if wrong != nil { // TODO(gri) This can still report uninstantiated types which makes the error message // more difficult to read then necessary. - check.softErrorf(atPos(pos), 0, + // TODO(rFindley) should this use parentheses rather than ':' for qualification? + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s", targ, tpar.bound, wrong, m, ) @@ -184,7 +185,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist if targ := asTypeParam(targ); targ != nil { targBound := targ.Bound() if targBound.allTypes == nil { - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ) break } for _, t := range unpackType(targBound.allTypes) { @@ -199,7 +200,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any. if !iface.isSatisfiedBy(targ) { - check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes) + check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes) break } } diff --git a/src/go/types/testdata/builtins.go2 b/src/go/types/testdata/builtins.go2 new file mode 100644 index 00000000000..3918d836b52 --- /dev/null +++ b/src/go/types/testdata/builtins.go2 @@ -0,0 +1,53 @@ +// Copyright 2020 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. + +// This file tests built-in calls on generic types. + +package builtins + +type Bmc interface { + type map[rune]string, chan int +} + +type Bms interface { + type map[string]int, []int +} + +type Bcs interface { + type chan bool, []float64 +} + +type Bss interface { + type []int, []string +} + +func _[T any] () { + _ = make(T /* ERROR invalid argument */ ) + _ = make(T /* ERROR invalid argument */ , 10) + _ = make(T /* ERROR invalid argument */ , 10, 20) +} + +func _[T Bmc] () { + _ = make(T) + _ = make(T, 10) + _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20) +} + +func _[T Bms] () { + _ = make /* ERROR expects 2 arguments */ (T) + _ = make(T, 10) + _ = make /* ERROR expects 2 arguments */ (T, 10, 20) +} + +func _[T Bcs] () { + _ = make /* ERROR expects 2 arguments */ (T) + _ = make(T, 10) + _ = make /* ERROR expects 2 arguments */ (T, 10, 20) +} + +func _[T Bss] () { + _ = make /* ERROR expects 2 or 3 arguments */ (T) + _ = make(T, 10) + _ = make(T, 10, 20) +} diff --git a/src/go/types/testdata/chans.go2 b/src/go/types/testdata/chans.go2 new file mode 100644 index 00000000000..fad2bcec9d0 --- /dev/null +++ b/src/go/types/testdata/chans.go2 @@ -0,0 +1,62 @@ +package chans + +import "runtime" + +// Ranger returns a Sender and a Receiver. The Receiver provides a +// Next method to retrieve values. The Sender provides a Send method +// to send values and a Close method to stop sending values. The Next +// method indicates when the Sender has been closed, and the Send +// method indicates when the Receiver has been freed. +// +// This is a convenient way to exit a goroutine sending values when +// the receiver stops reading them. +func Ranger[T any]() (*Sender[T], *Receiver[T]) { + c := make(chan T) + d := make(chan bool) + s := &Sender[T]{values: c, done: d} + r := &Receiver[T]{values: c, done: d} + runtime.SetFinalizer(r, r.finalize) + return s, r +} + +// A sender is used to send values to a Receiver. +type Sender[T any] struct { + values chan<- T + done <-chan bool +} + +// Send sends a value to the receiver. It returns whether any more +// values may be sent; if it returns false the value was not sent. +func (s *Sender[T]) Send(v T) bool { + select { + case s.values <- v: + return true + case <-s.done: + return false + } +} + +// Close tells the receiver that no more values will arrive. +// After Close is called, the Sender may no longer be used. +func (s *Sender[T]) Close() { + close(s.values) +} + +// A Receiver receives values from a Sender. +type Receiver[T any] struct { + values <-chan T + done chan<- bool +} + +// Next returns the next value from the channel. The bool result +// indicates whether the value is valid, or whether the Sender has +// been closed and no more values will be received. +func (r *Receiver[T]) Next() (T, bool) { + v, ok := <-r.values + return v, ok +} + +// finalize is a finalizer for the receiver. +func (r *Receiver[T]) finalize() { + close(r.done) +} diff --git a/src/go/types/testdata/issues.go2 b/src/go/types/testdata/issues.go2 new file mode 100644 index 00000000000..ac2dee36cbe --- /dev/null +++ b/src/go/types/testdata/issues.go2 @@ -0,0 +1,255 @@ +// Copyright 2020 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. + +// This file contains regression tests for bugs found. + +package p + +import "io" +import "context" + +// Interfaces are always comparable (though the comparison may panic at runtime). +func eql[T comparable](x, y T) bool { + return x == y +} + +func _() { + var x interface{} + var y interface{ m() } + eql(x, y /* ERROR does not match */ ) // interfaces of different types + eql(x, x) + eql(y, y) + eql(y, nil) + eql(io.Reader)(nil, nil) +} + +// If we have a receiver of pointer type (below: *T) we must ignore +// the pointer in the implementation of the method lookup because +// the type bound of T is an interface an pointer to interface types +// have no methods and then the lookup would fail. +type C[T any] interface { + m() +} + +// using type bound C +func _[T C[T]](x *T) { + x.m() +} + +// using an interface literal as bound +func _[T interface{ m() }](x *T) { + x.m() +} + +// In a generic function body all method calls will be pointer method calls. +// If necessary, the function body will insert temporary variables, not seen +// by the user, in order to get an addressable variable to use to call the method. +// Thus, assume an argument type for a generic function to be the type of addressable +// values in the generic function when checking if the argument type satisfies the +// generic function's type bound. +func f2[_ interface{ m1(); m2() }]() + +type T struct{} +func (T) m1() +func (*T) m2() + +func _() { + f2(T /* ERROR wrong method signature */ )() + f2(*T)() +} + +// When a type parameter is used as an argument to instantiate a parameterized +// type with a type list constraint, all of the type argument's types in its +// bound, but at least one (!), must be in the type list of the bound of the +// corresponding parameterized type's type parameter. +type T1[P interface{type uint}] struct{} + +func _[P any]() { + _ = T1[P /* ERROR P has no type constraints */ ]{} +} + +// This is the original (simplified) program causing the same issue. +type Unsigned interface { + type uint +} + +type T2[U Unsigned] struct { + s U +} + +func (u T2[U]) Add1() U { + return u.s + 1 +} + +func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { + return T2[U /* ERROR U has no type constraints */ ]{} +} + +func _() { + u := NewT2[string]() + _ = u.Add1() +} + +// When we encounter an instantiated type such as Elem[T] we must +// not "expand" the instantiation when the type to be instantiated +// (Elem in this case) is not yet fully set up. +type Elem[T any] struct { + next *Elem[T] + list *List[T] +} + +type List[T any] struct { + root Elem[T] +} + +func (l *List[T]) Init() { + l.root.next = &l.root +} + +// This is the original program causing the same issue. +type Element2[TElem any] struct { + next, prev *Element2[TElem] + list *List2[TElem] + Value TElem +} + +type List2[TElem any] struct { + root Element2[TElem] + len int +} + +func (l *List2[TElem]) Init() *List2[TElem] { + l.root.next = &l.root + l.root.prev = &l.root + l.len = 0 + return l +} + +// Self-recursive instantiations must work correctly. +type A[P any] struct { _ *A[P] } + +type AB[P any] struct { _ *BA[P] } +type BA[P any] struct { _ *AB[P] } + +// And a variation that also caused a problem with an +// unresolved underlying type. +type Element3[TElem any] struct { + next, prev *Element3[TElem] + list *List3[TElem] + Value TElem +} + +func (e *Element3[TElem]) Next() *Element3[TElem] { + if p := e.next; e.list != nil && p != &e.list.root { + return p + } + return nil +} + +type List3[TElem any] struct { + root Element3[TElem] + len int +} + +// Infinite generic type declarations must lead to an error. +type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] } +type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] } + +// The implementation of conversions T(x) between integers and floating-point +// numbers checks that both T and x have either integer or floating-point +// type. When the type of T or x is a type parameter, the respective simple +// predicate disjunction in the implementation was wrong because if a type list +// contains both an integer and a floating-point type, the type parameter is +// neither an integer or a floating-point number. +func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 { + return T2(v) +} + +func _() { + convert[int, uint](5) +} + +// When testing binary operators, for +, the operand types must either be +// both numeric, or both strings. The implementation had the same problem +// with this check as the conversion issue above (issue #39623). + +func issue39623[T interface{type int, string}](x, y T) T { + return x + y +} + +// Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI: +func Sum[T interface{type int, string}](s []T) (sum T) { + for _, v := range s { + sum += v + } + return +} + +// Assignability of an unnamed pointer type to a type parameter that +// has a matching underlying type. +func _[T interface{}, PT interface{type *T}] (x T) PT { + return &x +} + +// Indexing of generic types containing type parameters in their type list: +func at[T interface{ type []E }, E interface{}](x T, i int) E { + return x[i] +} + +// A generic type inside a function acts like a named type. Its underlying +// type is itself, its "operational type" is defined by the type list in +// the tybe bound, if any. +func _[T interface{type int}](x T) { + type myint int + var _ int = int(x) + var _ T = 42 + var _ T = T(myint(42)) +} + +// Indexing a generic type with an array type bound checks length. +// (Example by mdempsky@.) +func _[T interface { type [10]int }](x T) { + _ = x[9] // ok + _ = x[20 /* ERROR out of bounds */ ] +} + +// Pointer indirection of a generic type. +func _[T interface{ type *int }](p T) int { + return *p +} + +// Channel sends and receives on generic types. +func _[T interface{ type chan int }](ch T) int { + ch <- 0 + return <- ch +} + +// Calling of a generic variable. +func _[T interface{ type func() }](f T) { + f() + go f() +} + +// We must compare against the underlying type of type list entries +// when checking if a constraint is satisfied by a type. The under- +// lying type of each type list entry must be computed after the +// interface has been instantiated as its typelist may contain a +// type parameter that was substituted with a defined type. +// Test case from an (originally) failing example. + +type sliceOf[E any] interface{ type []E } + +func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S + +var f func() +var cancelSlice []context.CancelFunc +var _ = append(context.CancelFunc, []context.CancelFunc, context.CancelFunc)(cancelSlice, f) + +// A generic function must be instantiated with a type, not a value. + +func g[T any](T) T + +var _ = g[int] +var _ = g[nil /* ERROR is not a type */ ] +var _ = g(0) diff --git a/src/go/types/testdata/linalg.go2 b/src/go/types/testdata/linalg.go2 new file mode 100644 index 00000000000..0d27603a583 --- /dev/null +++ b/src/go/types/testdata/linalg.go2 @@ -0,0 +1,83 @@ +// Copyright 2019 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 linalg + +import "math" + +// Numeric is type bound that matches any numeric type. +// It would likely be in a constraints package in the standard library. +type Numeric interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64, + complex64, complex128 +} + +func DotProduct[T Numeric](s1, s2 []T) T { + if len(s1) != len(s2) { + panic("DotProduct: slices of unequal length") + } + var r T + for i := range s1 { + r += s1[i] * s2[i] + } + return r +} + +// NumericAbs matches numeric types with an Abs method. +type NumericAbs[T any] interface { + Numeric + + Abs() T +} + +// AbsDifference computes the absolute value of the difference of +// a and b, where the absolute value is determined by the Abs method. +func AbsDifference[T NumericAbs[T]](a, b T) T { + d := a - b + return d.Abs() +} + +// OrderedNumeric is a type bound that matches numeric types that support the < operator. +type OrderedNumeric interface { + type int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, uintptr, + float32, float64 +} + +// Complex is a type bound that matches the two complex types, which do not have a < operator. +type Complex interface { + type complex64, complex128 +} + +// OrderedAbs is a helper type that defines an Abs method for +// ordered numeric types. +type OrderedAbs[T OrderedNumeric] T + +func (a OrderedAbs[T]) Abs() OrderedAbs[T] { + if a < 0 { + return -a + } + return a +} + +// ComplexAbs is a helper type that defines an Abs method for +// complex types. +type ComplexAbs[T Complex] T + +func (a ComplexAbs[T]) Abs() ComplexAbs[T] { + r := float64(real(a)) + i := float64(imag(a)) + d := math.Sqrt(r * r + i * i) + return ComplexAbs[T](complex(d, 0)) +} + +func OrderedAbsDifference[T OrderedNumeric](a, b T) T { + return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b))) +} + +func ComplexAbsDifference[T Complex](a, b T) T { + return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b))) +} diff --git a/src/go/types/testdata/map.go2 b/src/go/types/testdata/map.go2 new file mode 100644 index 00000000000..814d9539fdc --- /dev/null +++ b/src/go/types/testdata/map.go2 @@ -0,0 +1,113 @@ +// Copyright 2019 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 orderedmap provides an ordered map, implemented as a binary tree. +package orderedmap + +// TODO(gri) fix imports for tests +import "chans" // ERROR could not import + +// Map is an ordered map. +type Map[K, V any] struct { + root *node[K, V] + compare func(K, K) int +} + +// node is the type of a node in the binary tree. +type node[K, V any] struct { + key K + val V + left, right *node[K, V] +} + +// New returns a new map. +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} +} + +// find looks up key in the map, and returns either a pointer +// to the node holding key, or a pointer to the location where +// such a node would go. +func (m *Map[K, V]) find(key K) **node[K, V] { + pn := &m.root + for *pn != nil { + switch cmp := m.compare(key, (*pn).key); { + case cmp < 0: + pn = &(*pn).left + case cmp > 0: + pn = &(*pn).right + default: + return pn + } + } + return pn +} + +// Insert inserts a new key/value into the map. +// If the key is already present, the value is replaced. +// Returns true if this is a new key, false if already present. +func (m *Map[K, V]) Insert(key K, val V) bool { + pn := m.find(key) + if *pn != nil { + (*pn).val = val + return false + } + *pn = &node[K, V]{key: key, val: val} + return true +} + +// Find returns the value associated with a key, or zero if not present. +// The found result reports whether the key was found. +func (m *Map[K, V]) Find(key K) (V, bool) { + pn := m.find(key) + if *pn == nil { + var zero V // see the discussion of zero values, above + return zero, false + } + return (*pn).val, true +} + +// keyValue is a pair of key and value used when iterating. +type keyValue[K, V any] struct { + key K + val V +} + +// InOrder returns an iterator that does an in-order traversal of the map. +func (m *Map[K, V]) InOrder() *Iterator[K, V] { + sender, receiver := chans.Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { + if n == nil { + return true + } + // Stop sending values if sender.Send returns false, + // meaning that nothing is listening at the receiver end. + return f(n.left) && + sender.Send(keyValue[K, V]{n.key, n.val}) && + f(n.right) + } + go func() { + f(m.root) + sender.Close() + }() + return &Iterator[K, V]{receiver} +} + +// Iterator is used to iterate over the map. +type Iterator[K, V any] struct { + r *chans.Receiver[keyValue[K, V]] +} + +// Next returns the next key and value pair, and a boolean indicating +// whether they are valid or whether we have reached the end. +func (it *Iterator[K, V]) Next() (K, V, bool) { + keyval, ok := it.r.Next() + if !ok { + var zerok K + var zerov V + return zerok, zerov, false + } + return keyval.key, keyval.val, true +} diff --git a/src/go/types/testdata/map2.go2 b/src/go/types/testdata/map2.go2 new file mode 100644 index 00000000000..2833445662d --- /dev/null +++ b/src/go/types/testdata/map2.go2 @@ -0,0 +1,146 @@ +// Copyright 2019 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. + +// This file is like map.go2, but instead if importing chans, it contains +// the necessary functionality at the end of the file. + +// Package orderedmap provides an ordered map, implemented as a binary tree. +package orderedmap + +// Map is an ordered map. +type Map[K, V any] struct { + root *node[K, V] + compare func(K, K) int +} + +// node is the type of a node in the binary tree. +type node[K, V any] struct { + key K + val V + left, right *node[K, V] +} + +// New returns a new map. +func New[K, V any](compare func(K, K) int) *Map[K, V] { + return &Map[K, V]{compare: compare} +} + +// find looks up key in the map, and returns either a pointer +// to the node holding key, or a pointer to the location where +// such a node would go. +func (m *Map[K, V]) find(key K) **node[K, V] { + pn := &m.root + for *pn != nil { + switch cmp := m.compare(key, (*pn).key); { + case cmp < 0: + pn = &(*pn).left + case cmp > 0: + pn = &(*pn).right + default: + return pn + } + } + return pn +} + +// Insert inserts a new key/value into the map. +// If the key is already present, the value is replaced. +// Returns true if this is a new key, false if already present. +func (m *Map[K, V]) Insert(key K, val V) bool { + pn := m.find(key) + if *pn != nil { + (*pn).val = val + return false + } + *pn = &node[K, V]{key: key, val: val} + return true +} + +// Find returns the value associated with a key, or zero if not present. +// The found result reports whether the key was found. +func (m *Map[K, V]) Find(key K) (V, bool) { + pn := m.find(key) + if *pn == nil { + var zero V // see the discussion of zero values, above + return zero, false + } + return (*pn).val, true +} + +// keyValue is a pair of key and value used when iterating. +type keyValue[K, V any] struct { + key K + val V +} + +// InOrder returns an iterator that does an in-order traversal of the map. +func (m *Map[K, V]) InOrder() *Iterator[K, V] { + sender, receiver := chans_Ranger[keyValue[K, V]]() + var f func(*node[K, V]) bool + f = func(n *node[K, V]) bool { + if n == nil { + return true + } + // Stop sending values if sender.Send returns false, + // meaning that nothing is listening at the receiver end. + return f(n.left) && + sender.Send(keyValue[K, V]{n.key, n.val}) && + f(n.right) + } + go func() { + f(m.root) + sender.Close() + }() + return &Iterator[K, V]{receiver} +} + +// Iterator is used to iterate over the map. +type Iterator[K, V any] struct { + r *chans_Receiver[keyValue[K, V]] +} + +// Next returns the next key and value pair, and a boolean indicating +// whether they are valid or whether we have reached the end. +func (it *Iterator[K, V]) Next() (K, V, bool) { + keyval, ok := it.r.Next() + if !ok { + var zerok K + var zerov V + return zerok, zerov, false + } + return keyval.key, keyval.val, true +} + +// chans + +func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T]) + +// A sender is used to send values to a Receiver. +type chans_Sender[T any] struct { + values chan<- T + done <-chan bool +} + +func (s *chans_Sender[T]) Send(v T) bool { + select { + case s.values <- v: + return true + case <-s.done: + return false + } +} + +func (s *chans_Sender[T]) Close() { + close(s.values) +} + +type chans_Receiver[T any] struct { + values <-chan T + done chan<- bool +} + +func (r *chans_Receiver[T]) Next() (T, bool) { + v, ok := <-r.values + return v, ok +} \ No newline at end of file diff --git a/src/go/types/testdata/slices.go2 b/src/go/types/testdata/slices.go2 new file mode 100644 index 00000000000..2bacd1c2aa8 --- /dev/null +++ b/src/go/types/testdata/slices.go2 @@ -0,0 +1,68 @@ +// Copyright 2019 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 slices implements various slice algorithms. +package slices + +// Map turns a []T1 to a []T2 using a mapping function. +func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 { + r := make([]T2, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +// Reduce reduces a []T1 to a single value using a reduction function. +func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r +} + +// Filter filters values from a slice using a filter function. +func Filter[T any](s []T, f func(T) bool) []T { + var r []T + for _, v := range s { + if f(v) { + r = append(r, v) + } + } + return r +} + +// Example uses + +func limiter(x int) byte { + switch { + case x < 0: + return 0 + default: + return byte(x) + case x > 255: + return 255 + } +} + +var input = []int{-4, 68954, 7, 44, 0, -555, 6945} +var limited1 = Map[int, byte](input, limiter) +var limited2 = Map(input, limiter) // using type inference + +func reducer(x float64, y int) float64 { + return x + float64(y) +} + +var reduced1 = Reduce[int, float64](input, 0, reducer) +var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference +var reduced3 = Reduce(input, 1, reducer) // using type inference + +func filter(x int) bool { + return x&1 != 0 +} + +var filtered1 = Filter[int](input, filter) +var filtered2 = Filter(input, filter) // using type inference + diff --git a/src/go/types/testdata/tinference.go2 b/src/go/types/testdata/tinference.go2 new file mode 100644 index 00000000000..31338b33ad6 --- /dev/null +++ b/src/go/types/testdata/tinference.go2 @@ -0,0 +1,108 @@ +// Copyright 2020 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 tinferenceB + +import "strconv" + +type any interface{} + +// TODO(rFindley) the below partially applied function types should probably +// not be permitted (spec question). + +func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D) +func _() { + f := f0[string] + f("a", "b", "c", "d") + f0("a", "b", "c", "d") +} + +func f1[A any, B interface{type A}](A, B) +func _() { + f := f1[int] + f(int(0), int(0)) + f1(int(0), int(0)) +} + +func f2[A any, B interface{type []A}](A, B) +func _() { + f := f2[byte] + f(byte(0), []byte{}) + f2(byte(0), []byte{}) +} + +func f3[A any, B interface{type C}, C interface{type *A}](A, B, C) +func _() { + f := f3[int] + var x int + f(x, &x, &x) + f3(x, &x, &x) +} + +func f4[A any, B interface{type []C}, C interface{type *A}](A, B, C) +func _() { + f := f4[int] + var x int + f(x, []*int{}, &x) + f4(x, []*int{}, &x) +} + +func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A +func _() { + x := f5(1.2) + var _ float64 = x.b + var _ float64 = *x.c +} + +func f6[A any, B interface{type struct{f []A}}](B) A +func _() { + x := f6(struct{f []string}{}) + var _ string = x +} + +// TODO(gri) Need to flag invalid recursive constraints. At the +// moment these cause infinite recursions and stack overflow. +// func f7[A interface{type B}, B interface{type A}]() + +// More realistic examples + +func Double[S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S { + r := make(S, len(s)) + for i, v := range s { + r[i] = v + v + } + return r +} + +type MySlice []int + +var _ = Double(MySlice{1}) + +// From the draft design. + +type Setter[B any] interface { + Set(string) + type *B +} + +func FromStrings[T interface{}, PT Setter[T]](s []string) []T { + result := make([]T, len(s)) + for i, v := range s { + // The type of &result[i] is *T which is in the type list + // of Setter2, so we can convert it to PT. + p := PT(&result[i]) + // PT has a Set method. + p.Set(v) + } + return result +} + +type Settable int + +func (p *Settable) Set(s string) { + i, _ := strconv.Atoi(s) // real code should not ignore the error + *p = Settable(i) +} + +var _ = FromStrings[Settable]([]string{"1", "2"}) diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 new file mode 100644 index 00000000000..dae78caff81 --- /dev/null +++ b/src/go/types/testdata/tmp.go2 @@ -0,0 +1,17 @@ +// Copyright 2020 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. + +// This file is meant as "dumping ground" for debugging code. + +package p + +// fun test case +type C[P interface{m()}] P + +func (r C[P]) m() { r.m() } + +func f[T interface{m(); n()}](x T) { + y := C[T](x) + y.m() +} diff --git a/src/go/types/testdata/todos.go2 b/src/go/types/testdata/todos.go2 new file mode 100644 index 00000000000..09e9b4c48a9 --- /dev/null +++ b/src/go/types/testdata/todos.go2 @@ -0,0 +1,22 @@ +// Copyright 2020 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. + +// This file is meant as "dumping ground" for tests +// of not yet implemented features. It will grow and +// shrink over time. + +package p + +// When using []'s instead of ()'s for type parameters +// we don't need extra parentheses for some composite +// literal types. +type T1[P any] struct{} +type T2[P, Q any] struct{} + +func _() { + _ = []T1[int]{} // ok if we use []'s + _ = [](T1[int]){} + _ = []T2[int, string]{} // ok if we use []'s + _ = [](T2[int, string]){} +} diff --git a/src/go/types/testdata/typeinst.go2 b/src/go/types/testdata/typeinst.go2 new file mode 100644 index 00000000000..3184a4b5b1c --- /dev/null +++ b/src/go/types/testdata/typeinst.go2 @@ -0,0 +1,59 @@ +// Copyright 2019 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 + +type myInt int + +// Parameterized type declarations + +type T1[P any] P + +type T2[P any] struct { + f P + g int // int should still be in scope chain +} + +type List[P any] []P + +// Alias type declarations cannot have type parameters. Syntax error. +type A1[P any] = /* ERROR cannot be alias */ P + +// But an alias may refer to a generic, uninstantiated type. +type A2 = List +var _ A2[int] +var _ A2 /* ERROR without instantiation */ + +type A3 = List[int] +var _ A3 + +// Parameterized type instantiations + +var x int +type _ x /* ERROR not a type */ [int] + +type _ int /* ERROR not a generic type */ [] +type _ myInt /* ERROR not a generic type */ [] + +// TODO(gri) better error messages +type _ T1 /* ERROR got 0 arguments but 1 type parameters */ [] +type _ T1[x /* ERROR not a type */ ] +type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32] + +var _ T2[int] = T2[int]{} + +var _ List[int] = []int{1, 2, 3} +var _ List[[]int] = [][]int{{1, 2, 3}} +var _ List[List[List[int]]] + +// Parameterized types containing parameterized types + +type T3[P any] List[P] + +var _ T3[int] = T3[int](List[int]{1, 2, 3}) + +// Self-recursive generic types are not permitted + +type self1[P any] self1 /* ERROR illegal cycle */ [P] +type self2[P any] *self2[P] // this is ok diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 new file mode 100644 index 00000000000..6e2104a5150 --- /dev/null +++ b/src/go/types/testdata/typeinst2.go2 @@ -0,0 +1,256 @@ +// Copyright 2019 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 + +type List[E any] []E +var _ List[List[List[int]]] +var _ List[List[List[int]]] = []List[List[int]]{} + +type ( + T1[P1 any] struct { + f1 T2[P1, float32] + } + + T2[P2, P3 any] struct { + f2 P2 + f3 P3 + } +) + +func _() { + var x1 T1[int] + var x2 T2[int, float32] + + x1.f1.f2 = 0 + x1.f1 = x2 +} + +type T3[P any] T1[T2[P, P]] + +func _() { + var x1 T3[int] + var x2 T2[int, int] + x1.f1.f2 = x2 +} + +func f[P any] (x P) List[P] { + return List[P]{x} +} + +var ( + _ []int = f(0) + _ []float32 = f[float32](10) + _ List[complex128] = f(1i) + _ []List[int] = f(List[int]{}) + _ List[List[int]] = []List[int]{} + _ = []List[int]{} +) + +// Parameterized types with methods + +func (l List[E]) Head() (_ E, _ bool) { + if len(l) > 0 { + return l[0], true + } + return +} + +// A test case for instantiating types with other types (extracted from map.go2) + +type Pair[K any] struct { + key K +} + +type Receiver[T any] struct { + values T +} + +type Iterator[K any] struct { + r Receiver[Pair[K]] +} + +func Values [T any] (r Receiver[T]) T { + return r.values +} + +func (it Iterator[K]) Next() K { + return Values[Pair[K]](it.r).key +} + +// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence) + +type NumericAbs[T any] interface { + Abs() T +} + +func AbsDifference[T NumericAbs[T]](x T) + +type OrderedAbs[T any] T + +func (a OrderedAbs[T]) Abs() OrderedAbs[T] + +func OrderedAbsDifference[T any](x T) { + AbsDifference(OrderedAbs[T](x)) +} + +// same code, reduced to essence + +func g[P interface{ m() P }](x P) + +type T4[P any] P + +func (_ T4[P]) m() T4[P] + +func _[Q any](x Q) { + g(T4[Q](x)) +} + +// Another test case that caused problems in the past + +type T5[_ interface { a() }, _ interface{}] struct{} + +type A[P any] struct{ x P } + +func (_ A[P]) a() {} + +var _ T5[A[int], int] + +// Invoking methods with parameterized receiver types uses +// type inference to determine the actual type arguments matching +// the receiver type parameters from the actual receiver argument. +// Go does implicit address-taking and dereferenciation depending +// on the actual receiver and the method's receiver type. To make +// type inference work, the type-checker matches "pointer-ness" +// of the actual receiver and the method's receiver type. +// The following code tests this mechanism. + +type R1[A any] struct{} +func (_ R1[A]) vm() +func (_ *R1[A]) pm() + +func _[T any](r R1[T], p *R1[T]) { + r.vm() + r.pm() + p.vm() + p.pm() +} + +type R2[A, B any] struct{} +func (_ R2[A, B]) vm() +func (_ *R2[A, B]) pm() + +func _[T any](r R2[T, int], p *R2[string, T]) { + r.vm() + r.pm() + p.vm() + p.pm() +} + +// An interface can (explicitly) declare at most one type list. +type _ interface { + m0() + type int, string, bool + type /* ERROR multiple type lists */ float32, float64 + m1() + m2() + type /* ERROR multiple type lists */ complex64, complex128 + type /* ERROR multiple type lists */ rune +} + +// Interface type lists may contain each type at most once. +// (If there are multiple lists, we assume the author intended +// for them to be all in a single list, and we report the error +// as well.) +type _ interface { + type int, int /* ERROR duplicate type int */ + type /* ERROR multiple type lists */ int /* ERROR duplicate type int */ +} + +type _ interface { + type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int} +} + +// Interface type lists can contain any type, incl. *Named types. +// Verify that we use the underlying type to compute the operational type. +type MyInt int +func add1[T interface{type MyInt}](x T) T { + return x + 1 +} + +type MyString string +func double[T interface{type MyInt, MyString}](x T) T { + return x + x +} + +// Embedding of interfaces with type lists leads to interfaces +// with type lists that are the intersection of the embedded +// type lists. + +type E0 interface { + type int, bool, string +} + +type E1 interface { + type int, float64, string +} + +type E2 interface { + type float64 +} + +type I0 interface { + E0 +} + +func f0[T I0]() +var _ = f0[int] +var _ = f0[bool] +var _ = f0[string] +var _ = f0[float64 /* ERROR does not satisfy I0 */ ] + +type I01 interface { + E0 + E1 +} + +func f01[T I01]() +var _ = f01[int] +var _ = f01[bool /* ERROR does not satisfy I0 */ ] +var _ = f01[string] +var _ = f01[float64 /* ERROR does not satisfy I0 */ ] + +type I012 interface { + E0 + E1 + E2 +} + +func f012[T I012]() +var _ = f012[int /* ERROR does not satisfy I012 */ ] +var _ = f012[bool /* ERROR does not satisfy I012 */ ] +var _ = f012[string /* ERROR does not satisfy I012 */ ] +var _ = f012[float64 /* ERROR does not satisfy I012 */ ] + +type I12 interface { + E1 + E2 +} + +func f12[T I12]() +var _ = f12[int /* ERROR does not satisfy I12 */ ] +var _ = f12[bool /* ERROR does not satisfy I12 */ ] +var _ = f12[string /* ERROR does not satisfy I12 */ ] +var _ = f12[float64] + +type I0_ interface { + E0 + type int +} + +func f0_[T I0_]() +var _ = f0_[int] +var _ = f0_[bool /* ERROR does not satisfy I0_ */ ] +var _ = f0_[string /* ERROR does not satisfy I0_ */ ] +var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ] diff --git a/src/go/types/testdata/typeparams.go2 b/src/go/types/testdata/typeparams.go2 new file mode 100644 index 00000000000..bdf6d560828 --- /dev/null +++ b/src/go/types/testdata/typeparams.go2 @@ -0,0 +1,458 @@ +// Copyright 2018 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 + +// import "io" // for type assertion tests + +// The predeclared identifier "any" is only visible as a constraint +// in a type parameter list. +var _ any // ERROR undeclared +func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) { + var _ any /* ERROR undeclared */ +} + +func identity[T any](x T) T { return x } + +func _[_ any](x int) int +func _[T any](T /* ERROR redeclared */ T)() +func _[T, T /* ERROR redeclared */ any]() + +func reverse[T any](list []T) []T { + rlist := make([]T, len(list)) + i := len(list) + for _, x := range list { + i-- + rlist[i] = x + } + return rlist +} + +var _ = reverse /* ERROR cannot use generic function reverse */ +var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3}) +var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3}) +var f = reverse[chan int] +var _ = f(0 /* ERROR cannot use 0 .* as \[\]chan int */ ) + +func swap[A, B any](a A, b B) (B, A) { return b, a } + +var _ = swap /* ERROR single value is expected */ [int, float32](1, 2) +var f32, i = swap[int, float32](swap(float32, int)(1, 2)) +var _ float32 = f32 +var _ int = i + +func swapswap[A, B any](a A, b B) (A, B) { + return swap[B, A](b, a) +} + +type F[A, B any] func(A, B) (B, A) + +func min[T interface{ type int }](x, y T) T { + if x < y { + return x + } + return y +} + +func _[T interface{type int, float32}](x, y T) bool { return x < y } +func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y } + +func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y } +func _[T C2[T]](x, y T) bool { return x < y } + +type C1[T any] interface{} +type C2[T any] interface{ type int, float32 } + +func new[T any]() *T { + var x T + return &x +} + +var _ = new /* ERROR cannot use generic function new */ +var _ *int = new[int]() + +func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable + +func f1[T1 any](struct{T1}) int +var _ = f1(int)(struct{T1}{}) +type T1 = int + +func f2[t1 any](struct{t1; x float32}) int +var _ = f2(t1)(struct{t1; x float32}{}) +type t1 = int + + +func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int + +var _ = f3[int, rune, bool](1, struct{x rune}{}, nil) + +// indexing + +func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type string }] (x T, i int) { _ = x[i] } +func _[T interface{ type []int }] (x T, i int) { _ = x[i] } +func _[T interface{ type [10]int, *[20]int, map[int]int }] (x T, i int) { _ = x[i] } +func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } +func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } + +// indexing with various combinations of map types in type lists (see issue #42616) +func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = x[i] } +func _[T interface{ type []E }, E any](x T, i int) { _ = &x[i] } +func _[T interface{ type map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted +func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ type []E, map[int]E, map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ type []E, map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } + +// slicing +// TODO(gri) implement this + +func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] } + +// len/cap built-ins + +func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) } +func _[T interface{ type string }](x T) { _ = len(x) } +func _[T interface{ type [10]int }](x T) { _ = len(x) } +func _[T interface{ type []byte }](x T) { _ = len(x) } +func _[T interface{ type map[int]int }](x T) { _ = len(x) } +func _[T interface{ type chan int }](x T) { _ = len(x) } +func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) } + +func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type [10]int }](x T) { _ = cap(x) } +func _[T interface{ type []byte }](x T) { _ = cap(x) } +func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) } +func _[T interface{ type chan int }](x T) { _ = cap(x) } +func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) } + +// range iteration + +func _[T interface{}](x T) { + for range x /* ERROR cannot range */ {} +} + +func _[T interface{ type string, []string }](x T) { + for range x {} + for i := range x { _ = i } + for i, _ := range x { _ = i } + for i, e := range x /* ERROR must have the same element type */ { _ = i } + for _, e := range x /* ERROR must have the same element type */ {} + var e rune + _ = e + for _, (e) = range x /* ERROR must have the same element type */ {} +} + + +func _[T interface{ type string, []rune, map[int]rune }](x T) { + for _, e := range x { _ = e } + for i, e := range x { _ = i; _ = e } +} + +func _[T interface{ type string, []rune, map[string]rune }](x T) { + for _, e := range x { _ = e } + for i, e := range x /* ERROR must have the same key type */ { _ = e } +} + +func _[T interface{ type string, chan int }](x T) { + for range x {} + for i := range x { _ = i } + for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value +} + +func _[T interface{ type string, chan<-int }](x T) { + for i := range x /* ERROR send-only channel */ { _ = i } +} + +// type inference checks + +var _ = new() /* ERROR cannot infer T */ + +func f4[A, B, C any](A, B) C + +var _ = f4(1, 2) /* ERROR cannot infer C */ +var _ = f4[int, float32, complex128](1, 2) + +func f5[A, B, C any](A, []*B, struct{f []C}) int + +var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{}) +var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer +var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{}) + +func f6[A any](A, []A) int + +var _ = f6(0, nil) + +func f6nil[A any](A) int + +var _ = f6nil(nil) // ERROR cannot infer + +// type inference with variadic functions + +func f7[T any](...T) T + +var _ int = f7() /* ERROR cannot infer T */ +var _ int = f7(1) +var _ int = f7(1, 2) +var _ int = f7([]int{}...) +var _ int = f7 /* ERROR cannot use */ ([]float64{}...) +var _ float64 = f7([]float64{}...) +var _ = f7[float64](1, 2.3) +var _ = f7(float64(1), 2.3) +var _ = f7(1, 2.3 /* ERROR does not match */ ) +var _ = f7(1.2, 3 /* ERROR does not match */ ) + +func f8[A, B any](A, B, ...B) int + +var _ = f8(1) /* ERROR not enough arguments */ +var _ = f8(1, 2.3) +var _ = f8(1, 2.3, 3.4, 4.5) +var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ ) +var _ = f8(int, float64)(1, 2.3, 3.4, 4) + +var _ = f8(int, float64)(0, 0, nil...) // test case for #18268 + +// init functions cannot have type parameters + +func init() {} +func init[/* ERROR func init must have no type parameters */ _ any]() {} +func init[/* ERROR func init must have no type parameters */ P any]() {} + +type T struct {} + +func (T) m1() {} +func (T) m2[ /* ERROR methods cannot have type parameters */ _ any]() {} +func (T) m3[ /* ERROR methods cannot have type parameters */ P any]() {} + +// type inference across parameterized types + +type S1[P any] struct { f P } + +func f9[P any](x S1[P]) + +func _() { + f9[int](S1[int]{42}) + f9(S1[int]{42}) +} + +type S2[A, B, C any] struct{} + +func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool]) + +func _[P any]() { + f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{}) + f10(S2[int, int, string]{}, S2[int, float32, bool]{}) + f10(S2[P, int, P]{}, S2[P, float32, bool]{}) +} + +// corner case for type inference +// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic) + +func f11[T any]() + +func _() { + f11[int]() +} + +// the previous example was extracted from + +func f12[T interface{m() T}]() + +type A[T any] T + +func (a A[T]) m() A[T] + +func _[T any]() { + f12(A[T])() +} + +// method expressions + +func (_ S1[P]) m() + +func _() { + m := S1[int].m + m(struct { f int }{42}) +} + +func _[T any] (x T) { + m := S1[T].m + m(S1[T]{x}) +} + +// type parameters in methods (generalization) + +type R0 struct{} + +func (R0) _[ /* ERROR methods cannot have type parameters */ T any](x T) +func (R0 /* ERROR invalid receiver */ ) _[ /* ERROR methods cannot have type parameters */ R0 any]() // scope of type parameters starts at "func" + +type R1[A, B any] struct{} + +func (_ R1[A, B]) m0(A, B) +func (_ R1[A, B]) m1[ /* ERROR methods cannot have type parameters */ T any](A, B, T) T +func (_ R1 /* ERROR not a generic type */ [R1, _]) _() +func (_ R1[A, B]) _[ /* ERROR methods cannot have type parameters */ A /* ERROR redeclared */ any](B) + +func _() { + var r R1[int, string] + r.m1[rune](42, "foo", 'a') + r.m1[rune](42, "foo", 1.2 /* ERROR cannot use .* as rune .* \(truncated\) */) + r.m1(42, "foo", 1.2) // using type inference + var _ float64 = r.m1(42, "foo", 1.2) +} + +type I1[A any] interface { + m1(A) +} + +var _ I1[int] = r1[int]{} + +type r1[T any] struct{} + +func (_ r1[T]) m1(T) + +type I2[A, B any] interface { + m1(A) + m2(A) B +} + +var _ I2[int, float32] = R2[int, float32]{} + +type R2[P, Q any] struct{} + +func (_ R2[X, Y]) m1(X) +func (_ R2[X, Y]) m2(X) Y + +// type assertions and type switches over generic types +// NOTE: These are currently disabled because it's unclear what the correct +// approach is, and one can always work around by assigning the variable to +// an interface first. + +// // ReadByte1 corresponds to the ReadByte example in the draft design. +// func ReadByte1[T io.Reader](r T) (byte, error) { +// if br, ok := r.(io.ByteReader); ok { +// return br.ReadByte() +// } +// var b [1]byte +// _, err := r.Read(b[:]) +// return b[0], err +// } +// +// // ReadBytes2 is like ReadByte1 but uses a type switch instead. +// func ReadByte2[T io.Reader](r T) (byte, error) { +// switch br := r.(type) { +// case io.ByteReader: +// return br.ReadByte() +// } +// var b [1]byte +// _, err := r.Read(b[:]) +// return b[0], err +// } +// +// // type assertions and type switches over generic types are strict +// type I3 interface { +// m(int) +// } +// +// type I4 interface { +// m() int // different signature from I3.m +// } +// +// func _[T I3](x I3, p T) { +// // type assertions and type switches over interfaces are not strict +// _ = x.(I4) +// switch x.(type) { +// case I4: +// } +// +// // type assertions and type switches over generic types are strict +// _ = p /* ERROR cannot have dynamic type I4 */.(I4) +// switch p.(type) { +// case I4 /* ERROR cannot have dynamic type I4 */ : +// } +// } + +// type assertions and type switches over generic types lead to errors for now + +func _[T any](x T) { + _ = x /* ERROR not an interface */ .(int) + switch x /* ERROR not an interface */ .(type) { + } + + // work-around + var t interface{} = x + _ = t.(int) + switch t.(type) { + } +} + +func _[T interface{type int}](x T) { + _ = x /* ERROR not an interface */ .(int) + switch x /* ERROR not an interface */ .(type) { + } + + // work-around + var t interface{} = x + _ = t.(int) + switch t.(type) { + } +} + +// error messages related to type bounds mention those bounds +type C[P any] interface{} + +func _[P C[P]] (x P) { + x.m /* ERROR x.m undefined */ () +} + +type I interface {} + +func _[P I] (x P) { + x.m /* ERROR interface I has no method m */ () +} + +func _[P interface{}] (x P) { + x.m /* ERROR type bound for P has no method m */ () +} + +func _[P any] (x P) { + x.m /* ERROR type bound for P has no method m */ () +} + +// automatic distinguishing between array and generic types +// NOTE: Disabled when using unified parameter list syntax. +/* +const P = 10 +type A1 [P]byte +func _(a A1) { + assert(len(a) == 10) +} + +type A2 [P]struct{ + f [P]byte +} +func _(a A2) { + assert(len(a) == 10) + assert(len(a[0].f) == 10) +} + +type A3 [P]func(x [P]A3) +func _(a A3) { + assert(len(a) == 10) +} + +type T2[P] struct{ P } +var _ T2[int] + +type T3[P] func(P) +var _ T3[int] +*/ diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 10d4973b2a1..a6b7314dd52 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -143,11 +143,11 @@ func (check *Checker) ordinaryType(pos positioner, typ Type) { if t := asInterface(typ); t != nil { check.completeInterface(pos.Pos(), t) // TODO(gri) is this the correct position? if t.allTypes != nil { - check.softErrorf(pos, 0, "interface contains type constraints (%s)", t.allTypes) + check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes) return } if t.IsComparable() { - check.softErrorf(pos, 0, "interface is (or embeds) comparable") + check.softErrorf(pos, _Todo, "interface is (or embeds) comparable") } } }) @@ -171,7 +171,7 @@ func (check *Checker) definedType(e ast.Expr, def *Named) Type { typ := check.typInternal(e, def) assert(isTyped(typ)) if isGeneric(typ) { - check.errorf(e, 0, "cannot use generic type %s without instantiation", typ) + check.errorf(e, _Todo, "cannot use generic type %s without instantiation", typ) typ = Typ[Invalid] } check.recordTypeAndValue(e, typexpr, typ, nil) @@ -184,7 +184,7 @@ func (check *Checker) genericType(e ast.Expr, reportErr bool) Type { assert(isTyped(typ)) if typ != Typ[Invalid] && !isGeneric(typ) { if reportErr { - check.errorf(e, 0, "%s is not a generic type", typ) + check.errorf(e, _Todo, "%s is not a generic type", typ) } typ = Typ[Invalid] } @@ -315,7 +315,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // (A separate check is needed when type-checking interface method signatures because // they don't have a receiver specification.) if recvPar != nil { - check.errorf(ftyp.TParams, 0, "methods cannot have type parameters") + check.errorf(ftyp.TParams, _Todo, "methods cannot have type parameters") } } @@ -776,7 +776,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // the author intended to include all types. types = append(types, f.Type) if tlist != nil && tlist != name { - check.errorf(name, 0, "cannot have multiple type lists in an interface") + check.errorf(name, _Todo, "cannot have multiple type lists in an interface") } tlist = name continue @@ -795,7 +795,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d // (This extra check is needed here because interface method signatures don't have // a receiver specification.) if sig.tparams != nil { - check.errorf(f.Type.(*ast.FuncType).TParams, 0, "methods cannot have type parameters") + check.errorf(f.Type.(*ast.FuncType).TParams, _Todo, "methods cannot have type parameters") } // use named receiver type if available (for better error messages) @@ -1072,7 +1072,9 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { pos := f.Type.Pos() name := embeddedFieldIdent(f.Type) if name == nil { - check.invalidAST(f.Type, "embedded field type %s has no name", f.Type) + // TODO(rFindley): using invalidAST here causes test failures (all + // errors should have codes). Clean this up. + check.errorf(f.Type, _Todo, "invalid AST: embedded field type %s has no name", f.Type) name = ast.NewIdent("_") name.NamePos = pos addInvalid(name, pos) @@ -1157,7 +1159,7 @@ func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) [] check.completeInterface(types[i].Pos(), t) } if includes(list[:i], t) { - check.softErrorf(types[i], 0, "duplicate type %s in type list", t) + check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t) } } })