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