libgo: update to go1.9
[official-gcc.git] / libgo / go / go / types / api_test.go
blob1b17579641074ffd93572fddb96af4eeaefbbd03
1 // Copyright 2013 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.
5 package types_test
7 import (
8 "bytes"
9 "fmt"
10 "go/ast"
11 "go/importer"
12 "go/parser"
13 "go/token"
14 "internal/testenv"
15 "reflect"
16 "regexp"
17 "strings"
18 "testing"
20 . "go/types"
23 func pkgFor(path, source string, info *Info) (*Package, error) {
24 fset := token.NewFileSet()
25 f, err := parser.ParseFile(fset, path, source, 0)
26 if err != nil {
27 return nil, err
30 conf := Config{Importer: importer.Default()}
31 return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
34 func mustTypecheck(t *testing.T, path, source string, info *Info) string {
35 t.Skip("skipping for gccgo--no importer")
36 pkg, err := pkgFor(path, source, info)
37 if err != nil {
38 name := path
39 if pkg != nil {
40 name = "package " + pkg.Name()
42 t.Fatalf("%s: didn't type-check (%s)", name, err)
44 return pkg.Name()
47 func TestValuesInfo(t *testing.T) {
48 var tests = []struct {
49 src string
50 expr string // constant expression
51 typ string // constant type
52 val string // constant value
54 {`package a0; const _ = false`, `false`, `untyped bool`, `false`},
55 {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
56 {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
57 {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
58 {`package a4; const _ = 0i`, `0i`, `untyped complex`, `(0 + 0i)`},
59 {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
61 {`package b0; var _ = false`, `false`, `bool`, `false`},
62 {`package b1; var _ = 0`, `0`, `int`, `0`},
63 {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
64 {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
65 {`package b4; var _ = 0i`, `0i`, `complex128`, `(0 + 0i)`},
66 {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
68 {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
69 {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
70 {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
72 {`package c1a; var _ = int(0)`, `0`, `int`, `0`},
73 {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
74 {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
76 {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
77 {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
78 {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
80 {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
81 {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
82 {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
84 {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `(0 + 0i)`},
85 {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `(0 + 0i)`},
86 {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `(0 + 0i)`},
88 {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
89 {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
90 {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
92 {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
93 {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
94 {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
95 {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
97 {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
98 {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
99 {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
100 {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
101 {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `(0 + 0i)`},
102 {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `(0 + 0i)`},
103 {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `(0 + 0i)`},
104 {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `(0 + 0i)`},
106 {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`},
107 {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
108 {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`},
109 {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
110 {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`},
111 {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`},
112 {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `(0 + 0i)`},
113 {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `(0 + 0i)`},
114 {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
115 {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
116 {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
117 {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
120 for _, test := range tests {
121 info := Info{
122 Types: make(map[ast.Expr]TypeAndValue),
124 name := mustTypecheck(t, "ValuesInfo", test.src, &info)
126 // look for constant expression
127 var expr ast.Expr
128 for e := range info.Types {
129 if ExprString(e) == test.expr {
130 expr = e
131 break
134 if expr == nil {
135 t.Errorf("package %s: no expression found for %s", name, test.expr)
136 continue
138 tv := info.Types[expr]
140 // check that type is correct
141 if got := tv.Type.String(); got != test.typ {
142 t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
143 continue
146 // check that value is correct
147 if got := tv.Value.ExactString(); got != test.val {
148 t.Errorf("package %s: got value %s; want %s", name, got, test.val)
153 func TestTypesInfo(t *testing.T) {
154 var tests = []struct {
155 src string
156 expr string // expression
157 typ string // value type
159 // single-valued expressions of untyped constants
160 {`package b0; var x interface{} = false`, `false`, `bool`},
161 {`package b1; var x interface{} = 0`, `0`, `int`},
162 {`package b2; var x interface{} = 0.`, `0.`, `float64`},
163 {`package b3; var x interface{} = 0i`, `0i`, `complex128`},
164 {`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
166 // comma-ok expressions
167 {`package p0; var x interface{}; var _, _ = x.(int)`,
168 `x.(int)`,
169 `(int, bool)`,
171 {`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
172 `x.(int)`,
173 `(int, bool)`,
175 {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
176 `m["foo"]`,
177 `(complex128, p2a.mybool)`,
179 {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
180 `m["foo"]`,
181 `(complex128, bool)`,
183 {`package p3; var c chan string; var _, _ = <-c`,
184 `<-c`,
185 `(string, bool)`,
188 // issue 6796
189 {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
190 `x.(int)`,
191 `(int, bool)`,
193 {`package issue6796_b; var c chan string; var _, _ = (<-c)`,
194 `(<-c)`,
195 `(string, bool)`,
197 {`package issue6796_c; var c chan string; var _, _ = (<-c)`,
198 `<-c`,
199 `(string, bool)`,
201 {`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
202 `(<-c)`,
203 `(string, bool)`,
205 {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
206 `(<-c)`,
207 `(string, bool)`,
210 // issue 7060
211 {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
212 `m[0]`,
213 `(string, bool)`,
215 {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
216 `m[0]`,
217 `(string, bool)`,
219 {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
220 `m[0]`,
221 `(string, bool)`,
223 {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
224 `<-ch`,
225 `(string, bool)`,
227 {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
228 `<-ch`,
229 `(string, bool)`,
231 {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
232 `<-ch`,
233 `(string, bool)`,
237 for _, test := range tests {
238 info := Info{Types: make(map[ast.Expr]TypeAndValue)}
239 name := mustTypecheck(t, "TypesInfo", test.src, &info)
241 // look for expression type
242 var typ Type
243 for e, tv := range info.Types {
244 if ExprString(e) == test.expr {
245 typ = tv.Type
246 break
249 if typ == nil {
250 t.Errorf("package %s: no type found for %s", name, test.expr)
251 continue
254 // check that type is correct
255 if got := typ.String(); got != test.typ {
256 t.Errorf("package %s: got %s; want %s", name, got, test.typ)
261 func predString(tv TypeAndValue) string {
262 var buf bytes.Buffer
263 pred := func(b bool, s string) {
264 if b {
265 if buf.Len() > 0 {
266 buf.WriteString(", ")
268 buf.WriteString(s)
272 pred(tv.IsVoid(), "void")
273 pred(tv.IsType(), "type")
274 pred(tv.IsBuiltin(), "builtin")
275 pred(tv.IsValue() && tv.Value != nil, "const")
276 pred(tv.IsValue() && tv.Value == nil, "value")
277 pred(tv.IsNil(), "nil")
278 pred(tv.Addressable(), "addressable")
279 pred(tv.Assignable(), "assignable")
280 pred(tv.HasOk(), "hasOk")
282 if buf.Len() == 0 {
283 return "invalid"
285 return buf.String()
288 func TestPredicatesInfo(t *testing.T) {
289 testenv.MustHaveGoBuild(t)
291 var tests = []struct {
292 src string
293 expr string
294 pred string
296 // void
297 {`package n0; func f() { f() }`, `f()`, `void`},
299 // types
300 {`package t0; type _ int`, `int`, `type`},
301 {`package t1; type _ []int`, `[]int`, `type`},
302 {`package t2; type _ func()`, `func()`, `type`},
304 // built-ins
305 {`package b0; var _ = len("")`, `len`, `builtin`},
306 {`package b1; var _ = (len)("")`, `(len)`, `builtin`},
308 // constants
309 {`package c0; var _ = 42`, `42`, `const`},
310 {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
311 {`package c2; const (i = 1i; _ = i)`, `i`, `const`},
313 // values
314 {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
315 {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
316 {`package v2; var _ = func(){}`, `(func() literal)`, `value`},
317 {`package v4; func f() { _ = f }`, `f`, `value`},
318 {`package v3; var _ *int = nil`, `nil`, `value, nil`},
319 {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
321 // addressable (and thus assignable) operands
322 {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
323 {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
324 {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
325 {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
326 {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
327 {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
328 {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
329 {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
330 // composite literals are not addressable
332 // assignable but not addressable values
333 {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
334 {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
336 // hasOk expressions
337 {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
338 {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
340 // missing entries
341 // - package names are collected in the Uses map
342 // - identifiers being declared are collected in the Defs map
343 {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
344 {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
345 {`package m2; const c = 0`, `c`, `<missing>`},
346 {`package m3; type T int`, `T`, `<missing>`},
347 {`package m4; var v int`, `v`, `<missing>`},
348 {`package m5; func f() {}`, `f`, `<missing>`},
349 {`package m6; func _(x int) {}`, `x`, `<missing>`},
350 {`package m6; func _()(x int) { return }`, `x`, `<missing>`},
351 {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
354 for _, test := range tests {
355 info := Info{Types: make(map[ast.Expr]TypeAndValue)}
356 name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
358 // look for expression predicates
359 got := "<missing>"
360 for e, tv := range info.Types {
361 //println(name, ExprString(e))
362 if ExprString(e) == test.expr {
363 got = predString(tv)
364 break
368 if got != test.pred {
369 t.Errorf("package %s: got %s; want %s", name, got, test.pred)
374 func TestScopesInfo(t *testing.T) {
375 testenv.MustHaveGoBuild(t)
377 var tests = []struct {
378 src string
379 scopes []string // list of scope descriptors of the form kind:varlist
381 {`package p0`, []string{
382 "file:",
384 {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
385 "file:fmt m",
387 {`package p2; func _() {}`, []string{
388 "file:", "func:",
390 {`package p3; func _(x, y int) {}`, []string{
391 "file:", "func:x y",
393 {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
394 "file:", "func:x y z", // redeclaration of x
396 {`package p5; func _(x, y int) (u, _ int) { return }`, []string{
397 "file:", "func:u x y",
399 {`package p6; func _() { { var x int; _ = x } }`, []string{
400 "file:", "func:", "block:x",
402 {`package p7; func _() { if true {} }`, []string{
403 "file:", "func:", "if:", "block:",
405 {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
406 "file:", "func:", "if:x", "block:y",
408 {`package p9; func _() { switch x := 0; x {} }`, []string{
409 "file:", "func:", "switch:x",
411 {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
412 "file:", "func:", "switch:x", "case:y", "case:",
414 {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
415 "file:", "func:t", "type switch:",
417 {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
418 "file:", "func:t", "type switch:t",
420 {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
421 "file:", "func:t", "type switch:", "case:x", // x implicitly declared
423 {`package p14; func _() { select{} }`, []string{
424 "file:", "func:",
426 {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
427 "file:", "func:c", "comm:",
429 {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
430 "file:", "func:c", "comm:i x",
432 {`package p17; func _() { for{} }`, []string{
433 "file:", "func:", "for:", "block:",
435 {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
436 "file:", "func:n", "for:i", "block:",
438 {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
439 "file:", "func:a", "range:i", "block:",
441 {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
442 "file:", "func:a", "range:i x", "block:",
446 for _, test := range tests {
447 info := Info{Scopes: make(map[ast.Node]*Scope)}
448 name := mustTypecheck(t, "ScopesInfo", test.src, &info)
450 // number of scopes must match
451 if len(info.Scopes) != len(test.scopes) {
452 t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
455 // scope descriptions must match
456 for node, scope := range info.Scopes {
457 kind := "<unknown node kind>"
458 switch node.(type) {
459 case *ast.File:
460 kind = "file"
461 case *ast.FuncType:
462 kind = "func"
463 case *ast.BlockStmt:
464 kind = "block"
465 case *ast.IfStmt:
466 kind = "if"
467 case *ast.SwitchStmt:
468 kind = "switch"
469 case *ast.TypeSwitchStmt:
470 kind = "type switch"
471 case *ast.CaseClause:
472 kind = "case"
473 case *ast.CommClause:
474 kind = "comm"
475 case *ast.ForStmt:
476 kind = "for"
477 case *ast.RangeStmt:
478 kind = "range"
481 // look for matching scope description
482 desc := kind + ":" + strings.Join(scope.Names(), " ")
483 found := false
484 for _, d := range test.scopes {
485 if desc == d {
486 found = true
487 break
490 if !found {
491 t.Errorf("package %s: no matching scope found for %s", name, desc)
497 func TestInitOrderInfo(t *testing.T) {
498 var tests = []struct {
499 src string
500 inits []string
502 {`package p0; var (x = 1; y = x)`, []string{
503 "x = 1", "y = x",
505 {`package p1; var (a = 1; b = 2; c = 3)`, []string{
506 "a = 1", "b = 2", "c = 3",
508 {`package p2; var (a, b, c = 1, 2, 3)`, []string{
509 "a = 1", "b = 2", "c = 3",
511 {`package p3; var _ = f(); func f() int { return 1 }`, []string{
512 "_ = f()", // blank var
514 {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
515 "a = 0", "z = 0", "y = z", "x = y",
517 {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
518 "a, _ = m[0]", // blank var
520 {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
521 "z = 0", "a, b = f()",
523 {`package p7; var (a = func() int { return b }(); b = 1)`, []string{
524 "b = 1", "a = (func() int literal)()",
526 {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
527 "c = 1", "a, b = (func() (_, _ int) literal)()",
529 {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
530 "y = 1", "x = T.m",
532 {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
533 "a = 0", "b = 0", "c = 0", "d = c + b",
535 {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
536 "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
538 // emit an initializer for n:1 initializations only once (not for each node
539 // on the lhs which may appear in different order in the dependency graph)
540 {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
541 "b = 0", "x, y = m[0]", "a = x",
543 // test case from spec section on package initialization
544 {`package p12
546 var (
547 a = c + b
548 b = f()
549 c = f()
550 d = 3
553 func f() int {
555 return d
556 }`, []string{
557 "d = 3", "b = f()", "c = f()", "a = c + b",
559 // test case for issue 7131
560 {`package main
562 var counter int
563 func next() int { counter++; return counter }
565 var _ = makeOrder()
566 func makeOrder() []int { return []int{f, b, d, e, c, a} }
568 var a = next()
569 var b, c = next(), next()
570 var d, e, f = next(), next(), next()
571 `, []string{
572 "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
574 // test case for issue 10709
575 {`package p13
577 var (
578 v = t.m()
579 t = makeT(0)
582 type T struct{}
584 func (T) m() int { return 0 }
586 func makeT(n int) T {
587 if n > 0 {
588 return makeT(n-1)
590 return T{}
591 }`, []string{
592 "t = makeT(0)", "v = t.m()",
594 // test case for issue 10709: same as test before, but variable decls swapped
595 {`package p14
597 var (
598 t = makeT(0)
599 v = t.m()
602 type T struct{}
604 func (T) m() int { return 0 }
606 func makeT(n int) T {
607 if n > 0 {
608 return makeT(n-1)
610 return T{}
611 }`, []string{
612 "t = makeT(0)", "v = t.m()",
614 // another candidate possibly causing problems with issue 10709
615 {`package p15
617 var y1 = f1()
619 func f1() int { return g1() }
620 func g1() int { f1(); return x1 }
622 var x1 = 0
624 var y2 = f2()
626 func f2() int { return g2() }
627 func g2() int { return x2 }
629 var x2 = 0`, []string{
630 "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()",
634 for _, test := range tests {
635 info := Info{}
636 name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
638 // number of initializers must match
639 if len(info.InitOrder) != len(test.inits) {
640 t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
641 continue
644 // initializers must match
645 for i, want := range test.inits {
646 got := info.InitOrder[i].String()
647 if got != want {
648 t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
649 continue
655 func TestMultiFileInitOrder(t *testing.T) {
656 fset := token.NewFileSet()
657 mustParse := func(src string) *ast.File {
658 f, err := parser.ParseFile(fset, "main", src, 0)
659 if err != nil {
660 t.Fatal(err)
662 return f
665 fileA := mustParse(`package main; var a = 1`)
666 fileB := mustParse(`package main; var b = 2`)
668 // The initialization order must not depend on the parse
669 // order of the files, only on the presentation order to
670 // the type-checker.
671 for _, test := range []struct {
672 files []*ast.File
673 want string
675 {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
676 {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
678 var info Info
679 if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
680 t.Fatal(err)
682 if got := fmt.Sprint(info.InitOrder); got != test.want {
683 t.Fatalf("got %s; want %s", got, test.want)
688 func TestFiles(t *testing.T) {
689 var sources = []string{
690 "package p; type T struct{}; func (T) m1() {}",
691 "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
692 "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
693 "package p",
696 var conf Config
697 fset := token.NewFileSet()
698 pkg := NewPackage("p", "p")
699 var info Info
700 check := NewChecker(&conf, fset, pkg, &info)
702 for i, src := range sources {
703 filename := fmt.Sprintf("sources%d", i)
704 f, err := parser.ParseFile(fset, filename, src, 0)
705 if err != nil {
706 t.Fatal(err)
708 if err := check.Files([]*ast.File{f}); err != nil {
709 t.Error(err)
713 // check InitOrder is [x y]
714 var vars []string
715 for _, init := range info.InitOrder {
716 for _, v := range init.Lhs {
717 vars = append(vars, v.Name())
720 if got, want := fmt.Sprint(vars), "[x y]"; got != want {
721 t.Errorf("InitOrder == %s, want %s", got, want)
725 type testImporter map[string]*Package
727 func (m testImporter) Import(path string) (*Package, error) {
728 if pkg := m[path]; pkg != nil {
729 return pkg, nil
731 return nil, fmt.Errorf("package %q not found", path)
734 func TestSelection(t *testing.T) {
735 selections := make(map[*ast.SelectorExpr]*Selection)
737 fset := token.NewFileSet()
738 imports := make(testImporter)
739 conf := Config{Importer: imports}
740 makePkg := func(path, src string) {
741 f, err := parser.ParseFile(fset, path+".go", src, 0)
742 if err != nil {
743 t.Fatal(err)
745 pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
746 if err != nil {
747 t.Fatal(err)
749 imports[path] = pkg
752 const libSrc = `
753 package lib
754 type T float64
755 const C T = 3
756 var V T
757 func F() {}
758 func (T) M() {}
760 const mainSrc = `
761 package main
762 import "lib"
764 type A struct {
769 type B struct {
770 b int
773 func (B) f(int)
775 type C struct {
776 c int
779 func (C) g()
780 func (*C) h()
782 func main() {
783 // qualified identifiers
784 var _ lib.T
785 _ = lib.C
786 _ = lib.F
787 _ = lib.V
788 _ = lib.T.M
790 // fields
791 _ = A{}.B
792 _ = new(A).B
794 _ = A{}.C
795 _ = new(A).C
797 _ = A{}.b
798 _ = new(A).b
800 _ = A{}.c
801 _ = new(A).c
803 // methods
804 _ = A{}.f
805 _ = new(A).f
806 _ = A{}.g
807 _ = new(A).g
808 _ = new(A).h
810 _ = B{}.f
811 _ = new(B).f
813 _ = C{}.g
814 _ = new(C).g
815 _ = new(C).h
817 // method expressions
818 _ = A.f
819 _ = (*A).f
820 _ = B.f
821 _ = (*B).f
824 wantOut := map[string][2]string{
825 "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
827 "A{}.B": {"field (main.A) B *main.B", ".[0]"},
828 "new(A).B": {"field (*main.A) B *main.B", "->[0]"},
829 "A{}.C": {"field (main.A) C main.C", ".[1]"},
830 "new(A).C": {"field (*main.A) C main.C", "->[1]"},
831 "A{}.b": {"field (main.A) b int", "->[0 0]"},
832 "new(A).b": {"field (*main.A) b int", "->[0 0]"},
833 "A{}.c": {"field (main.A) c int", ".[1 0]"},
834 "new(A).c": {"field (*main.A) c int", "->[1 0]"},
836 "A{}.f": {"method (main.A) f(int)", "->[0 0]"},
837 "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
838 "A{}.g": {"method (main.A) g()", ".[1 0]"},
839 "new(A).g": {"method (*main.A) g()", "->[1 0]"},
840 "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
841 "B{}.f": {"method (main.B) f(int)", ".[0]"},
842 "new(B).f": {"method (*main.B) f(int)", "->[0]"},
843 "C{}.g": {"method (main.C) g()", ".[0]"},
844 "new(C).g": {"method (*main.C) g()", "->[0]"},
845 "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
847 "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"},
848 "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
849 "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"},
850 "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
853 makePkg("lib", libSrc)
854 makePkg("main", mainSrc)
856 for e, sel := range selections {
857 _ = sel.String() // assertion: must not panic
859 start := fset.Position(e.Pos()).Offset
860 end := fset.Position(e.End()).Offset
861 syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
863 direct := "."
864 if sel.Indirect() {
865 direct = "->"
867 got := [2]string{
868 sel.String(),
869 fmt.Sprintf("%s%v", direct, sel.Index()),
871 want := wantOut[syntax]
872 if want != got {
873 t.Errorf("%s: got %q; want %q", syntax, got, want)
875 delete(wantOut, syntax)
877 // We must explicitly assert properties of the
878 // Signature's receiver since it doesn't participate
879 // in Identical() or String().
880 sig, _ := sel.Type().(*Signature)
881 if sel.Kind() == MethodVal {
882 got := sig.Recv().Type()
883 want := sel.Recv()
884 if !Identical(got, want) {
885 t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
887 } else if sig != nil && sig.Recv() != nil {
888 t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
891 // Assert that all wantOut entries were used exactly once.
892 for syntax := range wantOut {
893 t.Errorf("no ast.Selection found with syntax %q", syntax)
897 func TestIssue8518(t *testing.T) {
898 fset := token.NewFileSet()
899 imports := make(testImporter)
900 conf := Config{
901 Error: func(err error) { t.Log(err) }, // don't exit after first error
902 Importer: imports,
904 makePkg := func(path, src string) {
905 f, err := parser.ParseFile(fset, path, src, 0)
906 if err != nil {
907 t.Fatal(err)
909 pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
910 imports[path] = pkg
913 const libSrc = `
914 package a
915 import "missing"
916 const C1 = foo
917 const C2 = missing.C
920 const mainSrc = `
921 package main
922 import "a"
923 var _ = a.C1
924 var _ = a.C2
927 makePkg("a", libSrc)
928 makePkg("main", mainSrc) // don't crash when type-checking this package
931 func TestLookupFieldOrMethod(t *testing.T) {
932 t.Skip("skipping for gccgo--no importer")
933 // Test cases assume a lookup of the form a.f or x.f, where a stands for an
934 // addressable value, and x for a non-addressable value (even though a variable
935 // for ease of test case writing).
936 var tests = []struct {
937 src string
938 found bool
939 index []int
940 indirect bool
942 // field lookups
943 {"var x T; type T struct{}", false, nil, false},
944 {"var x T; type T struct{ f int }", true, []int{0}, false},
945 {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
947 // method lookups
948 {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
949 {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
950 {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
951 {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
953 // collisions
954 {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
955 {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
957 // outside methodset
958 // (*T).f method exists, but value of type T is not addressable
959 {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
962 for _, test := range tests {
963 pkg, err := pkgFor("test", "package p;"+test.src, nil)
964 if err != nil {
965 t.Errorf("%s: incorrect test case: %s", test.src, err)
966 continue
969 obj := pkg.Scope().Lookup("a")
970 if obj == nil {
971 if obj = pkg.Scope().Lookup("x"); obj == nil {
972 t.Errorf("%s: incorrect test case - no object a or x", test.src)
973 continue
977 f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
978 if (f != nil) != test.found {
979 if f == nil {
980 t.Errorf("%s: got no object; want one", test.src)
981 } else {
982 t.Errorf("%s: got object = %v; want none", test.src, f)
985 if !sameSlice(index, test.index) {
986 t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
988 if indirect != test.indirect {
989 t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
994 func sameSlice(a, b []int) bool {
995 if len(a) != len(b) {
996 return false
998 for i, x := range a {
999 if x != b[i] {
1000 return false
1003 return true
1006 // TestScopeLookupParent ensures that (*Scope).LookupParent returns
1007 // the correct result at various positions with the source.
1008 func TestScopeLookupParent(t *testing.T) {
1009 fset := token.NewFileSet()
1010 imports := make(testImporter)
1011 conf := Config{Importer: imports}
1012 mustParse := func(src string) *ast.File {
1013 f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments)
1014 if err != nil {
1015 t.Fatal(err)
1017 return f
1019 var info Info
1020 makePkg := func(path string, files ...*ast.File) {
1021 var err error
1022 imports[path], err = conf.Check(path, fset, files, &info)
1023 if err != nil {
1024 t.Fatal(err)
1028 makePkg("lib", mustParse("package lib; var X int"))
1029 // Each /*name=kind:line*/ comment makes the test look up the
1030 // name at that point and checks that it resolves to a decl of
1031 // the specified kind and line number. "undef" means undefined.
1032 mainSrc := `
1033 /*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
1034 package main
1036 import "lib"
1037 import . "lib"
1039 const Pi = 3.1415
1040 type T struct{}
1041 var Y, _ = lib.X, X
1043 func F(){
1044 const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
1045 type /*t=undef*/ t /*t=typename:14*/ *t
1046 print(Y) /*Y=var:10*/
1047 x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
1048 var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
1050 var a []int
1051 for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
1053 var i interface{}
1054 switch y := i.(type) { /*y=undef*/
1055 case /*y=undef*/ int /*y=var:23*/ :
1056 case float32, /*y=undef*/ float64 /*y=var:23*/ :
1057 default /*y=var:23*/:
1058 println(y)
1060 /*y=undef*/
1062 switch int := i.(type) {
1063 case /*int=typename:0*/ int /*int=var:31*/ :
1064 println(int)
1065 default /*int=var:31*/ :
1068 /*main=undef*/
1071 info.Uses = make(map[*ast.Ident]Object)
1072 f := mustParse(mainSrc)
1073 makePkg("main", f)
1074 mainScope := imports["main"].Scope()
1075 rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
1076 for _, group := range f.Comments {
1077 for _, comment := range group.List {
1078 // Parse the assertion in the comment.
1079 m := rx.FindStringSubmatch(comment.Text)
1080 if m == nil {
1081 t.Errorf("%s: bad comment: %s",
1082 fset.Position(comment.Pos()), comment.Text)
1083 continue
1085 name, want := m[1], m[2]
1087 // Look up the name in the innermost enclosing scope.
1088 inner := mainScope.Innermost(comment.Pos())
1089 if inner == nil {
1090 t.Errorf("%s: at %s: can't find innermost scope",
1091 fset.Position(comment.Pos()), comment.Text)
1092 continue
1094 got := "undef"
1095 if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil {
1096 kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
1097 got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line)
1099 if got != want {
1100 t.Errorf("%s: at %s: %s resolved to %s, want %s",
1101 fset.Position(comment.Pos()), comment.Text, name, got, want)
1106 // Check that for each referring identifier,
1107 // a lookup of its name on the innermost
1108 // enclosing scope returns the correct object.
1110 for id, wantObj := range info.Uses {
1111 inner := mainScope.Innermost(id.Pos())
1112 if inner == nil {
1113 t.Errorf("%s: can't find innermost scope enclosing %q",
1114 fset.Position(id.Pos()), id.Name)
1115 continue
1118 // Exclude selectors and qualified identifiers---lexical
1119 // refs only. (Ideally, we'd see if the AST parent is a
1120 // SelectorExpr, but that requires PathEnclosingInterval
1121 // from golang.org/x/tools/go/ast/astutil.)
1122 if id.Name == "X" {
1123 continue
1126 _, gotObj := inner.LookupParent(id.Name, id.Pos())
1127 if gotObj != wantObj {
1128 t.Errorf("%s: got %v, want %v",
1129 fset.Position(id.Pos()), gotObj, wantObj)
1130 continue
1135 func TestIdentical_issue15173(t *testing.T) {
1136 // Identical should allow nil arguments and be symmetric.
1137 for _, test := range []struct {
1138 x, y Type
1139 want bool
1141 {Typ[Int], Typ[Int], true},
1142 {Typ[Int], nil, false},
1143 {nil, Typ[Int], false},
1144 {nil, nil, true},
1146 if got := Identical(test.x, test.y); got != test.want {
1147 t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
1152 func TestIssue15305(t *testing.T) {
1153 const src = "package p; func f() int16; var _ = f(undef)"
1154 fset := token.NewFileSet()
1155 f, err := parser.ParseFile(fset, "issue15305.go", src, 0)
1156 if err != nil {
1157 t.Fatal(err)
1159 conf := Config{
1160 Error: func(err error) {}, // allow errors
1162 info := &Info{
1163 Types: make(map[ast.Expr]TypeAndValue),
1165 conf.Check("p", fset, []*ast.File{f}, info) // ignore result
1166 for e, tv := range info.Types {
1167 if _, ok := e.(*ast.CallExpr); ok {
1168 if tv.Type != Typ[Int16] {
1169 t.Errorf("CallExpr has type %v, want int16", tv.Type)
1171 return
1174 t.Errorf("CallExpr has no type")
1177 // TestCompositeLitTypes verifies that Info.Types registers the correct
1178 // types for composite literal expressions and composite literal type
1179 // expressions.
1180 func TestCompositeLitTypes(t *testing.T) {
1181 for _, test := range []struct {
1182 lit, typ string
1184 {`[16]byte{}`, `[16]byte`},
1185 {`[...]byte{}`, `[0]byte`}, // test for issue #14092
1186 {`[...]int{1, 2, 3}`, `[3]int`}, // test for issue #14092
1187 {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092
1188 {`[]int{}`, `[]int`},
1189 {`map[string]bool{"foo": true}`, `map[string]bool`},
1190 {`struct{}{}`, `struct{}`},
1191 {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
1193 fset := token.NewFileSet()
1194 f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0)
1195 if err != nil {
1196 t.Fatalf("%s: %v", test.lit, err)
1199 info := &Info{
1200 Types: make(map[ast.Expr]TypeAndValue),
1202 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
1203 t.Fatalf("%s: %v", test.lit, err)
1206 cmptype := func(x ast.Expr, want string) {
1207 tv, ok := info.Types[x]
1208 if !ok {
1209 t.Errorf("%s: no Types entry found", test.lit)
1210 return
1212 if tv.Type == nil {
1213 t.Errorf("%s: type is nil", test.lit)
1214 return
1216 if got := tv.Type.String(); got != want {
1217 t.Errorf("%s: got %v, want %s", test.lit, got, want)
1221 // test type of composite literal expression
1222 rhs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0]
1223 cmptype(rhs, test.typ)
1225 // test type of composite literal type expression
1226 cmptype(rhs.(*ast.CompositeLit).Type, test.typ)
1230 // TestObjectParents verifies that objects have parent scopes or not
1231 // as specified by the Object interface.
1232 func TestObjectParents(t *testing.T) {
1233 const src = `
1234 package p
1236 const C = 0
1238 type T1 struct {
1239 a, b int
1243 type T2 interface {
1244 im1()
1245 im2()
1248 func (T1) m1() {}
1249 func (*T1) m2() {}
1251 func f(x int) { y := x; print(y) }
1254 fset := token.NewFileSet()
1255 f, err := parser.ParseFile(fset, "src", src, 0)
1256 if err != nil {
1257 t.Fatal(err)
1260 info := &Info{
1261 Defs: make(map[*ast.Ident]Object),
1263 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
1264 t.Fatal(err)
1267 for ident, obj := range info.Defs {
1268 if obj == nil {
1269 // only package names and implicit vars have a nil object
1270 // (in this test we only need to handle the package name)
1271 if ident.Name != "p" {
1272 t.Errorf("%v has nil object", ident)
1274 continue
1277 // struct fields, type-associated and interface methods
1278 // have no parent scope
1279 wantParent := true
1280 switch obj := obj.(type) {
1281 case *Var:
1282 if obj.IsField() {
1283 wantParent = false
1285 case *Func:
1286 if obj.Type().(*Signature).Recv() != nil { // method
1287 wantParent = false
1291 gotParent := obj.Parent() != nil
1292 switch {
1293 case gotParent && !wantParent:
1294 t.Errorf("%v: want no parent, got %s", ident, obj.Parent())
1295 case !gotParent && wantParent:
1296 t.Errorf("%v: no parent found", ident)
1301 // TestFailedImport tests that we don't get follow-on errors
1302 // elsewhere in a package due to failing to import a package.
1303 func TestFailedImport(t *testing.T) {
1304 testenv.MustHaveGoBuild(t)
1306 const src = `
1307 package p
1309 import "foo" // should only see an error here
1311 const c = foo.C
1312 type T = foo.T
1313 var v T = c
1314 func f(x T) T { return foo.F(x) }
1316 fset := token.NewFileSet()
1317 f, err := parser.ParseFile(fset, "src", src, 0)
1318 if err != nil {
1319 t.Fatal(err)
1321 files := []*ast.File{f}
1323 // type-check using all possible importers
1324 for _, compiler := range []string{"gc", "gccgo", "source"} {
1325 errcount := 0
1326 conf := Config{
1327 Error: func(err error) {
1328 // we should only see the import error
1329 if errcount > 0 || !strings.Contains(err.Error(), "could not import foo") {
1330 t.Errorf("for %s importer, got unexpected error: %v", compiler, err)
1332 errcount++
1334 Importer: importer.For(compiler, nil),
1337 info := &Info{
1338 Uses: make(map[*ast.Ident]Object),
1340 pkg, _ := conf.Check("p", fset, files, info)
1341 if pkg == nil {
1342 t.Errorf("for %s importer, type-checking failed to return a package", compiler)
1343 continue
1346 imports := pkg.Imports()
1347 if len(imports) != 1 {
1348 t.Errorf("for %s importer, got %d imports, want 1", compiler, len(imports))
1349 continue
1351 imp := imports[0]
1352 if imp.Name() != "foo" {
1353 t.Errorf(`for %s importer, got %q, want "foo"`, compiler, imp.Name())
1354 continue
1357 // verify that all uses of foo refer to the imported package foo (imp)
1358 for ident, obj := range info.Uses {
1359 if ident.Name == "foo" {
1360 if obj, ok := obj.(*PkgName); ok {
1361 if obj.Imported() != imp {
1362 t.Errorf("%s resolved to %v; want %v", ident, obj.Imported(), imp)
1364 } else {
1365 t.Errorf("%s resolved to %v; want package name", ident, obj)