1// Copyright 2009 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 5package typecheck 6 7import ( 8 "fmt" 9 "sort" 10 "strings" 11 12 "cmd/compile/internal/base" 13 "cmd/compile/internal/ir" 14 "cmd/compile/internal/types" 15 "cmd/internal/obj" 16 "cmd/internal/src" 17) 18 19func AssignConv(n ir.Node, t *types.Type, context string) ir.Node { 20 return assignconvfn(n, t, func() string { return context }) 21} 22 23// LookupNum returns types.LocalPkg.LookupNum(prefix, n). 24func LookupNum(prefix string, n int) *types.Sym { 25 return types.LocalPkg.LookupNum(prefix, n) 26} 27 28// Given funarg struct list, return list of fn args. 29func NewFuncParams(origs []*types.Field) []*types.Field { 30 res := make([]*types.Field, len(origs)) 31 for i, orig := range origs { 32 p := types.NewField(orig.Pos, orig.Sym, orig.Type) 33 p.SetIsDDD(orig.IsDDD()) 34 res[i] = p 35 } 36 return res 37} 38 39// NodAddr returns a node representing &n at base.Pos. 40func NodAddr(n ir.Node) *ir.AddrExpr { 41 return NodAddrAt(base.Pos, n) 42} 43 44// NodAddrAt returns a node representing &n at position pos. 45func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr { 46 return ir.NewAddrExpr(pos, Expr(n)) 47} 48 49// LinksymAddr returns a new expression that evaluates to the address 50// of lsym. typ specifies the type of the addressed memory. 51func LinksymAddr(pos src.XPos, lsym *obj.LSym, typ *types.Type) *ir.AddrExpr { 52 n := ir.NewLinksymExpr(pos, lsym, typ) 53 return Expr(NodAddrAt(pos, n)).(*ir.AddrExpr) 54} 55 56func NodNil() ir.Node { 57 return ir.NewNilExpr(base.Pos, types.Types[types.TNIL]) 58} 59 60// AddImplicitDots finds missing fields in obj.field that 61// will give the shortest unique addressing and 62// modifies the tree with missing field names. 63func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr { 64 n.X = typecheck(n.X, ctxType|ctxExpr) 65 t := n.X.Type() 66 if t == nil { 67 return n 68 } 69 70 if n.X.Op() == ir.OTYPE { 71 return n 72 } 73 74 s := n.Sel 75 if s == nil { 76 return n 77 } 78 79 switch path, ambig := dotpath(s, t, nil, false); { 80 case path != nil: 81 // rebuild elided dots 82 for c := len(path) - 1; c >= 0; c-- { 83 dot := ir.NewSelectorExpr(n.Pos(), ir.ODOT, n.X, path[c].field.Sym) 84 dot.SetImplicit(true) 85 dot.SetType(path[c].field.Type) 86 n.X = dot 87 } 88 case ambig: 89 base.Errorf("ambiguous selector %v", n) 90 n.X = nil 91 } 92 93 return n 94} 95 96// CalcMethods calculates all the methods (including embedding) of a non-interface 97// type t. 98func CalcMethods(t *types.Type) { 99 if t == nil || len(t.AllMethods()) != 0 { 100 return 101 } 102 103 // mark top-level method symbols 104 // so that expand1 doesn't consider them. 105 for _, f := range t.Methods() { 106 f.Sym.SetUniq(true) 107 } 108 109 // generate all reachable methods 110 slist = slist[:0] 111 expand1(t, true) 112 113 // check each method to be uniquely reachable 114 var ms []*types.Field 115 for i, sl := range slist { 116 slist[i].field = nil 117 sl.field.Sym.SetUniq(false) 118 119 var f *types.Field 120 path, _ := dotpath(sl.field.Sym, t, &f, false) 121 if path == nil { 122 continue 123 } 124 125 // dotpath may have dug out arbitrary fields, we only want methods. 126 if !f.IsMethod() { 127 continue 128 } 129 130 // add it to the base type method list 131 f = f.Copy() 132 f.Embedded = 1 // needs a trampoline 133 for _, d := range path { 134 if d.field.Type.IsPtr() { 135 f.Embedded = 2 136 break 137 } 138 } 139 ms = append(ms, f) 140 } 141 142 for _, f := range t.Methods() { 143 f.Sym.SetUniq(false) 144 } 145 146 ms = append(ms, t.Methods()...) 147 sort.Sort(types.MethodsByName(ms)) 148 t.SetAllMethods(ms) 149} 150 151// adddot1 returns the number of fields or methods named s at depth d in Type t. 152// If exactly one exists, it will be returned in *save (if save is not nil), 153// and dotlist will contain the path of embedded fields traversed to find it, 154// in reverse order. If none exist, more will indicate whether t contains any 155// embedded fields at depth d, so callers can decide whether to retry at 156// a greater depth. 157func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) { 158 if t.Recur() { 159 return 160 } 161 t.SetRecur(true) 162 defer t.SetRecur(false) 163 164 var u *types.Type 165 d-- 166 if d < 0 { 167 // We've reached our target depth. If t has any fields/methods 168 // named s, then we're done. Otherwise, we still need to check 169 // below for embedded fields. 170 c = lookdot0(s, t, save, ignorecase) 171 if c != 0 { 172 return c, false 173 } 174 } 175 176 u = t 177 if u.IsPtr() { 178 u = u.Elem() 179 } 180 if !u.IsStruct() && !u.IsInterface() { 181 return c, false 182 } 183 184 var fields []*types.Field 185 if u.IsStruct() { 186 fields = u.Fields() 187 } else { 188 fields = u.AllMethods() 189 } 190 for _, f := range fields { 191 if f.Embedded == 0 || f.Sym == nil { 192 continue 193 } 194 if d < 0 { 195 // Found an embedded field at target depth. 196 return c, true 197 } 198 a, more1 := adddot1(s, f.Type, d, save, ignorecase) 199 if a != 0 && c == 0 { 200 dotlist[d].field = f 201 } 202 c += a 203 if more1 { 204 more = true 205 } 206 } 207 208 return c, more 209} 210 211// dotlist is used by adddot1 to record the path of embedded fields 212// used to access a target field or method. 213// Must be non-nil so that dotpath returns a non-nil slice even if d is zero. 214var dotlist = make([]dlist, 10) 215 216// Convert node n for assignment to type t. 217func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node { 218 if n == nil || n.Type() == nil { 219 return n 220 } 221 222 if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL { 223 base.Errorf("use of untyped nil") 224 } 225 226 n = convlit1(n, t, false, context) 227 if n.Type() == nil { 228 base.Fatalf("cannot assign %v to %v", n, t) 229 } 230 if n.Type().IsUntyped() { 231 base.Fatalf("%L has untyped type", n) 232 } 233 if t.Kind() == types.TBLANK { 234 return n 235 } 236 if types.Identical(n.Type(), t) { 237 return n 238 } 239 240 op, why := assignOp(n.Type(), t) 241 if op == ir.OXXX { 242 base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why) 243 op = ir.OCONV 244 } 245 246 r := ir.NewConvExpr(base.Pos, op, t, n) 247 r.SetTypecheck(1) 248 r.SetImplicit(true) 249 return r 250} 251 252// Is type src assignment compatible to type dst? 253// If so, return op code to use in conversion. 254// If not, return OXXX. In this case, the string return parameter may 255// hold a reason why. In all other cases, it'll be the empty string. 256func assignOp(src, dst *types.Type) (ir.Op, string) { 257 if src == dst { 258 return ir.OCONVNOP, "" 259 } 260 if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil { 261 return ir.OXXX, "" 262 } 263 264 // 1. src type is identical to dst. 265 if types.Identical(src, dst) { 266 return ir.OCONVNOP, "" 267 } 268 269 // 2. src and dst have identical underlying types and 270 // a. either src or dst is not a named type, or 271 // b. both are empty interface types, or 272 // c. at least one is a gcshape type. 273 // For assignable but different non-empty interface types, 274 // we want to recompute the itab. Recomputing the itab ensures 275 // that itabs are unique (thus an interface with a compile-time 276 // type I has an itab with interface type I). 277 if types.Identical(src.Underlying(), dst.Underlying()) { 278 if src.IsEmptyInterface() { 279 // Conversion between two empty interfaces 280 // requires no code. 281 return ir.OCONVNOP, "" 282 } 283 if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() { 284 // Conversion between two types, at least one unnamed, 285 // needs no conversion. The exception is nonempty interfaces 286 // which need to have their itab updated. 287 return ir.OCONVNOP, "" 288 } 289 if src.IsShape() || dst.IsShape() { 290 // Conversion between a shape type and one of the types 291 // it represents also needs no conversion. 292 return ir.OCONVNOP, "" 293 } 294 } 295 296 // 3. dst is an interface type and src implements dst. 297 if dst.IsInterface() && src.Kind() != types.TNIL { 298 if src.IsShape() { 299 // Shape types implement things they have already 300 // been typechecked to implement, even if they 301 // don't have the methods for them. 302 return ir.OCONVIFACE, "" 303 } 304 if src.HasShape() { 305 // Unified IR uses OCONVIFACE for converting all derived types 306 // to interface type, not just type arguments themselves. 307 return ir.OCONVIFACE, "" 308 } 309 310 why := ImplementsExplain(src, dst) 311 if why == "" { 312 return ir.OCONVIFACE, "" 313 } 314 return ir.OXXX, ":\n\t" + why 315 } 316 317 if isptrto(dst, types.TINTER) { 318 why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst) 319 return ir.OXXX, why 320 } 321 322 if src.IsInterface() && dst.Kind() != types.TBLANK { 323 var why string 324 if Implements(dst, src) { 325 why = ": need type assertion" 326 } 327 return ir.OXXX, why 328 } 329 330 // 4. src is a bidirectional channel value, dst is a channel type, 331 // src and dst have identical element types, and 332 // either src or dst is not a named type. 333 if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() { 334 if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) { 335 return ir.OCONVNOP, "" 336 } 337 } 338 339 // 5. src is the predeclared identifier nil and dst is a nillable type. 340 if src.Kind() == types.TNIL { 341 switch dst.Kind() { 342 case types.TPTR, 343 types.TFUNC, 344 types.TMAP, 345 types.TCHAN, 346 types.TINTER, 347 types.TSLICE: 348 return ir.OCONVNOP, "" 349 } 350 } 351 352 // 6. rule about untyped constants - already converted by DefaultLit. 353 354 // 7. Any typed value can be assigned to the blank identifier. 355 if dst.Kind() == types.TBLANK { 356 return ir.OCONVNOP, "" 357 } 358 359 return ir.OXXX, "" 360} 361 362// Can we convert a value of type src to a value of type dst? 363// If so, return op code to use in conversion (maybe OCONVNOP). 364// If not, return OXXX. In this case, the string return parameter may 365// hold a reason why. In all other cases, it'll be the empty string. 366// srcConstant indicates whether the value of type src is a constant. 367func convertOp(srcConstant bool, src, dst *types.Type) (ir.Op, string) { 368 if src == dst { 369 return ir.OCONVNOP, "" 370 } 371 if src == nil || dst == nil { 372 return ir.OXXX, "" 373 } 374 375 // Conversions from regular to not-in-heap are not allowed 376 // (unless it's unsafe.Pointer). These are runtime-specific 377 // rules. 378 // (a) Disallow (*T) to (*U) where T is not-in-heap but U isn't. 379 if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() { 380 why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem()) 381 return ir.OXXX, why 382 } 383 // (b) Disallow string to []T where T is not-in-heap. 384 if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) { 385 why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem()) 386 return ir.OXXX, why 387 } 388 389 // 1. src can be assigned to dst. 390 op, why := assignOp(src, dst) 391 if op != ir.OXXX { 392 return op, why 393 } 394 395 // The rules for interfaces are no different in conversions 396 // than assignments. If interfaces are involved, stop now 397 // with the good message from assignop. 398 // Otherwise clear the error. 399 if src.IsInterface() || dst.IsInterface() { 400 return ir.OXXX, why 401 } 402 403 // 2. Ignoring struct tags, src and dst have identical underlying types. 404 if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) { 405 return ir.OCONVNOP, "" 406 } 407 408 // 3. src and dst are unnamed pointer types and, ignoring struct tags, 409 // their base types have identical underlying types. 410 if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil { 411 if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) { 412 return ir.OCONVNOP, "" 413 } 414 } 415 416 // 4. src and dst are both integer or floating point types. 417 if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) { 418 if types.SimType[src.Kind()] == types.SimType[dst.Kind()] { 419 return ir.OCONVNOP, "" 420 } 421 return ir.OCONV, "" 422 } 423 424 // 5. src and dst are both complex types. 425 if src.IsComplex() && dst.IsComplex() { 426 if types.SimType[src.Kind()] == types.SimType[dst.Kind()] { 427 return ir.OCONVNOP, "" 428 } 429 return ir.OCONV, "" 430 } 431 432 // Special case for constant conversions: any numeric 433 // conversion is potentially okay. We'll validate further 434 // within evconst. See #38117. 435 if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { 436 return ir.OCONV, "" 437 } 438 439 // 6. src is an integer or has type []byte or []rune 440 // and dst is a string type. 441 if src.IsInteger() && dst.IsString() { 442 return ir.ORUNESTR, "" 443 } 444 445 if src.IsSlice() && dst.IsString() { 446 if src.Elem().Kind() == types.ByteType.Kind() { 447 return ir.OBYTES2STR, "" 448 } 449 if src.Elem().Kind() == types.RuneType.Kind() { 450 return ir.ORUNES2STR, "" 451 } 452 } 453 454 // 7. src is a string and dst is []byte or []rune. 455 // String to slice. 456 if src.IsString() && dst.IsSlice() { 457 if dst.Elem().Kind() == types.ByteType.Kind() { 458 return ir.OSTR2BYTES, "" 459 } 460 if dst.Elem().Kind() == types.RuneType.Kind() { 461 return ir.OSTR2RUNES, "" 462 } 463 } 464 465 // 8. src is a pointer or uintptr and dst is unsafe.Pointer. 466 if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() { 467 return ir.OCONVNOP, "" 468 } 469 470 // 9. src is unsafe.Pointer and dst is a pointer or uintptr. 471 if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) { 472 return ir.OCONVNOP, "" 473 } 474 475 // 10. src is a slice and dst is an array or pointer-to-array. 476 // They must have same element type. 477 if src.IsSlice() { 478 if dst.IsArray() && types.Identical(src.Elem(), dst.Elem()) { 479 return ir.OSLICE2ARR, "" 480 } 481 if dst.IsPtr() && dst.Elem().IsArray() && 482 types.Identical(src.Elem(), dst.Elem().Elem()) { 483 return ir.OSLICE2ARRPTR, "" 484 } 485 } 486 487 return ir.OXXX, "" 488} 489 490// Code to resolve elided DOTs in embedded types. 491 492// A dlist stores a pointer to a TFIELD Type embedded within 493// a TSTRUCT or TINTER Type. 494type dlist struct { 495 field *types.Field 496} 497 498// dotpath computes the unique shortest explicit selector path to fully qualify 499// a selection expression x.f, where x is of type t and f is the symbol s. 500// If no such path exists, dotpath returns nil. 501// If there are multiple shortest paths to the same depth, ambig is true. 502func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) { 503 // The embedding of types within structs imposes a tree structure onto 504 // types: structs parent the types they embed, and types parent their 505 // fields or methods. Our goal here is to find the shortest path to 506 // a field or method named s in the subtree rooted at t. To accomplish 507 // that, we iteratively perform depth-first searches of increasing depth 508 // until we either find the named field/method or exhaust the tree. 509 for d := 0; ; d++ { 510 if d > len(dotlist) { 511 dotlist = append(dotlist, dlist{}) 512 } 513 if c, more := adddot1(s, t, d, save, ignorecase); c == 1 { 514 return dotlist[:d], false 515 } else if c > 1 { 516 return nil, true 517 } else if !more { 518 return nil, false 519 } 520 } 521} 522 523func expand0(t *types.Type) { 524 u := t 525 if u.IsPtr() { 526 u = u.Elem() 527 } 528 529 if u.IsInterface() { 530 for _, f := range u.AllMethods() { 531 if f.Sym.Uniq() { 532 continue 533 } 534 f.Sym.SetUniq(true) 535 slist = append(slist, symlink{field: f}) 536 } 537 538 return 539 } 540 541 u = types.ReceiverBaseType(t) 542 if u != nil { 543 for _, f := range u.Methods() { 544 if f.Sym.Uniq() { 545 continue 546 } 547 f.Sym.SetUniq(true) 548 slist = append(slist, symlink{field: f}) 549 } 550 } 551} 552 553func expand1(t *types.Type, top bool) { 554 if t.Recur() { 555 return 556 } 557 t.SetRecur(true) 558 559 if !top { 560 expand0(t) 561 } 562 563 u := t 564 if u.IsPtr() { 565 u = u.Elem() 566 } 567 568 if u.IsStruct() || u.IsInterface() { 569 var fields []*types.Field 570 if u.IsStruct() { 571 fields = u.Fields() 572 } else { 573 fields = u.AllMethods() 574 } 575 for _, f := range fields { 576 if f.Embedded == 0 { 577 continue 578 } 579 if f.Sym == nil { 580 continue 581 } 582 expand1(f.Type, false) 583 } 584 } 585 586 t.SetRecur(false) 587} 588 589func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) *types.Field { 590 if t == nil { 591 return nil 592 } 593 594 var m *types.Field 595 path, _ := dotpath(s, t, &m, ignorecase) 596 if path == nil { 597 return nil 598 } 599 600 if !m.IsMethod() { 601 return nil 602 } 603 604 return m 605} 606 607// Implements reports whether t implements the interface iface. t can be 608// an interface, a type parameter, or a concrete type. 609func Implements(t, iface *types.Type) bool { 610 var missing, have *types.Field 611 var ptr int 612 return implements(t, iface, &missing, &have, &ptr) 613} 614 615// ImplementsExplain reports whether t implements the interface iface. t can be 616// an interface, a type parameter, or a concrete type. If t does not implement 617// iface, a non-empty string is returned explaining why. 618func ImplementsExplain(t, iface *types.Type) string { 619 var missing, have *types.Field 620 var ptr int 621 if implements(t, iface, &missing, &have, &ptr) { 622 return "" 623 } 624 625 if isptrto(t, types.TINTER) { 626 return fmt.Sprintf("%v is pointer to interface, not interface", t) 627 } else if have != nil && have.Sym == missing.Sym && have.Nointerface() { 628 return fmt.Sprintf("%v does not implement %v (%v method is marked 'nointerface')", t, iface, missing.Sym) 629 } else if have != nil && have.Sym == missing.Sym { 630 return fmt.Sprintf("%v does not implement %v (wrong type for %v method)\n"+ 631 "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) 632 } else if ptr != 0 { 633 return fmt.Sprintf("%v does not implement %v (%v method has pointer receiver)", t, iface, missing.Sym) 634 } else if have != nil { 635 return fmt.Sprintf("%v does not implement %v (missing %v method)\n"+ 636 "\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) 637 } 638 return fmt.Sprintf("%v does not implement %v (missing %v method)", t, iface, missing.Sym) 639} 640 641// implements reports whether t implements the interface iface. t can be 642// an interface, a type parameter, or a concrete type. If implements returns 643// false, it stores a method of iface that is not implemented in *m. If the 644// method name matches but the type is wrong, it additionally stores the type 645// of the method (on t) in *samename. 646func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool { 647 t0 := t 648 if t == nil { 649 return false 650 } 651 652 if t.IsInterface() { 653 i := 0 654 tms := t.AllMethods() 655 for _, im := range iface.AllMethods() { 656 for i < len(tms) && tms[i].Sym != im.Sym { 657 i++ 658 } 659 if i == len(tms) { 660 *m = im 661 *samename = nil 662 *ptr = 0 663 return false 664 } 665 tm := tms[i] 666 if !types.Identical(tm.Type, im.Type) { 667 *m = im 668 *samename = tm 669 *ptr = 0 670 return false 671 } 672 } 673 674 return true 675 } 676 677 t = types.ReceiverBaseType(t) 678 var tms []*types.Field 679 if t != nil { 680 CalcMethods(t) 681 tms = t.AllMethods() 682 } 683 i := 0 684 for _, im := range iface.AllMethods() { 685 for i < len(tms) && tms[i].Sym != im.Sym { 686 i++ 687 } 688 if i == len(tms) { 689 *m = im 690 *samename = ifacelookdot(im.Sym, t, true) 691 *ptr = 0 692 return false 693 } 694 tm := tms[i] 695 if tm.Nointerface() || !types.Identical(tm.Type, im.Type) { 696 *m = im 697 *samename = tm 698 *ptr = 0 699 return false 700 } 701 702 // if pointer receiver in method, 703 // the method does not exist for value types. 704 if !types.IsMethodApplicable(t0, tm) { 705 if false && base.Flag.LowerR != 0 { 706 base.Errorf("interface pointer mismatch") 707 } 708 709 *m = im 710 *samename = nil 711 *ptr = 1 712 return false 713 } 714 } 715 716 return true 717} 718 719func isptrto(t *types.Type, et types.Kind) bool { 720 if t == nil { 721 return false 722 } 723 if !t.IsPtr() { 724 return false 725 } 726 t = t.Elem() 727 if t == nil { 728 return false 729 } 730 if t.Kind() != et { 731 return false 732 } 733 return true 734} 735 736// lookdot0 returns the number of fields or methods named s associated 737// with Type t. If exactly one exists, it will be returned in *save 738// (if save is not nil). 739func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int { 740 u := t 741 if u.IsPtr() { 742 u = u.Elem() 743 } 744 745 c := 0 746 if u.IsStruct() || u.IsInterface() { 747 var fields []*types.Field 748 if u.IsStruct() { 749 fields = u.Fields() 750 } else { 751 fields = u.AllMethods() 752 } 753 for _, f := range fields { 754 if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) { 755 if save != nil { 756 *save = f 757 } 758 c++ 759 } 760 } 761 } 762 763 u = t 764 if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() { 765 // If t is a defined pointer type, then x.m is shorthand for (*x).m. 766 u = t.Elem() 767 } 768 u = types.ReceiverBaseType(u) 769 if u != nil { 770 for _, f := range u.Methods() { 771 if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) { 772 if save != nil { 773 *save = f 774 } 775 c++ 776 } 777 } 778 } 779 780 return c 781} 782 783var slist []symlink 784 785// Code to help generate trampoline functions for methods on embedded 786// types. These are approx the same as the corresponding AddImplicitDots 787// routines except that they expect to be called with unique tasks and 788// they return the actual methods. 789 790type symlink struct { 791 field *types.Field 792} 793