|
8 | 8 | "testing" |
9 | 9 | ) |
10 | 10 |
|
11 | | -func TestNestedSubst(t *testing.T) { |
| 11 | +func TestNestedSubstInGenericFunction(t *testing.T) { |
12 | 12 | const source = ` |
13 | 13 | package P |
14 | 14 |
|
@@ -71,6 +71,68 @@ func TestNestedSubst(t *testing.T) { |
71 | 71 | } |
72 | 72 | } |
73 | 73 |
|
| 74 | +func TestNestedSubstInConcreteFunction(t *testing.T) { |
| 75 | + const source = ` |
| 76 | + package P |
| 77 | +
|
| 78 | + func A(){ |
| 79 | + type C[U any] struct{X T; Y U} |
| 80 | + }` |
| 81 | + |
| 82 | + fSet := token.NewFileSet() |
| 83 | + f, err := parser.ParseFile(fSet, "hello.go", source, 0) |
| 84 | + if err != nil { |
| 85 | + t.Fatal(err) |
| 86 | + } |
| 87 | + |
| 88 | + var conf types.Config |
| 89 | + pkg, err := conf.Check("P", fSet, []*ast.File{f}, nil) |
| 90 | + if err != nil { |
| 91 | + t.Fatal(err) |
| 92 | + } |
| 93 | + |
| 94 | + for _, test := range []struct { |
| 95 | + fnName string // the name of the nesting function |
| 96 | + fnArgs []string // type expressions of args for the nesting function |
| 97 | + stName string // the name of the named type |
| 98 | + stArgs []string // type expressions of args for the named type |
| 99 | + want string // expected underlying value after substitution |
| 100 | + }{ |
| 101 | + { |
| 102 | + fnName: "A", fnArgs: []string{"int"}, |
| 103 | + stName: "B", stArgs: []string{}, |
| 104 | + want: "struct{X int}", |
| 105 | + }, |
| 106 | + } { |
| 107 | + ctxt := types.NewContext() |
| 108 | + |
| 109 | + fnGen, _ := pkg.Scope().Lookup(test.fnName).(*types.Func) |
| 110 | + if fnGen == nil { |
| 111 | + t.Fatal("Failed to find the function " + test.fnName) |
| 112 | + } |
| 113 | + fnType := fnGen.Type().(*types.Signature) |
| 114 | + fnArgs := evalTypeList(t, fSet, pkg, test.fnArgs) |
| 115 | + fnInst, err := types.Instantiate(ctxt, fnType, fnArgs, true) |
| 116 | + if err != nil { |
| 117 | + t.Fatalf("Failed to instantiate %s: %v", fnType, err) |
| 118 | + } |
| 119 | + fnFunc := types.NewFunc(fnGen.Pos(), pkg, fnGen.Name(), fnInst.(*types.Signature)) |
| 120 | + |
| 121 | + stType, _ := fnFunc.Scope().Lookup(test.stName).Type().(*types.Named) |
| 122 | + if stType == nil { |
| 123 | + t.Fatal("Failed to find the object " + test.fnName + " in function " + test.fnName) |
| 124 | + } |
| 125 | + stArgs := evalTypeList(t, fSet, pkg, test.stArgs) |
| 126 | + |
| 127 | + stSubst := New(types.NewContext(), fnFunc, stType.TypeParams(), stArgs) |
| 128 | + stInst := stSubst.Type(stType.Underlying()) |
| 129 | + |
| 130 | + if got := stInst.String(); got != test.want { |
| 131 | + t.Errorf("subst{%v->%v}.typ(%s) = %v, want %v", test.stName, test.stArgs, stType.Underlying(), got, test.want) |
| 132 | + } |
| 133 | + } |
| 134 | +} |
| 135 | + |
74 | 136 | func evalType(t *testing.T, fSet *token.FileSet, pkg *types.Package, expr string) types.Type { |
75 | 137 | tv, err := types.Eval(fSet, pkg, 0, expr) |
76 | 138 | if err != nil { |
|
0 commit comments