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