github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/go/types/api_test.go (about) 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. 4 5 package types_test 6 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" 19 20 . "go/types" 21 ) 22 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 28 } 29 conf := Config{Importer: importer.Default()} 30 return conf.Check(f.Name.Name, fset, []*ast.File{f}, info) 31 } 32 33 func mustTypecheck(t *testing.T, path, source string, info *Info) string { 34 pkg, err := pkgFor(path, source, info) 35 if err != nil { 36 name := path 37 if pkg != nil { 38 name = "package " + pkg.Name() 39 } 40 t.Fatalf("%s: didn't type-check (%s)", name, err) 41 } 42 return pkg.Name() 43 } 44 45 func mayTypecheck(t *testing.T, path, source string, info *Info) string { 46 fset := token.NewFileSet() 47 f, err := parser.ParseFile(fset, path, source, 0) 48 if f == nil { // ignore errors unless f is nil 49 t.Fatalf("%s: unable to parse: %s", path, err) 50 } 51 conf := Config{ 52 Error: func(err error) {}, 53 Importer: importer.Default(), 54 } 55 pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, info) 56 return pkg.Name() 57 } 58 59 func TestValuesInfo(t *testing.T) { 60 var tests = []struct { 61 src string 62 expr string // constant expression 63 typ string // constant type 64 val string // constant value 65 }{ 66 {`package a0; const _ = false`, `false`, `untyped bool`, `false`}, 67 {`package a1; const _ = 0`, `0`, `untyped int`, `0`}, 68 {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`}, 69 {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`}, 70 {`package a4; const _ = 0i`, `0i`, `untyped complex`, `(0 + 0i)`}, 71 {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`}, 72 73 {`package b0; var _ = false`, `false`, `bool`, `false`}, 74 {`package b1; var _ = 0`, `0`, `int`, `0`}, 75 {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`}, 76 {`package b3; var _ = 0.`, `0.`, `float64`, `0`}, 77 {`package b4; var _ = 0i`, `0i`, `complex128`, `(0 + 0i)`}, 78 {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`}, 79 80 {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`}, 81 {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`}, 82 {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`}, 83 84 {`package c1a; var _ = int(0)`, `0`, `int`, `0`}, 85 {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`}, 86 {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`}, 87 88 {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`}, 89 {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`}, 90 {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`}, 91 92 {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`}, 93 {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`}, 94 {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`}, 95 96 {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `(0 + 0i)`}, 97 {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `(0 + 0i)`}, 98 {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `(0 + 0i)`}, 99 100 {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`}, 101 {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`}, 102 {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`}, 103 {`package c5d; var _ = string(65)`, `65`, `untyped int`, `65`}, 104 {`package c5e; var _ = string('A')`, `'A'`, `untyped rune`, `65`}, 105 {`package c5f; type T string; var _ = T('A')`, `'A'`, `untyped rune`, `65`}, 106 {`package c5g; var s uint; var _ = string(1 << s)`, `1 << s`, `untyped int`, ``}, 107 108 {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`}, 109 {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`}, 110 {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`}, 111 {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`}, 112 113 {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`}, 114 {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`}, 115 {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`}, 116 {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`}, 117 {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `(0 + 0i)`}, 118 {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `(0 + 0i)`}, 119 {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `(0 + 0i)`}, 120 {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `(0 + 0i)`}, 121 122 {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`}, 123 {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`}, 124 {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`}, 125 {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`}, 126 {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`}, 127 {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`}, 128 {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `(0 + 0i)`}, 129 {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `(0 + 0i)`}, 130 {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`}, 131 {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`}, 132 {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`}, 133 {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`}, 134 135 {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341 136 } 137 138 for _, test := range tests { 139 info := Info{ 140 Types: make(map[ast.Expr]TypeAndValue), 141 } 142 name := mustTypecheck(t, "ValuesInfo", test.src, &info) 143 144 // look for expression 145 var expr ast.Expr 146 for e := range info.Types { 147 if ExprString(e) == test.expr { 148 expr = e 149 break 150 } 151 } 152 if expr == nil { 153 t.Errorf("package %s: no expression found for %s", name, test.expr) 154 continue 155 } 156 tv := info.Types[expr] 157 158 // check that type is correct 159 if got := tv.Type.String(); got != test.typ { 160 t.Errorf("package %s: got type %s; want %s", name, got, test.typ) 161 continue 162 } 163 164 // if we have a constant, check that value is correct 165 if tv.Value != nil { 166 if got := tv.Value.ExactString(); got != test.val { 167 t.Errorf("package %s: got value %s; want %s", name, got, test.val) 168 } 169 } else { 170 if test.val != "" { 171 t.Errorf("package %s: no constant found; want %s", name, test.val) 172 } 173 } 174 } 175 } 176 177 func TestTypesInfo(t *testing.T) { 178 var tests = []struct { 179 src string 180 expr string // expression 181 typ string // value type 182 }{ 183 // single-valued expressions of untyped constants 184 {`package b0; var x interface{} = false`, `false`, `bool`}, 185 {`package b1; var x interface{} = 0`, `0`, `int`}, 186 {`package b2; var x interface{} = 0.`, `0.`, `float64`}, 187 {`package b3; var x interface{} = 0i`, `0i`, `complex128`}, 188 {`package b4; var x interface{} = "foo"`, `"foo"`, `string`}, 189 190 // comma-ok expressions 191 {`package p0; var x interface{}; var _, _ = x.(int)`, 192 `x.(int)`, 193 `(int, bool)`, 194 }, 195 {`package p1; var x interface{}; func _() { _, _ = x.(int) }`, 196 `x.(int)`, 197 `(int, bool)`, 198 }, 199 {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`, 200 `m["foo"]`, 201 `(complex128, p2a.mybool)`, 202 }, 203 {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`, 204 `m["foo"]`, 205 `(complex128, bool)`, 206 }, 207 {`package p3; var c chan string; var _, _ = <-c`, 208 `<-c`, 209 `(string, bool)`, 210 }, 211 212 // issue 6796 213 {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`, 214 `x.(int)`, 215 `(int, bool)`, 216 }, 217 {`package issue6796_b; var c chan string; var _, _ = (<-c)`, 218 `(<-c)`, 219 `(string, bool)`, 220 }, 221 {`package issue6796_c; var c chan string; var _, _ = (<-c)`, 222 `<-c`, 223 `(string, bool)`, 224 }, 225 {`package issue6796_d; var c chan string; var _, _ = ((<-c))`, 226 `(<-c)`, 227 `(string, bool)`, 228 }, 229 {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`, 230 `(<-c)`, 231 `(string, bool)`, 232 }, 233 234 // issue 7060 235 {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`, 236 `m[0]`, 237 `(string, bool)`, 238 }, 239 {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`, 240 `m[0]`, 241 `(string, bool)`, 242 }, 243 {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`, 244 `m[0]`, 245 `(string, bool)`, 246 }, 247 {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`, 248 `<-ch`, 249 `(string, bool)`, 250 }, 251 {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`, 252 `<-ch`, 253 `(string, bool)`, 254 }, 255 {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`, 256 `<-ch`, 257 `(string, bool)`, 258 }, 259 260 // issue 28277 261 {`package issue28277_a; func f(...int)`, 262 `...int`, 263 `[]int`, 264 }, 265 {`package issue28277_b; func f(a, b int, c ...[]struct{})`, 266 `...[]struct{}`, 267 `[][]struct{}`, 268 }, 269 270 // tests for broken code that doesn't parse or type-check 271 {`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`}, 272 {`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`}, 273 {`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`}, 274 {`package x3; var x = panic("");`, `panic`, `func(interface{})`}, 275 {`package x4; func _() { panic("") }`, `panic`, `func(interface{})`}, 276 {`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`}, 277 } 278 279 for _, test := range tests { 280 info := Info{Types: make(map[ast.Expr]TypeAndValue)} 281 name := mayTypecheck(t, "TypesInfo", test.src, &info) 282 283 // look for expression type 284 var typ Type 285 for e, tv := range info.Types { 286 if ExprString(e) == test.expr { 287 typ = tv.Type 288 break 289 } 290 } 291 if typ == nil { 292 t.Errorf("package %s: no type found for %s", name, test.expr) 293 continue 294 } 295 296 // check that type is correct 297 if got := typ.String(); got != test.typ { 298 t.Errorf("package %s: got %s; want %s", name, got, test.typ) 299 } 300 } 301 } 302 303 func TestImplicitsInfo(t *testing.T) { 304 testenv.MustHaveGoBuild(t) 305 306 var tests = []struct { 307 src string 308 want string 309 }{ 310 {`package p2; import . "fmt"; var _ = Println`, ""}, // no Implicits entry 311 {`package p0; import local "fmt"; var _ = local.Println`, ""}, // no Implicits entry 312 {`package p1; import "fmt"; var _ = fmt.Println`, "importSpec: package fmt"}, 313 314 {`package p3; func f(x interface{}) { switch x.(type) { case int: } }`, ""}, // no Implicits entry 315 {`package p4; func f(x interface{}) { switch t := x.(type) { case int: _ = t } }`, "caseClause: var t int"}, 316 {`package p5; func f(x interface{}) { switch t := x.(type) { case int, uint: _ = t } }`, "caseClause: var t interface{}"}, 317 {`package p6; func f(x interface{}) { switch t := x.(type) { default: _ = t } }`, "caseClause: var t interface{}"}, 318 319 {`package p7; func f(x int) {}`, ""}, // no Implicits entry 320 {`package p8; func f(int) {}`, "field: var int"}, 321 {`package p9; func f() (complex64) { return 0 }`, "field: var complex64"}, 322 {`package p10; type T struct{}; func (*T) f() {}`, "field: var *p10.T"}, 323 } 324 325 for _, test := range tests { 326 info := Info{ 327 Implicits: make(map[ast.Node]Object), 328 } 329 name := mustTypecheck(t, "ImplicitsInfo", test.src, &info) 330 331 // the test cases expect at most one Implicits entry 332 if len(info.Implicits) > 1 { 333 t.Errorf("package %s: %d Implicits entries found", name, len(info.Implicits)) 334 continue 335 } 336 337 // extract Implicits entry, if any 338 var got string 339 for n, obj := range info.Implicits { 340 switch x := n.(type) { 341 case *ast.ImportSpec: 342 got = "importSpec" 343 case *ast.CaseClause: 344 got = "caseClause" 345 case *ast.Field: 346 got = "field" 347 default: 348 t.Fatalf("package %s: unexpected %T", name, x) 349 } 350 got += ": " + obj.String() 351 } 352 353 // verify entry 354 if got != test.want { 355 t.Errorf("package %s: got %q; want %q", name, got, test.want) 356 } 357 } 358 } 359 360 func predString(tv TypeAndValue) string { 361 var buf bytes.Buffer 362 pred := func(b bool, s string) { 363 if b { 364 if buf.Len() > 0 { 365 buf.WriteString(", ") 366 } 367 buf.WriteString(s) 368 } 369 } 370 371 pred(tv.IsVoid(), "void") 372 pred(tv.IsType(), "type") 373 pred(tv.IsBuiltin(), "builtin") 374 pred(tv.IsValue() && tv.Value != nil, "const") 375 pred(tv.IsValue() && tv.Value == nil, "value") 376 pred(tv.IsNil(), "nil") 377 pred(tv.Addressable(), "addressable") 378 pred(tv.Assignable(), "assignable") 379 pred(tv.HasOk(), "hasOk") 380 381 if buf.Len() == 0 { 382 return "invalid" 383 } 384 return buf.String() 385 } 386 387 func TestPredicatesInfo(t *testing.T) { 388 testenv.MustHaveGoBuild(t) 389 390 var tests = []struct { 391 src string 392 expr string 393 pred string 394 }{ 395 // void 396 {`package n0; func f() { f() }`, `f()`, `void`}, 397 398 // types 399 {`package t0; type _ int`, `int`, `type`}, 400 {`package t1; type _ []int`, `[]int`, `type`}, 401 {`package t2; type _ func()`, `func()`, `type`}, 402 {`package t3; type _ func(int)`, `int`, `type`}, 403 {`package t3; type _ func(...int)`, `...int`, `type`}, 404 405 // built-ins 406 {`package b0; var _ = len("")`, `len`, `builtin`}, 407 {`package b1; var _ = (len)("")`, `(len)`, `builtin`}, 408 409 // constants 410 {`package c0; var _ = 42`, `42`, `const`}, 411 {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`}, 412 {`package c2; const (i = 1i; _ = i)`, `i`, `const`}, 413 414 // values 415 {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`}, 416 {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`}, 417 {`package v2; var _ = func(){}`, `(func() literal)`, `value`}, 418 {`package v4; func f() { _ = f }`, `f`, `value`}, 419 {`package v3; var _ *int = nil`, `nil`, `value, nil`}, 420 {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`}, 421 422 // addressable (and thus assignable) operands 423 {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`}, 424 {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`}, 425 {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`}, 426 {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`}, 427 {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`}, 428 {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`}, 429 {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`}, 430 {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`}, 431 // composite literals are not addressable 432 433 // assignable but not addressable values 434 {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, 435 {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, 436 437 // hasOk expressions 438 {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`}, 439 {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`}, 440 441 // missing entries 442 // - package names are collected in the Uses map 443 // - identifiers being declared are collected in the Defs map 444 {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`}, 445 {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`}, 446 {`package m2; const c = 0`, `c`, `<missing>`}, 447 {`package m3; type T int`, `T`, `<missing>`}, 448 {`package m4; var v int`, `v`, `<missing>`}, 449 {`package m5; func f() {}`, `f`, `<missing>`}, 450 {`package m6; func _(x int) {}`, `x`, `<missing>`}, 451 {`package m6; func _()(x int) { return }`, `x`, `<missing>`}, 452 {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`}, 453 } 454 455 for _, test := range tests { 456 info := Info{Types: make(map[ast.Expr]TypeAndValue)} 457 name := mustTypecheck(t, "PredicatesInfo", test.src, &info) 458 459 // look for expression predicates 460 got := "<missing>" 461 for e, tv := range info.Types { 462 //println(name, ExprString(e)) 463 if ExprString(e) == test.expr { 464 got = predString(tv) 465 break 466 } 467 } 468 469 if got != test.pred { 470 t.Errorf("package %s: got %s; want %s", name, got, test.pred) 471 } 472 } 473 } 474 475 func TestScopesInfo(t *testing.T) { 476 testenv.MustHaveGoBuild(t) 477 478 var tests = []struct { 479 src string 480 scopes []string // list of scope descriptors of the form kind:varlist 481 }{ 482 {`package p0`, []string{ 483 "file:", 484 }}, 485 {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{ 486 "file:fmt m", 487 }}, 488 {`package p2; func _() {}`, []string{ 489 "file:", "func:", 490 }}, 491 {`package p3; func _(x, y int) {}`, []string{ 492 "file:", "func:x y", 493 }}, 494 {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{ 495 "file:", "func:x y z", // redeclaration of x 496 }}, 497 {`package p5; func _(x, y int) (u, _ int) { return }`, []string{ 498 "file:", "func:u x y", 499 }}, 500 {`package p6; func _() { { var x int; _ = x } }`, []string{ 501 "file:", "func:", "block:x", 502 }}, 503 {`package p7; func _() { if true {} }`, []string{ 504 "file:", "func:", "if:", "block:", 505 }}, 506 {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{ 507 "file:", "func:", "if:x", "block:y", 508 }}, 509 {`package p9; func _() { switch x := 0; x {} }`, []string{ 510 "file:", "func:", "switch:x", 511 }}, 512 {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{ 513 "file:", "func:", "switch:x", "case:y", "case:", 514 }}, 515 {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{ 516 "file:", "func:t", "type switch:", 517 }}, 518 {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{ 519 "file:", "func:t", "type switch:t", 520 }}, 521 {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{ 522 "file:", "func:t", "type switch:", "case:x", // x implicitly declared 523 }}, 524 {`package p14; func _() { select{} }`, []string{ 525 "file:", "func:", 526 }}, 527 {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{ 528 "file:", "func:c", "comm:", 529 }}, 530 {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{ 531 "file:", "func:c", "comm:i x", 532 }}, 533 {`package p17; func _() { for{} }`, []string{ 534 "file:", "func:", "for:", "block:", 535 }}, 536 {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{ 537 "file:", "func:n", "for:i", "block:", 538 }}, 539 {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{ 540 "file:", "func:a", "range:i", "block:", 541 }}, 542 {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{ 543 "file:", "func:a", "range:i x", "block:", 544 }}, 545 } 546 547 for _, test := range tests { 548 info := Info{Scopes: make(map[ast.Node]*Scope)} 549 name := mustTypecheck(t, "ScopesInfo", test.src, &info) 550 551 // number of scopes must match 552 if len(info.Scopes) != len(test.scopes) { 553 t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes)) 554 } 555 556 // scope descriptions must match 557 for node, scope := range info.Scopes { 558 kind := "<unknown node kind>" 559 switch node.(type) { 560 case *ast.File: 561 kind = "file" 562 case *ast.FuncType: 563 kind = "func" 564 case *ast.BlockStmt: 565 kind = "block" 566 case *ast.IfStmt: 567 kind = "if" 568 case *ast.SwitchStmt: 569 kind = "switch" 570 case *ast.TypeSwitchStmt: 571 kind = "type switch" 572 case *ast.CaseClause: 573 kind = "case" 574 case *ast.CommClause: 575 kind = "comm" 576 case *ast.ForStmt: 577 kind = "for" 578 case *ast.RangeStmt: 579 kind = "range" 580 } 581 582 // look for matching scope description 583 desc := kind + ":" + strings.Join(scope.Names(), " ") 584 found := false 585 for _, d := range test.scopes { 586 if desc == d { 587 found = true 588 break 589 } 590 } 591 if !found { 592 t.Errorf("package %s: no matching scope found for %s", name, desc) 593 } 594 } 595 } 596 } 597 598 func TestInitOrderInfo(t *testing.T) { 599 var tests = []struct { 600 src string 601 inits []string 602 }{ 603 {`package p0; var (x = 1; y = x)`, []string{ 604 "x = 1", "y = x", 605 }}, 606 {`package p1; var (a = 1; b = 2; c = 3)`, []string{ 607 "a = 1", "b = 2", "c = 3", 608 }}, 609 {`package p2; var (a, b, c = 1, 2, 3)`, []string{ 610 "a = 1", "b = 2", "c = 3", 611 }}, 612 {`package p3; var _ = f(); func f() int { return 1 }`, []string{ 613 "_ = f()", // blank var 614 }}, 615 {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{ 616 "a = 0", "z = 0", "y = z", "x = y", 617 }}, 618 {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{ 619 "a, _ = m[0]", // blank var 620 }}, 621 {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{ 622 "z = 0", "a, b = f()", 623 }}, 624 {`package p7; var (a = func() int { return b }(); b = 1)`, []string{ 625 "b = 1", "a = (func() int literal)()", 626 }}, 627 {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{ 628 "c = 1", "a, b = (func() (_, _ int) literal)()", 629 }}, 630 {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{ 631 "y = 1", "x = T.m", 632 }}, 633 {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{ 634 "a = 0", "b = 0", "c = 0", "d = c + b", 635 }}, 636 {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{ 637 "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c", 638 }}, 639 // emit an initializer for n:1 initializations only once (not for each node 640 // on the lhs which may appear in different order in the dependency graph) 641 {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{ 642 "b = 0", "x, y = m[0]", "a = x", 643 }}, 644 // test case from spec section on package initialization 645 {`package p12 646 647 var ( 648 a = c + b 649 b = f() 650 c = f() 651 d = 3 652 ) 653 654 func f() int { 655 d++ 656 return d 657 }`, []string{ 658 "d = 3", "b = f()", "c = f()", "a = c + b", 659 }}, 660 // test case for issue 7131 661 {`package main 662 663 var counter int 664 func next() int { counter++; return counter } 665 666 var _ = makeOrder() 667 func makeOrder() []int { return []int{f, b, d, e, c, a} } 668 669 var a = next() 670 var b, c = next(), next() 671 var d, e, f = next(), next(), next() 672 `, []string{ 673 "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()", 674 }}, 675 // test case for issue 10709 676 {`package p13 677 678 var ( 679 v = t.m() 680 t = makeT(0) 681 ) 682 683 type T struct{} 684 685 func (T) m() int { return 0 } 686 687 func makeT(n int) T { 688 if n > 0 { 689 return makeT(n-1) 690 } 691 return T{} 692 }`, []string{ 693 "t = makeT(0)", "v = t.m()", 694 }}, 695 // test case for issue 10709: same as test before, but variable decls swapped 696 {`package p14 697 698 var ( 699 t = makeT(0) 700 v = t.m() 701 ) 702 703 type T struct{} 704 705 func (T) m() int { return 0 } 706 707 func makeT(n int) T { 708 if n > 0 { 709 return makeT(n-1) 710 } 711 return T{} 712 }`, []string{ 713 "t = makeT(0)", "v = t.m()", 714 }}, 715 // another candidate possibly causing problems with issue 10709 716 {`package p15 717 718 var y1 = f1() 719 720 func f1() int { return g1() } 721 func g1() int { f1(); return x1 } 722 723 var x1 = 0 724 725 var y2 = f2() 726 727 func f2() int { return g2() } 728 func g2() int { return x2 } 729 730 var x2 = 0`, []string{ 731 "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()", 732 }}, 733 } 734 735 for _, test := range tests { 736 info := Info{} 737 name := mustTypecheck(t, "InitOrderInfo", test.src, &info) 738 739 // number of initializers must match 740 if len(info.InitOrder) != len(test.inits) { 741 t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits)) 742 continue 743 } 744 745 // initializers must match 746 for i, want := range test.inits { 747 got := info.InitOrder[i].String() 748 if got != want { 749 t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want) 750 continue 751 } 752 } 753 } 754 } 755 756 func TestMultiFileInitOrder(t *testing.T) { 757 fset := token.NewFileSet() 758 mustParse := func(src string) *ast.File { 759 f, err := parser.ParseFile(fset, "main", src, 0) 760 if err != nil { 761 t.Fatal(err) 762 } 763 return f 764 } 765 766 fileA := mustParse(`package main; var a = 1`) 767 fileB := mustParse(`package main; var b = 2`) 768 769 // The initialization order must not depend on the parse 770 // order of the files, only on the presentation order to 771 // the type-checker. 772 for _, test := range []struct { 773 files []*ast.File 774 want string 775 }{ 776 {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"}, 777 {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"}, 778 } { 779 var info Info 780 if _, err := new(Config).Check("main", fset, test.files, &info); err != nil { 781 t.Fatal(err) 782 } 783 if got := fmt.Sprint(info.InitOrder); got != test.want { 784 t.Fatalf("got %s; want %s", got, test.want) 785 } 786 } 787 } 788 789 func TestFiles(t *testing.T) { 790 var sources = []string{ 791 "package p; type T struct{}; func (T) m1() {}", 792 "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}", 793 "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}", 794 "package p", 795 } 796 797 var conf Config 798 fset := token.NewFileSet() 799 pkg := NewPackage("p", "p") 800 var info Info 801 check := NewChecker(&conf, fset, pkg, &info) 802 803 for i, src := range sources { 804 filename := fmt.Sprintf("sources%d", i) 805 f, err := parser.ParseFile(fset, filename, src, 0) 806 if err != nil { 807 t.Fatal(err) 808 } 809 if err := check.Files([]*ast.File{f}); err != nil { 810 t.Error(err) 811 } 812 } 813 814 // check InitOrder is [x y] 815 var vars []string 816 for _, init := range info.InitOrder { 817 for _, v := range init.Lhs { 818 vars = append(vars, v.Name()) 819 } 820 } 821 if got, want := fmt.Sprint(vars), "[x y]"; got != want { 822 t.Errorf("InitOrder == %s, want %s", got, want) 823 } 824 } 825 826 type testImporter map[string]*Package 827 828 func (m testImporter) Import(path string) (*Package, error) { 829 if pkg := m[path]; pkg != nil { 830 return pkg, nil 831 } 832 return nil, fmt.Errorf("package %q not found", path) 833 } 834 835 func TestSelection(t *testing.T) { 836 selections := make(map[*ast.SelectorExpr]*Selection) 837 838 fset := token.NewFileSet() 839 imports := make(testImporter) 840 conf := Config{Importer: imports} 841 makePkg := func(path, src string) { 842 f, err := parser.ParseFile(fset, path+".go", src, 0) 843 if err != nil { 844 t.Fatal(err) 845 } 846 pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections}) 847 if err != nil { 848 t.Fatal(err) 849 } 850 imports[path] = pkg 851 } 852 853 const libSrc = ` 854 package lib 855 type T float64 856 const C T = 3 857 var V T 858 func F() {} 859 func (T) M() {} 860 ` 861 const mainSrc = ` 862 package main 863 import "lib" 864 865 type A struct { 866 *B 867 C 868 } 869 870 type B struct { 871 b int 872 } 873 874 func (B) f(int) 875 876 type C struct { 877 c int 878 } 879 880 func (C) g() 881 func (*C) h() 882 883 func main() { 884 // qualified identifiers 885 var _ lib.T 886 _ = lib.C 887 _ = lib.F 888 _ = lib.V 889 _ = lib.T.M 890 891 // fields 892 _ = A{}.B 893 _ = new(A).B 894 895 _ = A{}.C 896 _ = new(A).C 897 898 _ = A{}.b 899 _ = new(A).b 900 901 _ = A{}.c 902 _ = new(A).c 903 904 // methods 905 _ = A{}.f 906 _ = new(A).f 907 _ = A{}.g 908 _ = new(A).g 909 _ = new(A).h 910 911 _ = B{}.f 912 _ = new(B).f 913 914 _ = C{}.g 915 _ = new(C).g 916 _ = new(C).h 917 918 // method expressions 919 _ = A.f 920 _ = (*A).f 921 _ = B.f 922 _ = (*B).f 923 }` 924 925 wantOut := map[string][2]string{ 926 "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"}, 927 928 "A{}.B": {"field (main.A) B *main.B", ".[0]"}, 929 "new(A).B": {"field (*main.A) B *main.B", "->[0]"}, 930 "A{}.C": {"field (main.A) C main.C", ".[1]"}, 931 "new(A).C": {"field (*main.A) C main.C", "->[1]"}, 932 "A{}.b": {"field (main.A) b int", "->[0 0]"}, 933 "new(A).b": {"field (*main.A) b int", "->[0 0]"}, 934 "A{}.c": {"field (main.A) c int", ".[1 0]"}, 935 "new(A).c": {"field (*main.A) c int", "->[1 0]"}, 936 937 "A{}.f": {"method (main.A) f(int)", "->[0 0]"}, 938 "new(A).f": {"method (*main.A) f(int)", "->[0 0]"}, 939 "A{}.g": {"method (main.A) g()", ".[1 0]"}, 940 "new(A).g": {"method (*main.A) g()", "->[1 0]"}, 941 "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ? 942 "B{}.f": {"method (main.B) f(int)", ".[0]"}, 943 "new(B).f": {"method (*main.B) f(int)", "->[0]"}, 944 "C{}.g": {"method (main.C) g()", ".[0]"}, 945 "new(C).g": {"method (*main.C) g()", "->[0]"}, 946 "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ? 947 948 "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"}, 949 "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"}, 950 "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"}, 951 "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"}, 952 } 953 954 makePkg("lib", libSrc) 955 makePkg("main", mainSrc) 956 957 for e, sel := range selections { 958 _ = sel.String() // assertion: must not panic 959 960 start := fset.Position(e.Pos()).Offset 961 end := fset.Position(e.End()).Offset 962 syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib) 963 964 direct := "." 965 if sel.Indirect() { 966 direct = "->" 967 } 968 got := [2]string{ 969 sel.String(), 970 fmt.Sprintf("%s%v", direct, sel.Index()), 971 } 972 want := wantOut[syntax] 973 if want != got { 974 t.Errorf("%s: got %q; want %q", syntax, got, want) 975 } 976 delete(wantOut, syntax) 977 978 // We must explicitly assert properties of the 979 // Signature's receiver since it doesn't participate 980 // in Identical() or String(). 981 sig, _ := sel.Type().(*Signature) 982 if sel.Kind() == MethodVal { 983 got := sig.Recv().Type() 984 want := sel.Recv() 985 if !Identical(got, want) { 986 t.Errorf("%s: Recv() = %s, want %s", syntax, got, want) 987 } 988 } else if sig != nil && sig.Recv() != nil { 989 t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type()) 990 } 991 } 992 // Assert that all wantOut entries were used exactly once. 993 for syntax := range wantOut { 994 t.Errorf("no ast.Selection found with syntax %q", syntax) 995 } 996 } 997 998 func TestIssue8518(t *testing.T) { 999 fset := token.NewFileSet() 1000 imports := make(testImporter) 1001 conf := Config{ 1002 Error: func(err error) { t.Log(err) }, // don't exit after first error 1003 Importer: imports, 1004 } 1005 makePkg := func(path, src string) { 1006 f, err := parser.ParseFile(fset, path, src, 0) 1007 if err != nil { 1008 t.Fatal(err) 1009 } 1010 pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error 1011 imports[path] = pkg 1012 } 1013 1014 const libSrc = ` 1015 package a 1016 import "missing" 1017 const C1 = foo 1018 const C2 = missing.C 1019 ` 1020 1021 const mainSrc = ` 1022 package main 1023 import "a" 1024 var _ = a.C1 1025 var _ = a.C2 1026 ` 1027 1028 makePkg("a", libSrc) 1029 makePkg("main", mainSrc) // don't crash when type-checking this package 1030 } 1031 1032 func TestLookupFieldOrMethod(t *testing.T) { 1033 // Test cases assume a lookup of the form a.f or x.f, where a stands for an 1034 // addressable value, and x for a non-addressable value (even though a variable 1035 // for ease of test case writing). 1036 var tests = []struct { 1037 src string 1038 found bool 1039 index []int 1040 indirect bool 1041 }{ 1042 // field lookups 1043 {"var x T; type T struct{}", false, nil, false}, 1044 {"var x T; type T struct{ f int }", true, []int{0}, false}, 1045 {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false}, 1046 1047 // method lookups 1048 {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false}, 1049 {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true}, 1050 {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false}, 1051 {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false? 1052 1053 // collisions 1054 {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false}, 1055 {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false}, 1056 1057 // outside methodset 1058 // (*T).f method exists, but value of type T is not addressable 1059 {"var x T; type T struct{}; func (*T) f() {}", false, nil, true}, 1060 } 1061 1062 for _, test := range tests { 1063 pkg, err := pkgFor("test", "package p;"+test.src, nil) 1064 if err != nil { 1065 t.Errorf("%s: incorrect test case: %s", test.src, err) 1066 continue 1067 } 1068 1069 obj := pkg.Scope().Lookup("a") 1070 if obj == nil { 1071 if obj = pkg.Scope().Lookup("x"); obj == nil { 1072 t.Errorf("%s: incorrect test case - no object a or x", test.src) 1073 continue 1074 } 1075 } 1076 1077 f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f") 1078 if (f != nil) != test.found { 1079 if f == nil { 1080 t.Errorf("%s: got no object; want one", test.src) 1081 } else { 1082 t.Errorf("%s: got object = %v; want none", test.src, f) 1083 } 1084 } 1085 if !sameSlice(index, test.index) { 1086 t.Errorf("%s: got index = %v; want %v", test.src, index, test.index) 1087 } 1088 if indirect != test.indirect { 1089 t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect) 1090 } 1091 } 1092 } 1093 1094 func sameSlice(a, b []int) bool { 1095 if len(a) != len(b) { 1096 return false 1097 } 1098 for i, x := range a { 1099 if x != b[i] { 1100 return false 1101 } 1102 } 1103 return true 1104 } 1105 1106 // TestScopeLookupParent ensures that (*Scope).LookupParent returns 1107 // the correct result at various positions with the source. 1108 func TestScopeLookupParent(t *testing.T) { 1109 fset := token.NewFileSet() 1110 imports := make(testImporter) 1111 conf := Config{Importer: imports} 1112 mustParse := func(src string) *ast.File { 1113 f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments) 1114 if err != nil { 1115 t.Fatal(err) 1116 } 1117 return f 1118 } 1119 var info Info 1120 makePkg := func(path string, files ...*ast.File) { 1121 var err error 1122 imports[path], err = conf.Check(path, fset, files, &info) 1123 if err != nil { 1124 t.Fatal(err) 1125 } 1126 } 1127 1128 makePkg("lib", mustParse("package lib; var X int")) 1129 // Each /*name=kind:line*/ comment makes the test look up the 1130 // name at that point and checks that it resolves to a decl of 1131 // the specified kind and line number. "undef" means undefined. 1132 mainSrc := ` 1133 /*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/ 1134 package main 1135 1136 import "lib" 1137 import . "lib" 1138 1139 const Pi = 3.1415 1140 type T struct{} 1141 var Y, _ = lib.X, X 1142 1143 func F(){ 1144 const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/ 1145 type /*t=undef*/ t /*t=typename:14*/ *t 1146 print(Y) /*Y=var:10*/ 1147 x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y 1148 var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F 1149 1150 var a []int 1151 for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x } 1152 1153 var i interface{} 1154 switch y := i.(type) { /*y=undef*/ 1155 case /*y=undef*/ int /*y=var:23*/ : 1156 case float32, /*y=undef*/ float64 /*y=var:23*/ : 1157 default /*y=var:23*/: 1158 println(y) 1159 } 1160 /*y=undef*/ 1161 1162 switch int := i.(type) { 1163 case /*int=typename:0*/ int /*int=var:31*/ : 1164 println(int) 1165 default /*int=var:31*/ : 1166 } 1167 } 1168 /*main=undef*/ 1169 ` 1170 1171 info.Uses = make(map[*ast.Ident]Object) 1172 f := mustParse(mainSrc) 1173 makePkg("main", f) 1174 mainScope := imports["main"].Scope() 1175 rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`) 1176 for _, group := range f.Comments { 1177 for _, comment := range group.List { 1178 // Parse the assertion in the comment. 1179 m := rx.FindStringSubmatch(comment.Text) 1180 if m == nil { 1181 t.Errorf("%s: bad comment: %s", 1182 fset.Position(comment.Pos()), comment.Text) 1183 continue 1184 } 1185 name, want := m[1], m[2] 1186 1187 // Look up the name in the innermost enclosing scope. 1188 inner := mainScope.Innermost(comment.Pos()) 1189 if inner == nil { 1190 t.Errorf("%s: at %s: can't find innermost scope", 1191 fset.Position(comment.Pos()), comment.Text) 1192 continue 1193 } 1194 got := "undef" 1195 if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil { 1196 kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) 1197 got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line) 1198 } 1199 if got != want { 1200 t.Errorf("%s: at %s: %s resolved to %s, want %s", 1201 fset.Position(comment.Pos()), comment.Text, name, got, want) 1202 } 1203 } 1204 } 1205 1206 // Check that for each referring identifier, 1207 // a lookup of its name on the innermost 1208 // enclosing scope returns the correct object. 1209 1210 for id, wantObj := range info.Uses { 1211 inner := mainScope.Innermost(id.Pos()) 1212 if inner == nil { 1213 t.Errorf("%s: can't find innermost scope enclosing %q", 1214 fset.Position(id.Pos()), id.Name) 1215 continue 1216 } 1217 1218 // Exclude selectors and qualified identifiers---lexical 1219 // refs only. (Ideally, we'd see if the AST parent is a 1220 // SelectorExpr, but that requires PathEnclosingInterval 1221 // from golang.org/x/tools/go/ast/astutil.) 1222 if id.Name == "X" { 1223 continue 1224 } 1225 1226 _, gotObj := inner.LookupParent(id.Name, id.Pos()) 1227 if gotObj != wantObj { 1228 t.Errorf("%s: got %v, want %v", 1229 fset.Position(id.Pos()), gotObj, wantObj) 1230 continue 1231 } 1232 } 1233 } 1234 1235 func TestIdentical_issue15173(t *testing.T) { 1236 // Identical should allow nil arguments and be symmetric. 1237 for _, test := range []struct { 1238 x, y Type 1239 want bool 1240 }{ 1241 {Typ[Int], Typ[Int], true}, 1242 {Typ[Int], nil, false}, 1243 {nil, Typ[Int], false}, 1244 {nil, nil, true}, 1245 } { 1246 if got := Identical(test.x, test.y); got != test.want { 1247 t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got) 1248 } 1249 } 1250 } 1251 1252 func TestIssue15305(t *testing.T) { 1253 const src = "package p; func f() int16; var _ = f(undef)" 1254 fset := token.NewFileSet() 1255 f, err := parser.ParseFile(fset, "issue15305.go", src, 0) 1256 if err != nil { 1257 t.Fatal(err) 1258 } 1259 conf := Config{ 1260 Error: func(err error) {}, // allow errors 1261 } 1262 info := &Info{ 1263 Types: make(map[ast.Expr]TypeAndValue), 1264 } 1265 conf.Check("p", fset, []*ast.File{f}, info) // ignore result 1266 for e, tv := range info.Types { 1267 if _, ok := e.(*ast.CallExpr); ok { 1268 if tv.Type != Typ[Int16] { 1269 t.Errorf("CallExpr has type %v, want int16", tv.Type) 1270 } 1271 return 1272 } 1273 } 1274 t.Errorf("CallExpr has no type") 1275 } 1276 1277 // TestCompositeLitTypes verifies that Info.Types registers the correct 1278 // types for composite literal expressions and composite literal type 1279 // expressions. 1280 func TestCompositeLitTypes(t *testing.T) { 1281 for _, test := range []struct { 1282 lit, typ string 1283 }{ 1284 {`[16]byte{}`, `[16]byte`}, 1285 {`[...]byte{}`, `[0]byte`}, // test for issue #14092 1286 {`[...]int{1, 2, 3}`, `[3]int`}, // test for issue #14092 1287 {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092 1288 {`[]int{}`, `[]int`}, 1289 {`map[string]bool{"foo": true}`, `map[string]bool`}, 1290 {`struct{}{}`, `struct{}`}, 1291 {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`}, 1292 } { 1293 fset := token.NewFileSet() 1294 f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0) 1295 if err != nil { 1296 t.Fatalf("%s: %v", test.lit, err) 1297 } 1298 1299 info := &Info{ 1300 Types: make(map[ast.Expr]TypeAndValue), 1301 } 1302 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil { 1303 t.Fatalf("%s: %v", test.lit, err) 1304 } 1305 1306 cmptype := func(x ast.Expr, want string) { 1307 tv, ok := info.Types[x] 1308 if !ok { 1309 t.Errorf("%s: no Types entry found", test.lit) 1310 return 1311 } 1312 if tv.Type == nil { 1313 t.Errorf("%s: type is nil", test.lit) 1314 return 1315 } 1316 if got := tv.Type.String(); got != want { 1317 t.Errorf("%s: got %v, want %s", test.lit, got, want) 1318 } 1319 } 1320 1321 // test type of composite literal expression 1322 rhs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0] 1323 cmptype(rhs, test.typ) 1324 1325 // test type of composite literal type expression 1326 cmptype(rhs.(*ast.CompositeLit).Type, test.typ) 1327 } 1328 } 1329 1330 // TestObjectParents verifies that objects have parent scopes or not 1331 // as specified by the Object interface. 1332 func TestObjectParents(t *testing.T) { 1333 const src = ` 1334 package p 1335 1336 const C = 0 1337 1338 type T1 struct { 1339 a, b int 1340 T2 1341 } 1342 1343 type T2 interface { 1344 im1() 1345 im2() 1346 } 1347 1348 func (T1) m1() {} 1349 func (*T1) m2() {} 1350 1351 func f(x int) { y := x; print(y) } 1352 ` 1353 1354 fset := token.NewFileSet() 1355 f, err := parser.ParseFile(fset, "src", src, 0) 1356 if err != nil { 1357 t.Fatal(err) 1358 } 1359 1360 info := &Info{ 1361 Defs: make(map[*ast.Ident]Object), 1362 } 1363 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil { 1364 t.Fatal(err) 1365 } 1366 1367 for ident, obj := range info.Defs { 1368 if obj == nil { 1369 // only package names and implicit vars have a nil object 1370 // (in this test we only need to handle the package name) 1371 if ident.Name != "p" { 1372 t.Errorf("%v has nil object", ident) 1373 } 1374 continue 1375 } 1376 1377 // struct fields, type-associated and interface methods 1378 // have no parent scope 1379 wantParent := true 1380 switch obj := obj.(type) { 1381 case *Var: 1382 if obj.IsField() { 1383 wantParent = false 1384 } 1385 case *Func: 1386 if obj.Type().(*Signature).Recv() != nil { // method 1387 wantParent = false 1388 } 1389 } 1390 1391 gotParent := obj.Parent() != nil 1392 switch { 1393 case gotParent && !wantParent: 1394 t.Errorf("%v: want no parent, got %s", ident, obj.Parent()) 1395 case !gotParent && wantParent: 1396 t.Errorf("%v: no parent found", ident) 1397 } 1398 } 1399 } 1400 1401 // TestFailedImport tests that we don't get follow-on errors 1402 // elsewhere in a package due to failing to import a package. 1403 func TestFailedImport(t *testing.T) { 1404 testenv.MustHaveGoBuild(t) 1405 1406 const src = ` 1407 package p 1408 1409 import foo "go/types/thisdirectorymustnotexistotherwisethistestmayfail/foo" // should only see an error here 1410 1411 const c = foo.C 1412 type T = foo.T 1413 var v T = c 1414 func f(x T) T { return foo.F(x) } 1415 ` 1416 fset := token.NewFileSet() 1417 f, err := parser.ParseFile(fset, "src", src, 0) 1418 if err != nil { 1419 t.Fatal(err) 1420 } 1421 files := []*ast.File{f} 1422 1423 // type-check using all possible importers 1424 for _, compiler := range []string{"gc", "gccgo", "source"} { 1425 errcount := 0 1426 conf := Config{ 1427 Error: func(err error) { 1428 // we should only see the import error 1429 if errcount > 0 || !strings.Contains(err.Error(), "could not import") { 1430 t.Errorf("for %s importer, got unexpected error: %v", compiler, err) 1431 } 1432 errcount++ 1433 }, 1434 Importer: importer.For(compiler, nil), 1435 } 1436 1437 info := &Info{ 1438 Uses: make(map[*ast.Ident]Object), 1439 } 1440 pkg, _ := conf.Check("p", fset, files, info) 1441 if pkg == nil { 1442 t.Errorf("for %s importer, type-checking failed to return a package", compiler) 1443 continue 1444 } 1445 1446 imports := pkg.Imports() 1447 if len(imports) != 1 { 1448 t.Errorf("for %s importer, got %d imports, want 1", compiler, len(imports)) 1449 continue 1450 } 1451 imp := imports[0] 1452 if imp.Name() != "foo" { 1453 t.Errorf(`for %s importer, got %q, want "foo"`, compiler, imp.Name()) 1454 continue 1455 } 1456 1457 // verify that all uses of foo refer to the imported package foo (imp) 1458 for ident, obj := range info.Uses { 1459 if ident.Name == "foo" { 1460 if obj, ok := obj.(*PkgName); ok { 1461 if obj.Imported() != imp { 1462 t.Errorf("%s resolved to %v; want %v", ident, obj.Imported(), imp) 1463 } 1464 } else { 1465 t.Errorf("%s resolved to %v; want package name", ident, obj) 1466 } 1467 } 1468 } 1469 } 1470 }