github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/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 "runtime" 15 "strings" 16 "testing" 17 18 . "go/types" 19 ) 20 21 // skipSpecialPlatforms causes the test to be skipped for platforms where 22 // builders (build.golang.org) don't have access to compiled packages for 23 // import. 24 func skipSpecialPlatforms(t *testing.T) { 25 switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform { 26 case "nacl-amd64p32", 27 "nacl-386", 28 "darwin-arm", 29 "darwin-arm64": 30 t.Skipf("no compiled packages available for import on %s", platform) 31 } 32 } 33 34 func pkgFor(path, source string, info *Info) (*Package, error) { 35 fset := token.NewFileSet() 36 f, err := parser.ParseFile(fset, path, source, 0) 37 if err != nil { 38 return nil, err 39 } 40 41 conf := Config{Importer: importer.Default()} 42 return conf.Check(f.Name.Name, fset, []*ast.File{f}, info) 43 } 44 45 func mustTypecheck(t *testing.T, path, source string, info *Info) string { 46 pkg, err := pkgFor(path, source, info) 47 if err != nil { 48 name := path 49 if pkg != nil { 50 name = "package " + pkg.Name() 51 } 52 t.Fatalf("%s: didn't type-check (%s)", name, err) 53 } 54 return pkg.Name() 55 } 56 57 func TestValuesInfo(t *testing.T) { 58 var tests = []struct { 59 src string 60 expr string // constant expression 61 typ string // constant type 62 val string // constant value 63 }{ 64 {`package a0; const _ = false`, `false`, `untyped bool`, `false`}, 65 {`package a1; const _ = 0`, `0`, `untyped int`, `0`}, 66 {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`}, 67 {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`}, 68 {`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`}, 69 {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`}, 70 71 {`package b0; var _ = false`, `false`, `bool`, `false`}, 72 {`package b1; var _ = 0`, `0`, `int`, `0`}, 73 {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`}, 74 {`package b3; var _ = 0.`, `0.`, `float64`, `0`}, 75 {`package b4; var _ = 0i`, `0i`, `complex128`, `0`}, 76 {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`}, 77 78 {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`}, 79 {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`}, 80 {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`}, 81 82 {`package c1a; var _ = int(0)`, `0`, `int`, `0`}, 83 {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`}, 84 {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`}, 85 86 {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`}, 87 {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`}, 88 {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`}, 89 90 {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`}, 91 {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`}, 92 {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`}, 93 94 {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`}, 95 {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`}, 96 {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`}, 97 98 {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`}, 99 {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`}, 100 {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`}, 101 102 {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`}, 103 {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`}, 104 {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`}, 105 {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`}, 106 107 {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`}, 108 {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`}, 109 {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`}, 110 {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`}, 111 {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`}, 112 {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`}, 113 {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`}, 114 {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`}, 115 116 {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`}, 117 {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`}, 118 {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`}, 119 {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`}, 120 {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`}, 121 {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`}, 122 {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `0`}, 123 {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `0`}, 124 {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `0`}, 125 {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`}, 126 {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `0`}, 127 {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `0`}, 128 } 129 130 for _, test := range tests { 131 info := Info{ 132 Types: make(map[ast.Expr]TypeAndValue), 133 } 134 name := mustTypecheck(t, "ValuesInfo", test.src, &info) 135 136 // look for constant expression 137 var expr ast.Expr 138 for e := range info.Types { 139 if ExprString(e) == test.expr { 140 expr = e 141 break 142 } 143 } 144 if expr == nil { 145 t.Errorf("package %s: no expression found for %s", name, test.expr) 146 continue 147 } 148 tv := info.Types[expr] 149 150 // check that type is correct 151 if got := tv.Type.String(); got != test.typ { 152 t.Errorf("package %s: got type %s; want %s", name, got, test.typ) 153 continue 154 } 155 156 // check that value is correct 157 if got := tv.Value.String(); got != test.val { 158 t.Errorf("package %s: got value %s; want %s", name, got, test.val) 159 } 160 } 161 } 162 163 func TestTypesInfo(t *testing.T) { 164 var tests = []struct { 165 src string 166 expr string // expression 167 typ string // value type 168 }{ 169 // single-valued expressions of untyped constants 170 {`package b0; var x interface{} = false`, `false`, `bool`}, 171 {`package b1; var x interface{} = 0`, `0`, `int`}, 172 {`package b2; var x interface{} = 0.`, `0.`, `float64`}, 173 {`package b3; var x interface{} = 0i`, `0i`, `complex128`}, 174 {`package b4; var x interface{} = "foo"`, `"foo"`, `string`}, 175 176 // comma-ok expressions 177 {`package p0; var x interface{}; var _, _ = x.(int)`, 178 `x.(int)`, 179 `(int, bool)`, 180 }, 181 {`package p1; var x interface{}; func _() { _, _ = x.(int) }`, 182 `x.(int)`, 183 `(int, bool)`, 184 }, 185 // TODO(gri): uncomment if we accept issue 8189. 186 // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`, 187 // `m["foo"]`, 188 // `(complex128, p2.mybool)`, 189 // }, 190 // TODO(gri): remove if we accept issue 8189. 191 {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`, 192 `m["foo"]`, 193 `(complex128, bool)`, 194 }, 195 {`package p3; var c chan string; var _, _ = <-c`, 196 `<-c`, 197 `(string, bool)`, 198 }, 199 200 // issue 6796 201 {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`, 202 `x.(int)`, 203 `(int, bool)`, 204 }, 205 {`package issue6796_b; var c chan string; var _, _ = (<-c)`, 206 `(<-c)`, 207 `(string, bool)`, 208 }, 209 {`package issue6796_c; var c chan string; var _, _ = (<-c)`, 210 `<-c`, 211 `(string, bool)`, 212 }, 213 {`package issue6796_d; var c chan string; var _, _ = ((<-c))`, 214 `(<-c)`, 215 `(string, bool)`, 216 }, 217 {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`, 218 `(<-c)`, 219 `(string, bool)`, 220 }, 221 222 // issue 7060 223 {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`, 224 `m[0]`, 225 `(string, bool)`, 226 }, 227 {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`, 228 `m[0]`, 229 `(string, bool)`, 230 }, 231 {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`, 232 `m[0]`, 233 `(string, bool)`, 234 }, 235 {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`, 236 `<-ch`, 237 `(string, bool)`, 238 }, 239 {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`, 240 `<-ch`, 241 `(string, bool)`, 242 }, 243 {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`, 244 `<-ch`, 245 `(string, bool)`, 246 }, 247 } 248 249 for _, test := range tests { 250 info := Info{Types: make(map[ast.Expr]TypeAndValue)} 251 name := mustTypecheck(t, "TypesInfo", test.src, &info) 252 253 // look for expression type 254 var typ Type 255 for e, tv := range info.Types { 256 if ExprString(e) == test.expr { 257 typ = tv.Type 258 break 259 } 260 } 261 if typ == nil { 262 t.Errorf("package %s: no type found for %s", name, test.expr) 263 continue 264 } 265 266 // check that type is correct 267 if got := typ.String(); got != test.typ { 268 t.Errorf("package %s: got %s; want %s", name, got, test.typ) 269 } 270 } 271 } 272 273 func predString(tv TypeAndValue) string { 274 var buf bytes.Buffer 275 pred := func(b bool, s string) { 276 if b { 277 if buf.Len() > 0 { 278 buf.WriteString(", ") 279 } 280 buf.WriteString(s) 281 } 282 } 283 284 pred(tv.IsVoid(), "void") 285 pred(tv.IsType(), "type") 286 pred(tv.IsBuiltin(), "builtin") 287 pred(tv.IsValue() && tv.Value != nil, "const") 288 pred(tv.IsValue() && tv.Value == nil, "value") 289 pred(tv.IsNil(), "nil") 290 pred(tv.Addressable(), "addressable") 291 pred(tv.Assignable(), "assignable") 292 pred(tv.HasOk(), "hasOk") 293 294 if buf.Len() == 0 { 295 return "invalid" 296 } 297 return buf.String() 298 } 299 300 func TestPredicatesInfo(t *testing.T) { 301 skipSpecialPlatforms(t) 302 303 var tests = []struct { 304 src string 305 expr string 306 pred string 307 }{ 308 // void 309 {`package n0; func f() { f() }`, `f()`, `void`}, 310 311 // types 312 {`package t0; type _ int`, `int`, `type`}, 313 {`package t1; type _ []int`, `[]int`, `type`}, 314 {`package t2; type _ func()`, `func()`, `type`}, 315 316 // built-ins 317 {`package b0; var _ = len("")`, `len`, `builtin`}, 318 {`package b1; var _ = (len)("")`, `(len)`, `builtin`}, 319 320 // constants 321 {`package c0; var _ = 42`, `42`, `const`}, 322 {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`}, 323 {`package c2; const (i = 1i; _ = i)`, `i`, `const`}, 324 325 // values 326 {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`}, 327 {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`}, 328 {`package v2; var _ = func(){}`, `(func() literal)`, `value`}, 329 {`package v4; func f() { _ = f }`, `f`, `value`}, 330 {`package v3; var _ *int = nil`, `nil`, `value, nil`}, 331 {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`}, 332 333 // addressable (and thus assignable) operands 334 {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`}, 335 {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`}, 336 {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`}, 337 {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`}, 338 {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`}, 339 {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`}, 340 {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`}, 341 {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`}, 342 // composite literals are not addressable 343 344 // assignable but not addressable values 345 {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, 346 {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, 347 348 // hasOk expressions 349 {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`}, 350 {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`}, 351 352 // missing entries 353 // - package names are collected in the Uses map 354 // - identifiers being declared are collected in the Defs map 355 {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`}, 356 {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`}, 357 {`package m2; const c = 0`, `c`, `<missing>`}, 358 {`package m3; type T int`, `T`, `<missing>`}, 359 {`package m4; var v int`, `v`, `<missing>`}, 360 {`package m5; func f() {}`, `f`, `<missing>`}, 361 {`package m6; func _(x int) {}`, `x`, `<missing>`}, 362 {`package m6; func _()(x int) { return }`, `x`, `<missing>`}, 363 {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`}, 364 } 365 366 for _, test := range tests { 367 info := Info{Types: make(map[ast.Expr]TypeAndValue)} 368 name := mustTypecheck(t, "PredicatesInfo", test.src, &info) 369 370 // look for expression predicates 371 got := "<missing>" 372 for e, tv := range info.Types { 373 //println(name, ExprString(e)) 374 if ExprString(e) == test.expr { 375 got = predString(tv) 376 break 377 } 378 } 379 380 if got != test.pred { 381 t.Errorf("package %s: got %s; want %s", name, got, test.pred) 382 } 383 } 384 } 385 386 func TestScopesInfo(t *testing.T) { 387 skipSpecialPlatforms(t) 388 389 var tests = []struct { 390 src string 391 scopes []string // list of scope descriptors of the form kind:varlist 392 }{ 393 {`package p0`, []string{ 394 "file:", 395 }}, 396 {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{ 397 "file:fmt m", 398 }}, 399 {`package p2; func _() {}`, []string{ 400 "file:", "func:", 401 }}, 402 {`package p3; func _(x, y int) {}`, []string{ 403 "file:", "func:x y", 404 }}, 405 {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{ 406 "file:", "func:x y z", // redeclaration of x 407 }}, 408 {`package p5; func _(x, y int) (u, _ int) { return }`, []string{ 409 "file:", "func:u x y", 410 }}, 411 {`package p6; func _() { { var x int; _ = x } }`, []string{ 412 "file:", "func:", "block:x", 413 }}, 414 {`package p7; func _() { if true {} }`, []string{ 415 "file:", "func:", "if:", "block:", 416 }}, 417 {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{ 418 "file:", "func:", "if:x", "block:y", 419 }}, 420 {`package p9; func _() { switch x := 0; x {} }`, []string{ 421 "file:", "func:", "switch:x", 422 }}, 423 {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{ 424 "file:", "func:", "switch:x", "case:y", "case:", 425 }}, 426 {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{ 427 "file:", "func:t", "type switch:", 428 }}, 429 {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{ 430 "file:", "func:t", "type switch:t", 431 }}, 432 {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{ 433 "file:", "func:t", "type switch:", "case:x", // x implicitly declared 434 }}, 435 {`package p14; func _() { select{} }`, []string{ 436 "file:", "func:", 437 }}, 438 {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{ 439 "file:", "func:c", "comm:", 440 }}, 441 {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{ 442 "file:", "func:c", "comm:i x", 443 }}, 444 {`package p17; func _() { for{} }`, []string{ 445 "file:", "func:", "for:", "block:", 446 }}, 447 {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{ 448 "file:", "func:n", "for:i", "block:", 449 }}, 450 {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{ 451 "file:", "func:a", "range:i", "block:", 452 }}, 453 {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{ 454 "file:", "func:a", "range:i x", "block:", 455 }}, 456 } 457 458 for _, test := range tests { 459 info := Info{Scopes: make(map[ast.Node]*Scope)} 460 name := mustTypecheck(t, "ScopesInfo", test.src, &info) 461 462 // number of scopes must match 463 if len(info.Scopes) != len(test.scopes) { 464 t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes)) 465 } 466 467 // scope descriptions must match 468 for node, scope := range info.Scopes { 469 kind := "<unknown node kind>" 470 switch node.(type) { 471 case *ast.File: 472 kind = "file" 473 case *ast.FuncType: 474 kind = "func" 475 case *ast.BlockStmt: 476 kind = "block" 477 case *ast.IfStmt: 478 kind = "if" 479 case *ast.SwitchStmt: 480 kind = "switch" 481 case *ast.TypeSwitchStmt: 482 kind = "type switch" 483 case *ast.CaseClause: 484 kind = "case" 485 case *ast.CommClause: 486 kind = "comm" 487 case *ast.ForStmt: 488 kind = "for" 489 case *ast.RangeStmt: 490 kind = "range" 491 } 492 493 // look for matching scope description 494 desc := kind + ":" + strings.Join(scope.Names(), " ") 495 found := false 496 for _, d := range test.scopes { 497 if desc == d { 498 found = true 499 break 500 } 501 } 502 if !found { 503 t.Errorf("package %s: no matching scope found for %s", name, desc) 504 } 505 } 506 } 507 } 508 509 func TestInitOrderInfo(t *testing.T) { 510 var tests = []struct { 511 src string 512 inits []string 513 }{ 514 {`package p0; var (x = 1; y = x)`, []string{ 515 "x = 1", "y = x", 516 }}, 517 {`package p1; var (a = 1; b = 2; c = 3)`, []string{ 518 "a = 1", "b = 2", "c = 3", 519 }}, 520 {`package p2; var (a, b, c = 1, 2, 3)`, []string{ 521 "a = 1", "b = 2", "c = 3", 522 }}, 523 {`package p3; var _ = f(); func f() int { return 1 }`, []string{ 524 "_ = f()", // blank var 525 }}, 526 {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{ 527 "a = 0", "z = 0", "y = z", "x = y", 528 }}, 529 {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{ 530 "a, _ = m[0]", // blank var 531 }}, 532 {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{ 533 "z = 0", "a, b = f()", 534 }}, 535 {`package p7; var (a = func() int { return b }(); b = 1)`, []string{ 536 "b = 1", "a = (func() int literal)()", 537 }}, 538 {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{ 539 "c = 1", "a, b = (func() (_, _ int) literal)()", 540 }}, 541 {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{ 542 "y = 1", "x = T.m", 543 }}, 544 {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{ 545 "a = 0", "b = 0", "c = 0", "d = c + b", 546 }}, 547 {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{ 548 "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c", 549 }}, 550 // emit an initializer for n:1 initializations only once (not for each node 551 // on the lhs which may appear in different order in the dependency graph) 552 {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{ 553 "b = 0", "x, y = m[0]", "a = x", 554 }}, 555 // test case from spec section on package initialization 556 {`package p12 557 558 var ( 559 a = c + b 560 b = f() 561 c = f() 562 d = 3 563 ) 564 565 func f() int { 566 d++ 567 return d 568 }`, []string{ 569 "d = 3", "b = f()", "c = f()", "a = c + b", 570 }}, 571 // test case for issue 7131 572 {`package main 573 574 var counter int 575 func next() int { counter++; return counter } 576 577 var _ = makeOrder() 578 func makeOrder() []int { return []int{f, b, d, e, c, a} } 579 580 var a = next() 581 var b, c = next(), next() 582 var d, e, f = next(), next(), next() 583 `, []string{ 584 "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()", 585 }}, 586 } 587 588 for _, test := range tests { 589 info := Info{} 590 name := mustTypecheck(t, "InitOrderInfo", test.src, &info) 591 592 // number of initializers must match 593 if len(info.InitOrder) != len(test.inits) { 594 t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits)) 595 continue 596 } 597 598 // initializers must match 599 for i, want := range test.inits { 600 got := info.InitOrder[i].String() 601 if got != want { 602 t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want) 603 continue 604 } 605 } 606 } 607 } 608 609 func TestMultiFileInitOrder(t *testing.T) { 610 fset := token.NewFileSet() 611 mustParse := func(src string) *ast.File { 612 f, err := parser.ParseFile(fset, "main", src, 0) 613 if err != nil { 614 t.Fatal(err) 615 } 616 return f 617 } 618 619 fileA := mustParse(`package main; var a = 1`) 620 fileB := mustParse(`package main; var b = 2`) 621 622 // The initialization order must not depend on the parse 623 // order of the files, only on the presentation order to 624 // the type-checker. 625 for _, test := range []struct { 626 files []*ast.File 627 want string 628 }{ 629 {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"}, 630 {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"}, 631 } { 632 var info Info 633 if _, err := new(Config).Check("main", fset, test.files, &info); err != nil { 634 t.Fatal(err) 635 } 636 if got := fmt.Sprint(info.InitOrder); got != test.want { 637 t.Fatalf("got %s; want %s", got, test.want) 638 } 639 } 640 } 641 642 func TestFiles(t *testing.T) { 643 var sources = []string{ 644 "package p; type T struct{}; func (T) m1() {}", 645 "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}", 646 "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}", 647 "package p", 648 } 649 650 var conf Config 651 fset := token.NewFileSet() 652 pkg := NewPackage("p", "p") 653 var info Info 654 check := NewChecker(&conf, fset, pkg, &info) 655 656 for i, src := range sources { 657 filename := fmt.Sprintf("sources%d", i) 658 f, err := parser.ParseFile(fset, filename, src, 0) 659 if err != nil { 660 t.Fatal(err) 661 } 662 if err := check.Files([]*ast.File{f}); err != nil { 663 t.Error(err) 664 } 665 } 666 667 // check InitOrder is [x y] 668 var vars []string 669 for _, init := range info.InitOrder { 670 for _, v := range init.Lhs { 671 vars = append(vars, v.Name()) 672 } 673 } 674 if got, want := fmt.Sprint(vars), "[x y]"; got != want { 675 t.Errorf("InitOrder == %s, want %s", got, want) 676 } 677 } 678 679 type testImporter map[string]*Package 680 681 func (m testImporter) Import(path string) (*Package, error) { 682 if pkg := m[path]; pkg != nil { 683 return pkg, nil 684 } 685 return nil, fmt.Errorf("package %q not found", path) 686 } 687 688 func TestSelection(t *testing.T) { 689 selections := make(map[*ast.SelectorExpr]*Selection) 690 691 fset := token.NewFileSet() 692 imports := make(testImporter) 693 conf := Config{Importer: imports} 694 makePkg := func(path, src string) { 695 f, err := parser.ParseFile(fset, path+".go", src, 0) 696 if err != nil { 697 t.Fatal(err) 698 } 699 pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections}) 700 if err != nil { 701 t.Fatal(err) 702 } 703 imports[path] = pkg 704 } 705 706 const libSrc = ` 707 package lib 708 type T float64 709 const C T = 3 710 var V T 711 func F() {} 712 func (T) M() {} 713 ` 714 const mainSrc = ` 715 package main 716 import "lib" 717 718 type A struct { 719 *B 720 C 721 } 722 723 type B struct { 724 b int 725 } 726 727 func (B) f(int) 728 729 type C struct { 730 c int 731 } 732 733 func (C) g() 734 func (*C) h() 735 736 func main() { 737 // qualified identifiers 738 var _ lib.T 739 _ = lib.C 740 _ = lib.F 741 _ = lib.V 742 _ = lib.T.M 743 744 // fields 745 _ = A{}.B 746 _ = new(A).B 747 748 _ = A{}.C 749 _ = new(A).C 750 751 _ = A{}.b 752 _ = new(A).b 753 754 _ = A{}.c 755 _ = new(A).c 756 757 // methods 758 _ = A{}.f 759 _ = new(A).f 760 _ = A{}.g 761 _ = new(A).g 762 _ = new(A).h 763 764 _ = B{}.f 765 _ = new(B).f 766 767 _ = C{}.g 768 _ = new(C).g 769 _ = new(C).h 770 771 // method expressions 772 _ = A.f 773 _ = (*A).f 774 _ = B.f 775 _ = (*B).f 776 }` 777 778 wantOut := map[string][2]string{ 779 "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"}, 780 781 "A{}.B": {"field (main.A) B *main.B", ".[0]"}, 782 "new(A).B": {"field (*main.A) B *main.B", "->[0]"}, 783 "A{}.C": {"field (main.A) C main.C", ".[1]"}, 784 "new(A).C": {"field (*main.A) C main.C", "->[1]"}, 785 "A{}.b": {"field (main.A) b int", "->[0 0]"}, 786 "new(A).b": {"field (*main.A) b int", "->[0 0]"}, 787 "A{}.c": {"field (main.A) c int", ".[1 0]"}, 788 "new(A).c": {"field (*main.A) c int", "->[1 0]"}, 789 790 "A{}.f": {"method (main.A) f(int)", "->[0 0]"}, 791 "new(A).f": {"method (*main.A) f(int)", "->[0 0]"}, 792 "A{}.g": {"method (main.A) g()", ".[1 0]"}, 793 "new(A).g": {"method (*main.A) g()", "->[1 0]"}, 794 "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ? 795 "B{}.f": {"method (main.B) f(int)", ".[0]"}, 796 "new(B).f": {"method (*main.B) f(int)", "->[0]"}, 797 "C{}.g": {"method (main.C) g()", ".[0]"}, 798 "new(C).g": {"method (*main.C) g()", "->[0]"}, 799 "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ? 800 801 "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"}, 802 "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"}, 803 "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"}, 804 "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"}, 805 } 806 807 makePkg("lib", libSrc) 808 makePkg("main", mainSrc) 809 810 for e, sel := range selections { 811 sel.String() // assertion: must not panic 812 813 start := fset.Position(e.Pos()).Offset 814 end := fset.Position(e.End()).Offset 815 syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib) 816 817 direct := "." 818 if sel.Indirect() { 819 direct = "->" 820 } 821 got := [2]string{ 822 sel.String(), 823 fmt.Sprintf("%s%v", direct, sel.Index()), 824 } 825 want := wantOut[syntax] 826 if want != got { 827 t.Errorf("%s: got %q; want %q", syntax, got, want) 828 } 829 delete(wantOut, syntax) 830 831 // We must explicitly assert properties of the 832 // Signature's receiver since it doesn't participate 833 // in Identical() or String(). 834 sig, _ := sel.Type().(*Signature) 835 if sel.Kind() == MethodVal { 836 got := sig.Recv().Type() 837 want := sel.Recv() 838 if !Identical(got, want) { 839 t.Errorf("%s: Recv() = %s, want %s", syntax, got, want) 840 } 841 } else if sig != nil && sig.Recv() != nil { 842 t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type()) 843 } 844 } 845 // Assert that all wantOut entries were used exactly once. 846 for syntax := range wantOut { 847 t.Errorf("no ast.Selection found with syntax %q", syntax) 848 } 849 } 850 851 func TestIssue8518(t *testing.T) { 852 fset := token.NewFileSet() 853 imports := make(testImporter) 854 conf := Config{ 855 Error: func(err error) { t.Log(err) }, // don't exit after first error 856 Importer: imports, 857 } 858 makePkg := func(path, src string) { 859 f, err := parser.ParseFile(fset, path, src, 0) 860 if err != nil { 861 t.Fatal(err) 862 } 863 pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error 864 imports[path] = pkg 865 } 866 867 const libSrc = ` 868 package a 869 import "missing" 870 const C1 = foo 871 const C2 = missing.C 872 ` 873 874 const mainSrc = ` 875 package main 876 import "a" 877 var _ = a.C1 878 var _ = a.C2 879 ` 880 881 makePkg("a", libSrc) 882 makePkg("main", mainSrc) // don't crash when type-checking this package 883 } 884 885 func TestLookupFieldOrMethod(t *testing.T) { 886 // Test cases assume a lookup of the form a.f or x.f, where a stands for an 887 // addressable value, and x for a non-addressable value (even though a variable 888 // for ease of test case writing). 889 var tests = []struct { 890 src string 891 found bool 892 index []int 893 indirect bool 894 }{ 895 // field lookups 896 {"var x T; type T struct{}", false, nil, false}, 897 {"var x T; type T struct{ f int }", true, []int{0}, false}, 898 {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false}, 899 900 // method lookups 901 {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false}, 902 {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true}, 903 {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false}, 904 {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false? 905 906 // collisions 907 {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false}, 908 {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false}, 909 910 // outside methodset 911 // (*T).f method exists, but value of type T is not addressable 912 {"var x T; type T struct{}; func (*T) f() {}", false, nil, true}, 913 } 914 915 for _, test := range tests { 916 pkg, err := pkgFor("test", "package p;"+test.src, nil) 917 if err != nil { 918 t.Errorf("%s: incorrect test case: %s", test.src, err) 919 continue 920 } 921 922 obj := pkg.Scope().Lookup("a") 923 if obj == nil { 924 if obj = pkg.Scope().Lookup("x"); obj == nil { 925 t.Errorf("%s: incorrect test case - no object a or x", test.src) 926 continue 927 } 928 } 929 930 f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f") 931 if (f != nil) != test.found { 932 if f == nil { 933 t.Errorf("%s: got no object; want one", test.src) 934 } else { 935 t.Errorf("%s: got object = %v; want none", test.src, f) 936 } 937 } 938 if !sameSlice(index, test.index) { 939 t.Errorf("%s: got index = %v; want %v", test.src, index, test.index) 940 } 941 if indirect != test.indirect { 942 t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect) 943 } 944 } 945 } 946 947 func sameSlice(a, b []int) bool { 948 if len(a) != len(b) { 949 return false 950 } 951 for i, x := range a { 952 if x != b[i] { 953 return false 954 } 955 } 956 return true 957 }