22// Use of this source code is governed by a BSD-style
33// license that can be found in the LICENSE file.
44
5+ //go:debug gotypesalias=1
6+
57package facts_test
68
79import (
@@ -18,8 +20,10 @@ import (
1820
1921 "golang.org/x/tools/go/analysis/analysistest"
2022 "golang.org/x/tools/go/packages"
23+ "golang.org/x/tools/internal/aliases"
2124 "golang.org/x/tools/internal/facts"
2225 "golang.org/x/tools/internal/testenv"
26+ "golang.org/x/tools/internal/typesinternal"
2327)
2428
2529type myFact struct {
@@ -35,10 +39,9 @@ func init() {
3539
3640func TestEncodeDecode (t * testing.T ) {
3741 tests := []struct {
38- name string
39- typeparams bool // requires typeparams to be enabled
40- files map [string ]string
41- plookups []pkgLookups // see testEncodeDecode for details
42+ name string
43+ files map [string ]string
44+ plookups []pkgLookups // see testEncodeDecode for details
4245 }{
4346 {
4447 name : "loading-order" ,
@@ -184,8 +187,7 @@ func TestEncodeDecode(t *testing.T) {
184187 },
185188 },
186189 {
187- name : "typeparams" ,
188- typeparams : true ,
190+ name : "typeparams" ,
189191 files : map [string ]string {
190192 "a/a.go" : `package a
191193 type T1 int
@@ -202,9 +204,9 @@ func TestEncodeDecode(t *testing.T) {
202204 type N3[T a.T3] func() T
203205 type N4[T a.T4|int8] func() T
204206 type N5[T interface{Bar() a.T5} ] func() T
205-
207+
206208 type t5 struct{}; func (t5) Bar() a.T5 { return 0 }
207-
209+
208210 var G1 N1[a.T1]
209211 var G2 func() N2[a.T2]
210212 var G3 N3[a.T3]
@@ -222,7 +224,7 @@ func TestEncodeDecode(t *testing.T) {
222224 v5 = b.G5
223225 v6 = b.F6[t6]
224226 )
225-
227+
226228 type t6 struct{}; func (t6) Foo() {}
227229 ` ,
228230 },
@@ -244,19 +246,44 @@ func TestEncodeDecode(t *testing.T) {
244246 },
245247 },
246248 }
247-
248- for i := range tests {
249- test := tests [i ]
249+ for _ , test := range tests {
250250 t .Run (test .name , func (t * testing.T ) {
251251 t .Parallel ()
252252 testEncodeDecode (t , test .files , test .plookups )
253253 })
254254 }
255255}
256256
257+ func TestEncodeDecodeAliases (t * testing.T ) {
258+ testenv .NeedsGo1Point (t , 24 )
259+
260+ files := map [string ]string {
261+ "a/a.go" : `package a
262+ type A = int
263+ ` ,
264+ "b/b.go" : `package b
265+ import "a"
266+ type B = a.A
267+ ` ,
268+ "c/c.go" : `package c
269+ import "b";
270+ type N1[T int|~string] = struct{}
271+
272+ var V1 = N1[b.B]{}
273+ ` ,
274+ }
275+ plookups := []pkgLookups {
276+ {"a" , []lookup {}},
277+ {"b" , []lookup {}},
278+ // fake objexpr for RHS of V1's type arg (see customFind hack)
279+ {"c" , []lookup {{"c.V1->c.N1->b.B->a.A" , "myFact(a.A)" }}},
280+ }
281+ testEncodeDecode (t , files , plookups )
282+ }
283+
257284type lookup struct {
258- objexpr string
259- want string
285+ objexpr string // expression whose type is a named type
286+ want string // printed form of fact associated with that type (or "no fact")
260287}
261288
262289type pkgLookups struct {
@@ -345,22 +372,37 @@ func testEncodeDecode(t *testing.T, files map[string]string, tests []pkgLookups)
345372 }
346373}
347374
375+ // customFind allows for overriding how an object is looked up
376+ // by find. This is necessary for objects that are accessible through
377+ // the API but are not the type of any expression we can pass to types.CheckExpr.
378+ var customFind = map [string ]func (p * types.Package ) types.Object {
379+ "c.V1->c.N1->b.B->a.A" : func (p * types.Package ) types.Object {
380+ cV1 := p .Scope ().Lookup ("V1" )
381+ cN1 := cV1 .Type ().(* types.Alias )
382+ aT1 := aliases .TypeArgs (cN1 ).At (0 ).(* types.Alias )
383+ zZ1 := aliases .Rhs (aT1 ).(* types.Alias )
384+ return zZ1 .Obj ()
385+ },
386+ }
387+
348388func find (p * types.Package , expr string ) types.Object {
349389 // types.Eval only allows us to compute a TypeName object for an expression.
350390 // TODO(adonovan): support other expressions that denote an object:
351391 // - an identifier (or qualified ident) for a func, const, or var
352392 // - new(T).f for a field or method
353393 // I've added CheckExpr in https://go-review.googlesource.com/c/go/+/144677.
354394 // If that becomes available, use it.
355-
395+ if f := customFind [expr ]; f != nil {
396+ return f (p )
397+ }
356398 // Choose an arbitrary position within the (single-file) package
357399 // so that we are within the scope of its import declarations.
358400 somepos := p .Scope ().Lookup (p .Scope ().Names ()[0 ]).Pos ()
359401 tv , err := types .Eval (token .NewFileSet (), p , somepos , expr )
360402 if err != nil {
361403 return nil
362404 }
363- if n , ok := types . Unalias ( tv .Type ).( * types. Named ); ok {
405+ if n , ok := tv .Type .(typesinternal. NamedOrAlias ); ok {
364406 return n .Obj ()
365407 }
366408 return nil
0 commit comments