| 1 | // Copyright 2022 The Go Authors. All rights reserved. |
|---|---|
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package typeparams_test |
| 6 | |
| 7 | import ( |
| 8 | "go/ast" |
| 9 | "go/parser" |
| 10 | "go/token" |
| 11 | "go/types" |
| 12 | "testing" |
| 13 | |
| 14 | "golang.org/x/tools/internal/typeparams" |
| 15 | ) |
| 16 | |
| 17 | func TestCoreType(t *testing.T) { |
| 18 | if !typeparams.Enabled { |
| 19 | t.Skip("TestCoreType requires type parameters.") |
| 20 | } |
| 21 | |
| 22 | const source = ` |
| 23 | package P |
| 24 | |
| 25 | type Named int |
| 26 | |
| 27 | type A any |
| 28 | type B interface{~int} |
| 29 | type C interface{int} |
| 30 | type D interface{Named} |
| 31 | type E interface{~int|interface{Named}} |
| 32 | type F interface{~int|~float32} |
| 33 | type G interface{chan int|interface{chan int}} |
| 34 | type H interface{chan int|chan float32} |
| 35 | type I interface{chan<- int|chan int} |
| 36 | type J interface{chan int|chan<- int} |
| 37 | type K interface{<-chan int|chan int} |
| 38 | type L interface{chan int|<-chan int} |
| 39 | type M interface{chan int|chan Named} |
| 40 | type N interface{<-chan int|chan<- int} |
| 41 | type O interface{chan int|bool} |
| 42 | type P struct{ Named } |
| 43 | type Q interface{ Foo() } |
| 44 | type R interface{ Foo() ; Named } |
| 45 | type S interface{ Foo() ; ~int } |
| 46 | |
| 47 | type T interface{chan int|interface{chan int}|<-chan int} |
| 48 | ` |
| 49 | |
| 50 | fset := token.NewFileSet() |
| 51 | f, err := parser.ParseFile(fset, "hello.go", source, 0) |
| 52 | if err != nil { |
| 53 | t.Fatal(err) |
| 54 | } |
| 55 | |
| 56 | var conf types.Config |
| 57 | pkg, err := conf.Check("P", fset, []*ast.File{f}, nil) |
| 58 | if err != nil { |
| 59 | t.Fatal(err) |
| 60 | } |
| 61 | |
| 62 | for _, test := range []struct { |
| 63 | expr string // type expression of Named type |
| 64 | want string // expected core type (or "<nil>" if none) |
| 65 | }{ |
| 66 | {"Named", "int"}, // Underlying type is not interface. |
| 67 | {"A", "<nil>"}, // Interface has no terms. |
| 68 | {"B", "int"}, // Tilde term. |
| 69 | {"C", "int"}, // Non-tilde term. |
| 70 | {"D", "int"}, // Named term. |
| 71 | {"E", "int"}, // Identical underlying types. |
| 72 | {"F", "<nil>"}, // Differing underlying types. |
| 73 | {"G", "chan int"}, // Identical Element types. |
| 74 | {"H", "<nil>"}, // Element type int has differing underlying type to float32. |
| 75 | {"I", "chan<- int"}, // SendRecv followed by SendOnly |
| 76 | {"J", "chan<- int"}, // SendOnly followed by SendRecv |
| 77 | {"K", "<-chan int"}, // RecvOnly followed by SendRecv |
| 78 | {"L", "<-chan int"}, // SendRecv followed by RecvOnly |
| 79 | {"M", "<nil>"}, // Element type int is not *identical* to Named. |
| 80 | {"N", "<nil>"}, // Differing channel directions |
| 81 | {"O", "<nil>"}, // A channel followed by a non-channel. |
| 82 | {"P", "struct{P.Named}"}, // Embedded type. |
| 83 | {"Q", "<nil>"}, // interface type with no terms and functions |
| 84 | {"R", "int"}, // interface type with both terms and functions. |
| 85 | {"S", "int"}, // interface type with a tilde term |
| 86 | {"T", "<-chan int"}, // Prefix of 2 terms that are identical before switching to channel. |
| 87 | } { |
| 88 | // Eval() expr for its type. |
| 89 | tv, err := types.Eval(fset, pkg, 0, test.expr) |
| 90 | if err != nil { |
| 91 | t.Fatalf("Eval(%s) failed: %v", test.expr, err) |
| 92 | } |
| 93 | |
| 94 | ct := typeparams.CoreType(tv.Type) |
| 95 | var got string |
| 96 | if ct == nil { |
| 97 | got = "<nil>" |
| 98 | } else { |
| 99 | got = ct.String() |
| 100 | } |
| 101 | if got != test.want { |
| 102 | t.Errorf("coreType(%s) = %v, want %v", test.expr, got, test.want) |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 |
Members