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 "bytes" 9 "fmt" 10 "sort" 11 "strconv" 12 "strings" 13 14 "cmd/compile/internal/base" 15 "cmd/compile/internal/ir" 16 "cmd/compile/internal/types" 17 "cmd/internal/objabi" 18 "cmd/internal/src" 19) 20 21func AssignConv(n ir.Node, t *types.Type, context string) ir.Node { 22 return assignconvfn(n, t, func() string { return context }) 23} 24 25// DotImportRefs maps idents introduced by importDot back to the 26// ir.PkgName they were dot-imported through. 27var DotImportRefs map[*ir.Ident]*ir.PkgName 28 29// LookupNum looks up the symbol starting with prefix and ending with 30// the decimal n. If prefix is too long, LookupNum panics. 31func LookupNum(prefix string, n int) *types.Sym { 32 var buf [20]byte // plenty long enough for all current users 33 copy(buf[:], prefix) 34 b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10) 35 return types.LocalPkg.LookupBytes(b) 36} 37 38// Given funarg struct list, return list of fn args. 39func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field { 40 var args []*ir.Field 41 gen := 0 42 for _, t := range tl.Fields().Slice() { 43 s := t.Sym 44 if mustname && (s == nil || s.Name == "_") { 45 // invent a name so that we can refer to it in the trampoline 46 s = LookupNum(".anon", gen) 47 gen++ 48 } else if s != nil && s.Pkg != types.LocalPkg { 49 // TODO(mdempsky): Preserve original position, name, and package. 50 s = Lookup(s.Name) 51 } 52 a := ir.NewField(base.Pos, s, nil, t.Type) 53 a.Pos = t.Pos 54 a.IsDDD = t.IsDDD() 55 args = append(args, a) 56 } 57 58 return args 59} 60 61// newname returns a new ONAME Node associated with symbol s. 62func NewName(s *types.Sym) *ir.Name { 63 n := ir.NewNameAt(base.Pos, s) 64 n.Curfn = ir.CurFunc 65 return n 66} 67 68// NodAddr returns a node representing &n at base.Pos. 69func NodAddr(n ir.Node) *ir.AddrExpr { 70 return NodAddrAt(base.Pos, n) 71} 72 73// nodAddrPos returns a node representing &n at position pos. 74func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr { 75 n = markAddrOf(n) 76 return ir.NewAddrExpr(pos, n) 77} 78 79func markAddrOf(n ir.Node) ir.Node { 80 if IncrementalAddrtaken { 81 // We can only do incremental addrtaken computation when it is ok 82 // to typecheck the argument of the OADDR. That's only safe after the 83 // main typecheck has completed. 84 // The argument to OADDR needs to be typechecked because &x[i] takes 85 // the address of x if x is an array, but not if x is a slice. 86 // Note: OuterValue doesn't work correctly until n is typechecked. 87 n = typecheck(n, ctxExpr) 88 if x := ir.OuterValue(n); x.Op() == ir.ONAME { 89 x.Name().SetAddrtaken(true) 90 } 91 } else { 92 // Remember that we built an OADDR without computing the Addrtaken bit for 93 // its argument. We'll do that later in bulk using computeAddrtaken. 94 DirtyAddrtaken = true 95 } 96 return n 97} 98 99// If IncrementalAddrtaken is false, we do not compute Addrtaken for an OADDR Node 100// when it is built. The Addrtaken bits are set in bulk by computeAddrtaken. 101// If IncrementalAddrtaken is true, then when an OADDR Node is built the Addrtaken 102// field of its argument is updated immediately. 103var IncrementalAddrtaken = false 104 105// If DirtyAddrtaken is true, then there are OADDR whose corresponding arguments 106// have not yet been marked as Addrtaken. 107var DirtyAddrtaken = false 108 109func ComputeAddrtaken(top []ir.Node) { 110 for _, n := range top { 111 var doVisit func(n ir.Node) 112 doVisit = func(n ir.Node) { 113 if n.Op() == ir.OADDR { 114 if x := ir.OuterValue(n.(*ir.AddrExpr).X); x.Op() == ir.ONAME { 115 x.Name().SetAddrtaken(true) 116 if x.Name().IsClosureVar() { 117 // Mark the original variable as Addrtaken so that capturevars 118 // knows not to pass it by value. 119 x.Name().Defn.Name().SetAddrtaken(true) 120 } 121 } 122 } 123 if n.Op() == ir.OCLOSURE { 124 ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doVisit) 125 } 126 } 127 ir.Visit(n, doVisit) 128 } 129} 130 131func NodNil() ir.Node { 132 n := ir.NewNilExpr(base.Pos) 133 n.SetType(types.Types[types.TNIL]) 134 return n 135} 136 137// AddImplicitDots finds missing fields in obj.field that 138// will give the shortest unique addressing and 139// modifies the tree with missing field names. 140func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr { 141 n.X = typecheck(n.X, ctxType|ctxExpr) 142 if n.X.Diag() { 143 n.SetDiag(true) 144 } 145 t := n.X.Type() 146 if t == nil { 147 return n 148 } 149 150 if n.X.Op() == ir.OTYPE { 151 return n 152 } 153 154 s := n.Sel 155 if s == nil { 156 return n 157 } 158 159 switch path, ambig := dotpath(s, t, nil, false); { 160 case path != nil: 161 // rebuild elided dots 162 for c := len(path) - 1; c >= 0; c-- { 163 dot := ir.NewSelectorExpr(n.Pos(), ir.ODOT, n.X, path[c].field.Sym) 164 dot.SetImplicit(true) 165 dot.SetType(path[c].field.Type) 166 n.X = dot 167 } 168 case ambig: 169 base.Errorf("ambiguous selector %v", n) 170 n.X = nil 171 } 172 173 return n 174} 175 176func CalcMethods(t *types.Type) { 177 if t == nil || t.AllMethods().Len() != 0 { 178 return 179 } 180 181 // mark top-level method symbols 182 // so that expand1 doesn't consider them. 183 for _, f := range t.Methods().Slice() { 184 f.Sym.SetUniq(true) 185 } 186 187 // generate all reachable methods 188 slist = slist[:0] 189 expand1(t, true) 190 191 // check each method to be uniquely reachable 192 var ms []*types.Field 193 for i, sl := range slist { 194 slist[i].field = nil 195 sl.field.Sym.SetUniq(false) 196 197 var f *types.Field 198 path, _ := dotpath(sl.field.Sym, t, &f, false) 199 if path == nil { 200 continue 201 } 202 203 // dotpath may have dug out arbitrary fields, we only want methods. 204 if !f.IsMethod() { 205 continue 206 } 207 208 // add it to the base type method list 209 f = f.Copy() 210 f.Embedded = 1 // needs a trampoline 211 for _, d := range path { 212 if d.field.Type.IsPtr() { 213 f.Embedded = 2 214 break 215 } 216 } 217 ms = append(ms, f) 218 } 219 220 for _, f := range t.Methods().Slice() { 221 f.Sym.SetUniq(false) 222 } 223 224 ms = append(ms, t.Methods().Slice()...) 225 sort.Sort(types.MethodsByName(ms)) 226 t.SetAllMethods(ms) 227} 228 229// adddot1 returns the number of fields or methods named s at depth d in Type t. 230// If exactly one exists, it will be returned in *save (if save is not nil), 231// and dotlist will contain the path of embedded fields traversed to find it, 232// in reverse order. If none exist, more will indicate whether t contains any 233// embedded fields at depth d, so callers can decide whether to retry at 234// a greater depth. 235func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) { 236 if t.Recur() { 237 return 238 } 239 t.SetRecur(true) 240 defer t.SetRecur(false) 241 242 var u *types.Type 243 d-- 244 if d < 0 { 245 // We've reached our target depth. If t has any fields/methods 246 // named s, then we're done. Otherwise, we still need to check 247 // below for embedded fields. 248 c = lookdot0(s, t, save, ignorecase) 249 if c != 0 { 250 return c, false 251 } 252 } 253 254 u = t 255 if u.IsPtr() { 256 u = u.Elem() 257 } 258 if !u.IsStruct() && !u.IsInterface() { 259 return c, false 260 } 261 262 var fields *types.Fields 263 if u.IsStruct() { 264 fields = u.Fields() 265 } else { 266 fields = u.AllMethods() 267 } 268 for _, f := range fields.Slice() { 269 if f.Embedded == 0 || f.Sym == nil { 270 continue 271 } 272 if d < 0 { 273 // Found an embedded field at target depth. 274 return c, true 275 } 276 a, more1 := adddot1(s, f.Type, d, save, ignorecase) 277 if a != 0 && c == 0 { 278 dotlist[d].field = f 279 } 280 c += a 281 if more1 { 282 more = true 283 } 284 } 285 286 return c, more 287} 288 289// dotlist is used by adddot1 to record the path of embedded fields 290// used to access a target field or method. 291// Must be non-nil so that dotpath returns a non-nil slice even if d is zero. 292var dotlist = make([]dlist, 10) 293 294// Convert node n for assignment to type t. 295func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node { 296 if n == nil || n.Type() == nil || n.Type().Broke() { 297 return n 298 } 299 300 if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL { 301 base.Errorf("use of untyped nil") 302 } 303 304 n = convlit1(n, t, false, context) 305 if n.Type() == nil { 306 return n 307 } 308 if t.Kind() == types.TBLANK { 309 return n 310 } 311 312 // Convert ideal bool from comparison to plain bool 313 // if the next step is non-bool (like interface{}). 314 if n.Type() == types.UntypedBool && !t.IsBoolean() { 315 if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL { 316 r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n) 317 r.SetType(types.Types[types.TBOOL]) 318 r.SetTypecheck(1) 319 r.SetImplicit(true) 320 n = r 321 } 322 } 323 324 if types.Identical(n.Type(), t) { 325 return n 326 } 327 328 op, why := Assignop(n.Type(), t) 329 if op == ir.OXXX { 330 base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why) 331 op = ir.OCONV 332 } 333 334 r := ir.NewConvExpr(base.Pos, op, t, n) 335 r.SetTypecheck(1) 336 r.SetImplicit(true) 337 return r 338} 339 340// Is type src assignment compatible to type dst? 341// If so, return op code to use in conversion. 342// If not, return OXXX. In this case, the string return parameter may 343// hold a reason why. In all other cases, it'll be the empty string. 344func Assignop(src, dst *types.Type) (ir.Op, string) { 345 if src == dst { 346 return ir.OCONVNOP, "" 347 } 348 if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil { 349 return ir.OXXX, "" 350 } 351 352 // 1. src type is identical to dst. 353 if types.Identical(src, dst) { 354 return ir.OCONVNOP, "" 355 } 356 return Assignop1(src, dst) 357} 358 359func Assignop1(src, dst *types.Type) (ir.Op, string) { 360 // 2. src and dst have identical underlying types and 361 // a. either src or dst is not a named type, or 362 // b. both are empty interface types, or 363 // c. at least one is a gcshape type. 364 // For assignable but different non-empty interface types, 365 // we want to recompute the itab. Recomputing the itab ensures 366 // that itabs are unique (thus an interface with a compile-time 367 // type I has an itab with interface type I). 368 if types.Identical(src.Underlying(), dst.Underlying()) { 369 if src.IsEmptyInterface() { 370 // Conversion between two empty interfaces 371 // requires no code. 372 return ir.OCONVNOP, "" 373 } 374 if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() { 375 // Conversion between two types, at least one unnamed, 376 // needs no conversion. The exception is nonempty interfaces 377 // which need to have their itab updated. 378 return ir.OCONVNOP, "" 379 } 380 if src.IsShape() || dst.IsShape() { 381 // Conversion between a shape type and one of the types 382 // it represents also needs no conversion. 383 return ir.OCONVNOP, "" 384 } 385 } 386 387 // 3. dst is an interface type and src implements dst. 388 if dst.IsInterface() && src.Kind() != types.TNIL { 389 var missing, have *types.Field 390 var ptr int 391 if src.IsShape() { 392 // Shape types implement things they have already 393 // been typechecked to implement, even if they 394 // don't have the methods for them. 395 return ir.OCONVIFACE, "" 396 } 397 if implements(src, dst, &missing, &have, &ptr) { 398 return ir.OCONVIFACE, "" 399 } 400 401 // we'll have complained about this method anyway, suppress spurious messages. 402 if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) { 403 return ir.OCONVIFACE, "" 404 } 405 406 var why string 407 if isptrto(src, types.TINTER) { 408 why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src) 409 } else if have != nil && have.Sym == missing.Sym && have.Nointerface() { 410 why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym) 411 } else if have != nil && have.Sym == missing.Sym { 412 why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+ 413 "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) 414 } else if ptr != 0 { 415 why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym) 416 } else if have != nil { 417 why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+ 418 "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) 419 } else { 420 why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym) 421 } 422 423 return ir.OXXX, why 424 } 425 426 if isptrto(dst, types.TINTER) { 427 why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst) 428 return ir.OXXX, why 429 } 430 431 if src.IsInterface() && dst.Kind() != types.TBLANK { 432 var missing, have *types.Field 433 var ptr int 434 var why string 435 if implements(dst, src, &missing, &have, &ptr) { 436 why = ": need type assertion" 437 } 438 return ir.OXXX, why 439 } 440 441 // 4. src is a bidirectional channel value, dst is a channel type, 442 // src and dst have identical element types, and 443 // either src or dst is not a named type. 444 if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() { 445 if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) { 446 return ir.OCONVNOP, "" 447 } 448 } 449 450 // 5. src is the predeclared identifier nil and dst is a nillable type. 451 if src.Kind() == types.TNIL { 452 switch dst.Kind() { 453 case types.TPTR, 454 types.TFUNC, 455 types.TMAP, 456 types.TCHAN, 457 types.TINTER, 458 types.TSLICE: 459 return ir.OCONVNOP, "" 460 } 461 } 462 463 // 6. rule about untyped constants - already converted by DefaultLit. 464 465 // 7. Any typed value can be assigned to the blank identifier. 466 if dst.Kind() == types.TBLANK { 467 return ir.OCONVNOP, "" 468 } 469 470 return ir.OXXX, "" 471} 472 473// Can we convert a value of type src to a value of type dst? 474// If so, return op code to use in conversion (maybe OCONVNOP). 475// If not, return OXXX. In this case, the string return parameter may 476// hold a reason why. In all other cases, it'll be the empty string. 477// srcConstant indicates whether the value of type src is a constant. 478func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) { 479 if src == dst { 480 return ir.OCONVNOP, "" 481 } 482 if src == nil || dst == nil { 483 return ir.OXXX, "" 484 } 485 486 // Conversions from regular to go:notinheap are not allowed 487 // (unless it's unsafe.Pointer). These are runtime-specific 488 // rules. 489 // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't. 490 if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() { 491 why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem()) 492 return ir.OXXX, why 493 } 494 // (b) Disallow string to []T where T is go:notinheap. 495 if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) { 496 why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem()) 497 return ir.OXXX, why 498 } 499 500 // 1. src can be assigned to dst. 501 op, why := Assignop(src, dst) 502 if op != ir.OXXX { 503 return op, why 504 } 505 506 // The rules for interfaces are no different in conversions 507 // than assignments. If interfaces are involved, stop now 508 // with the good message from assignop. 509 // Otherwise clear the error. 510 if src.IsInterface() || dst.IsInterface() { 511 return ir.OXXX, why 512 } 513 514 // 2. Ignoring struct tags, src and dst have identical underlying types. 515 if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) { 516 return ir.OCONVNOP, "" 517 } 518 519 // 3. src and dst are unnamed pointer types and, ignoring struct tags, 520 // their base types have identical underlying types. 521 if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil { 522 if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) { 523 return ir.OCONVNOP, "" 524 } 525 } 526 527 // 4. src and dst are both integer or floating point types. 528 if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) { 529 if types.SimType[src.Kind()] == types.SimType[dst.Kind()] { 530 return ir.OCONVNOP, "" 531 } 532 return ir.OCONV, "" 533 } 534 535 // 5. src and dst are both complex types. 536 if src.IsComplex() && dst.IsComplex() { 537 if types.SimType[src.Kind()] == types.SimType[dst.Kind()] { 538 return ir.OCONVNOP, "" 539 } 540 return ir.OCONV, "" 541 } 542 543 // Special case for constant conversions: any numeric 544 // conversion is potentially okay. We'll validate further 545 // within evconst. See #38117. 546 if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { 547 return ir.OCONV, "" 548 } 549 550 // 6. src is an integer or has type []byte or []rune 551 // and dst is a string type. 552 if src.IsInteger() && dst.IsString() { 553 return ir.ORUNESTR, "" 554 } 555 556 if src.IsSlice() && dst.IsString() { 557 if src.Elem().Kind() == types.ByteType.Kind() { 558 return ir.OBYTES2STR, "" 559 } 560 if src.Elem().Kind() == types.RuneType.Kind() { 561 return ir.ORUNES2STR, "" 562 } 563 } 564 565 // 7. src is a string and dst is []byte or []rune. 566 // String to slice. 567 if src.IsString() && dst.IsSlice() { 568 if dst.Elem().Kind() == types.ByteType.Kind() { 569 return ir.OSTR2BYTES, "" 570 } 571 if dst.Elem().Kind() == types.RuneType.Kind() { 572 return ir.OSTR2RUNES, "" 573 } 574 } 575 576 // 8. src is a pointer or uintptr and dst is unsafe.Pointer. 577 if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() { 578 return ir.OCONVNOP, "" 579 } 580 581 // 9. src is unsafe.Pointer and dst is a pointer or uintptr. 582 if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) { 583 return ir.OCONVNOP, "" 584 } 585 586 // 10. src is map and dst is a pointer to corresponding hmap. 587 // This rule is needed for the implementation detail that 588 // go gc maps are implemented as a pointer to a hmap struct. 589 if src.Kind() == types.TMAP && dst.IsPtr() && 590 src.MapType().Hmap == dst.Elem() { 591 return ir.OCONVNOP, "" 592 } 593 594 // 11. src is a slice and dst is a pointer-to-array. 595 // They must have same element type. 596 if src.IsSlice() && dst.IsPtr() && dst.Elem().IsArray() && 597 types.Identical(src.Elem(), dst.Elem().Elem()) { 598 if !types.AllowsGoVersion(curpkg(), 1, 17) { 599 return ir.OXXX, ":\n\tconversion of slices to array pointers only supported as of -lang=go1.17" 600 } 601 return ir.OSLICE2ARRPTR, "" 602 } 603 604 return ir.OXXX, "" 605} 606 607// Code to resolve elided DOTs in embedded types. 608 609// A dlist stores a pointer to a TFIELD Type embedded within 610// a TSTRUCT or TINTER Type. 611type dlist struct { 612 field *types.Field 613} 614 615// dotpath computes the unique shortest explicit selector path to fully qualify 616// a selection expression x.f, where x is of type t and f is the symbol s. 617// If no such path exists, dotpath returns nil. 618// If there are multiple shortest paths to the same depth, ambig is true. 619func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) { 620 // The embedding of types within structs imposes a tree structure onto 621 // types: structs parent the types they embed, and types parent their 622 // fields or methods. Our goal here is to find the shortest path to 623 // a field or method named s in the subtree rooted at t. To accomplish 624 // that, we iteratively perform depth-first searches of increasing depth 625 // until we either find the named field/method or exhaust the tree. 626 for d := 0; ; d++ { 627 if d > len(dotlist) { 628 dotlist = append(dotlist, dlist{}) 629 } 630 if c, more := adddot1(s, t, d, save, ignorecase); c == 1 { 631 return dotlist[:d], false 632 } else if c > 1 { 633 return nil, true 634 } else if !more { 635 return nil, false 636 } 637 } 638} 639 640func expand0(t *types.Type) { 641 u := t 642 if u.IsPtr() { 643 u = u.Elem() 644 } 645 646 if u.IsInterface() { 647 for _, f := range u.AllMethods().Slice() { 648 if f.Sym.Uniq() { 649 continue 650 } 651 f.Sym.SetUniq(true) 652 slist = append(slist, symlink{field: f}) 653 } 654 655 return 656 } 657 658 u = types.ReceiverBaseType(t) 659 if u != nil { 660 for _, f := range u.Methods().Slice() { 661 if f.Sym.Uniq() { 662 continue 663 } 664 f.Sym.SetUniq(true) 665 slist = append(slist, symlink{field: f}) 666 } 667 } 668} 669 670func expand1(t *types.Type, top bool) { 671 if t.Recur() { 672 return 673 } 674 t.SetRecur(true) 675 676 if !top { 677 expand0(t) 678 } 679 680 u := t 681 if u.IsPtr() { 682 u = u.Elem() 683 } 684 685 if u.IsStruct() || u.IsInterface() { 686 var fields *types.Fields 687 if u.IsStruct() { 688 fields = u.Fields() 689 } else { 690 fields = u.AllMethods() 691 } 692 for _, f := range fields.Slice() { 693 if f.Embedded == 0 { 694 continue 695 } 696 if f.Sym == nil { 697 continue 698 } 699 expand1(f.Type, false) 700 } 701 } 702 703 t.SetRecur(false) 704} 705 706func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) { 707 if t == nil { 708 return nil, false 709 } 710 711 path, ambig := dotpath(s, t, &m, ignorecase) 712 if path == nil { 713 if ambig { 714 base.Errorf("%v.%v is ambiguous", t, s) 715 } 716 return nil, false 717 } 718 719 for _, d := range path { 720 if d.field.Type.IsPtr() { 721 followptr = true 722 break 723 } 724 } 725 726 if !m.IsMethod() { 727 base.Errorf("%v.%v is a field, not a method", t, s) 728 return nil, followptr 729 } 730 731 return m, followptr 732} 733 734// implements reports whether t implements the interface iface. t can be 735// an interface, a type parameter, or a concrete type. If implements returns 736// false, it stores a method of iface that is not implemented in *m. If the 737// method name matches but the type is wrong, it additionally stores the type 738// of the method (on t) in *samename. 739func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool { 740 t0 := t 741 if t == nil { 742 return false 743 } 744 745 if t.IsInterface() || t.IsTypeParam() { 746 if t.IsTypeParam() { 747 // If t is a simple type parameter T, its type and underlying is the same. 748 // If t is a type definition:'type P[T any] T', its type is P[T] and its 749 // underlying is T. Therefore we use 't.Underlying() != t' to distinguish them. 750 if t.Underlying() != t { 751 CalcMethods(t) 752 } else { 753 // A typeparam satisfies an interface if its type bound 754 // has all the methods of that interface. 755 t = t.Bound() 756 } 757 } 758 i := 0 759 tms := t.AllMethods().Slice() 760 for _, im := range iface.AllMethods().Slice() { 761 for i < len(tms) && tms[i].Sym != im.Sym { 762 i++ 763 } 764 if i == len(tms) { 765 *m = im 766 *samename = nil 767 *ptr = 0 768 return false 769 } 770 tm := tms[i] 771 if !types.Identical(tm.Type, im.Type) { 772 *m = im 773 *samename = tm 774 *ptr = 0 775 return false 776 } 777 } 778 779 return true 780 } 781 782 t = types.ReceiverBaseType(t) 783 var tms []*types.Field 784 if t != nil { 785 CalcMethods(t) 786 tms = t.AllMethods().Slice() 787 } 788 i := 0 789 for _, im := range iface.AllMethods().Slice() { 790 if im.Broke() { 791 continue 792 } 793 for i < len(tms) && tms[i].Sym != im.Sym { 794 i++ 795 } 796 if i == len(tms) { 797 *m = im 798 *samename, _ = ifacelookdot(im.Sym, t, true) 799 *ptr = 0 800 return false 801 } 802 tm := tms[i] 803 if tm.Nointerface() || !types.Identical(tm.Type, im.Type) { 804 *m = im 805 *samename = tm 806 *ptr = 0 807 return false 808 } 809 followptr := tm.Embedded == 2 810 811 // if pointer receiver in method, 812 // the method does not exist for value types. 813 rcvr := tm.Type.Recv().Type 814 if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) { 815 if false && base.Flag.LowerR != 0 { 816 base.Errorf("interface pointer mismatch") 817 } 818 819 *m = im 820 *samename = nil 821 *ptr = 1 822 return false 823 } 824 } 825 826 return true 827} 828 829func isptrto(t *types.Type, et types.Kind) bool { 830 if t == nil { 831 return false 832 } 833 if !t.IsPtr() { 834 return false 835 } 836 t = t.Elem() 837 if t == nil { 838 return false 839 } 840 if t.Kind() != et { 841 return false 842 } 843 return true 844} 845 846// lookdot0 returns the number of fields or methods named s associated 847// with Type t. If exactly one exists, it will be returned in *save 848// (if save is not nil). 849func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int { 850 u := t 851 if u.IsPtr() { 852 u = u.Elem() 853 } 854 855 c := 0 856 if u.IsStruct() || u.IsInterface() { 857 var fields *types.Fields 858 if u.IsStruct() { 859 fields = u.Fields() 860 } else { 861 fields = u.AllMethods() 862 } 863 for _, f := range fields.Slice() { 864 if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) { 865 if save != nil { 866 *save = f 867 } 868 c++ 869 } 870 } 871 } 872 873 u = t 874 if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() { 875 // If t is a defined pointer type, then x.m is shorthand for (*x).m. 876 u = t.Elem() 877 } 878 u = types.ReceiverBaseType(u) 879 if u != nil { 880 for _, f := range u.Methods().Slice() { 881 if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) { 882 if save != nil { 883 *save = f 884 } 885 c++ 886 } 887 } 888 } 889 890 return c 891} 892 893var slist []symlink 894 895// Code to help generate trampoline functions for methods on embedded 896// types. These are approx the same as the corresponding AddImplicitDots 897// routines except that they expect to be called with unique tasks and 898// they return the actual methods. 899 900type symlink struct { 901 field *types.Field 902} 903 904// TypesOf converts a list of nodes to a list 905// of types of those nodes. 906func TypesOf(x []ir.Node) []*types.Type { 907 r := make([]*types.Type, len(x)) 908 for i, n := range x { 909 r[i] = n.Type() 910 } 911 return r 912} 913 914// addTargs writes out the targs to buffer b as a comma-separated list enclosed by 915// brackets. 916func addTargs(b *bytes.Buffer, targs []*types.Type) { 917 b.WriteByte('[') 918 for i, targ := range targs { 919 if i > 0 { 920 b.WriteByte(',') 921 } 922 // Make sure that type arguments (including type params), are 923 // uniquely specified. LinkString() eliminates all spaces 924 // and includes the package path (local package path is "" before 925 // linker substitution). 926 tstring := targ.LinkString() 927 b.WriteString(tstring) 928 } 929 b.WriteString("]") 930} 931 932// InstTypeName creates a name for an instantiated type, based on the name of the 933// generic type and the type args. 934func InstTypeName(name string, targs []*types.Type) string { 935 b := bytes.NewBufferString(name) 936 addTargs(b, targs) 937 return b.String() 938} 939 940// makeInstName1 returns the name of the generic function instantiated with the 941// given types, which can have type params or shapes, or be concrete types. name is 942// the name of the generic function or method. 943func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string { 944 b := bytes.NewBufferString("") 945 i := strings.Index(name, "[") 946 assert(hasBrackets == (i >= 0)) 947 if i >= 0 { 948 b.WriteString(name[0:i]) 949 } else { 950 b.WriteString(name) 951 } 952 addTargs(b, targs) 953 if i >= 0 { 954 i2 := strings.LastIndex(name[i:], "]") 955 assert(i2 >= 0) 956 b.WriteString(name[i+i2+1:]) 957 } 958 return b.String() 959} 960 961// MakeFuncInstSym makes the unique sym for a stenciled generic function or method, 962// based on the name of the function gf and the targs. It replaces any 963// existing bracket type list in the name. MakeInstName asserts that gf has 964// brackets in its name if and only if hasBrackets is true. 965// 966// Names of declared generic functions have no brackets originally, so hasBrackets 967// should be false. Names of generic methods already have brackets, since the new 968// type parameter is specified in the generic type of the receiver (e.g. func 969// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set. 970// 971// The standard naming is something like: 'genFn[int,bool]' for functions and 972// '(*genType[int,bool]).methodName' for methods 973// 974// isMethodNode specifies if the name of a method node is being generated (as opposed 975// to a name of an instantiation of generic function or name of the shape-based 976// function that helps implement a method of an instantiated type). For method nodes 977// on shape types, we prepend "nofunc.", because method nodes for shape types will 978// have no body, and we want to avoid a name conflict with the shape-based function 979// that helps implement the same method for fully-instantiated types. 980func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym { 981 nm := makeInstName1(gf.Name, targs, hasBrackets) 982 if targs[0].HasShape() && isMethodNode { 983 nm = "nofunc." + nm 984 } 985 return gf.Pkg.Lookup(nm) 986} 987 988func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym { 989 for _, targ := range targs { 990 if targ.HasTParam() { 991 fmt.Printf("FUNCTION %s\n", gf.Name) 992 for _, targ := range targs { 993 fmt.Printf(" PARAM %+v\n", targ) 994 } 995 panic("dictionary should always have concrete type args") 996 } 997 } 998 name := makeInstName1(gf.Name, targs, hasBrackets) 999 name = fmt.Sprintf("%s.%s", objabi.GlobalDictPrefix, name) 1000 return gf.Pkg.Lookup(name) 1001} 1002 1003func assert(p bool) { 1004 base.Assert(p) 1005} 1006 1007// List of newly fully-instantiated types who should have their methods generated. 1008var instTypeList []*types.Type 1009 1010// NeedInstType adds a new fully-instantiated type to instTypeList. 1011func NeedInstType(t *types.Type) { 1012 instTypeList = append(instTypeList, t) 1013} 1014 1015// GetInstTypeList returns the current contents of instTypeList. 1016func GetInstTypeList() []*types.Type { 1017 r := instTypeList 1018 return r 1019} 1020 1021// ClearInstTypeList clears the contents of instTypeList. 1022func ClearInstTypeList() { 1023 instTypeList = nil 1024} 1025 1026// General type substituter, for replacing typeparams with type args. 1027type Tsubster struct { 1028 Tparams []*types.Type 1029 Targs []*types.Type 1030 // If non-nil, the substitution map from name nodes in the generic function to the 1031 // name nodes in the new stenciled function. 1032 Vars map[*ir.Name]*ir.Name 1033 // If non-nil, function to substitute an incomplete (TFORW) type. 1034 SubstForwFunc func(*types.Type) *types.Type 1035} 1036 1037// Typ computes the type obtained by substituting any type parameter or shape in t 1038// that appears in subst.Tparams with the corresponding type argument in subst.Targs. 1039// If t contains no type parameters, the result is t; otherwise the result is a new 1040// type. It deals with recursive types by using TFORW types and finding partially or 1041// fully created types via sym.Def. 1042func (ts *Tsubster) Typ(t *types.Type) *types.Type { 1043 // Defer the CheckSize calls until we have fully-defined 1044 // (possibly-recursive) top-level type. 1045 types.DeferCheckSize() 1046 r := ts.typ1(t) 1047 types.ResumeCheckSize() 1048 return r 1049} 1050 1051func (ts *Tsubster) typ1(t *types.Type) *types.Type { 1052 if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TFUNC { 1053 // Note: function types need to be copied regardless, as the 1054 // types of closures may contain declarations that need 1055 // to be copied. See #45738. 1056 return t 1057 } 1058 1059 if t.IsTypeParam() || t.IsShape() { 1060 for i, tp := range ts.Tparams { 1061 if tp == t { 1062 return ts.Targs[i] 1063 } 1064 } 1065 // If t is a simple typeparam T, then t has the name/symbol 'T' 1066 // and t.Underlying() == t. 1067 // 1068 // However, consider the type definition: 'type P[T any] T'. We 1069 // might use this definition so we can have a variant of type T 1070 // that we can add new methods to. Suppose t is a reference to 1071 // P[T]. t has the name 'P[T]', but its kind is TTYPEPARAM, 1072 // because P[T] is defined as T. If we look at t.Underlying(), it 1073 // is different, because the name of t.Underlying() is 'T' rather 1074 // than 'P[T]'. But the kind of t.Underlying() is also TTYPEPARAM. 1075 // In this case, we do the needed recursive substitution in the 1076 // case statement below. 1077 if t.Underlying() == t { 1078 // t is a simple typeparam that didn't match anything in tparam 1079 return t 1080 } 1081 // t is a more complex typeparam (e.g. P[T], as above, whose 1082 // definition is just T). 1083 assert(t.Sym() != nil) 1084 } 1085 1086 var newsym *types.Sym 1087 var neededTargs []*types.Type 1088 var targsChanged bool 1089 var forw *types.Type 1090 1091 if t.Sym() != nil && (t.HasTParam() || t.HasShape()) { 1092 // Need to test for t.HasTParam() again because of special TFUNC case above. 1093 // Translate the type params for this type according to 1094 // the tparam/targs mapping from subst. 1095 neededTargs = make([]*types.Type, len(t.RParams())) 1096 for i, rparam := range t.RParams() { 1097 neededTargs[i] = ts.typ1(rparam) 1098 if !types.IdenticalStrict(neededTargs[i], rparam) { 1099 targsChanged = true 1100 } 1101 } 1102 // For a named (defined) type, we have to change the name of the 1103 // type as well. We do this first, so we can look up if we've 1104 // already seen this type during this substitution or other 1105 // definitions/substitutions. 1106 genName := genericTypeName(t.Sym()) 1107 newsym = t.Sym().Pkg.Lookup(InstTypeName(genName, neededTargs)) 1108 if newsym.Def != nil { 1109 // We've already created this instantiated defined type. 1110 return newsym.Def.Type() 1111 } 1112 1113 // In order to deal with recursive generic types, create a TFORW 1114 // type initially and set the Def field of its sym, so it can be 1115 // found if this type appears recursively within the type. 1116 forw = NewIncompleteNamedType(t.Pos(), newsym) 1117 //println("Creating new type by sub", newsym.Name, forw.HasTParam()) 1118 forw.SetRParams(neededTargs) 1119 // Copy the OrigSym from the re-instantiated type (which is the sym of 1120 // the base generic type). 1121 assert(t.OrigSym() != nil) 1122 forw.SetOrigSym(t.OrigSym()) 1123 } 1124 1125 var newt *types.Type 1126 1127 switch t.Kind() { 1128 case types.TTYPEPARAM: 1129 if t.Sym() == newsym && !targsChanged { 1130 // The substitution did not change the type. 1131 return t 1132 } 1133 // Substitute the underlying typeparam (e.g. T in P[T], see 1134 // the example describing type P[T] above). 1135 newt = ts.typ1(t.Underlying()) 1136 assert(newt != t) 1137 1138 case types.TARRAY: 1139 elem := t.Elem() 1140 newelem := ts.typ1(elem) 1141 if newelem != elem || targsChanged { 1142 newt = types.NewArray(newelem, t.NumElem()) 1143 } 1144 1145 case types.TPTR: 1146 elem := t.Elem() 1147 newelem := ts.typ1(elem) 1148 if newelem != elem || targsChanged { 1149 newt = types.NewPtr(newelem) 1150 } 1151 1152 case types.TSLICE: 1153 elem := t.Elem() 1154 newelem := ts.typ1(elem) 1155 if newelem != elem || targsChanged { 1156 newt = types.NewSlice(newelem) 1157 } 1158 1159 case types.TSTRUCT: 1160 newt = ts.tstruct(t, targsChanged) 1161 if newt == t { 1162 newt = nil 1163 } 1164 1165 case types.TFUNC: 1166 newrecvs := ts.tstruct(t.Recvs(), false) 1167 newparams := ts.tstruct(t.Params(), false) 1168 newresults := ts.tstruct(t.Results(), false) 1169 // Translate the tparams of a signature. 1170 newtparams := ts.tstruct(t.TParams(), false) 1171 if newrecvs != t.Recvs() || newparams != t.Params() || 1172 newresults != t.Results() || newtparams != t.TParams() || targsChanged { 1173 // If any types have changed, then the all the fields of 1174 // of recv, params, and results must be copied, because they have 1175 // offset fields that are dependent, and so must have an 1176 // independent copy for each new signature. 1177 var newrecv *types.Field 1178 if newrecvs.NumFields() > 0 { 1179 if newrecvs == t.Recvs() { 1180 newrecvs = ts.tstruct(t.Recvs(), true) 1181 } 1182 newrecv = newrecvs.Field(0) 1183 } 1184 if newparams == t.Params() { 1185 newparams = ts.tstruct(t.Params(), true) 1186 } 1187 if newresults == t.Results() { 1188 newresults = ts.tstruct(t.Results(), true) 1189 } 1190 var tparamfields []*types.Field 1191 if newtparams.HasTParam() { 1192 tparamfields = newtparams.FieldSlice() 1193 } else { 1194 // Completely remove the tparams from the resulting 1195 // signature, if the tparams are now concrete types. 1196 tparamfields = nil 1197 } 1198 newt = types.NewSignature(t.Pkg(), newrecv, tparamfields, 1199 newparams.FieldSlice(), newresults.FieldSlice()) 1200 } 1201 1202 case types.TINTER: 1203 newt = ts.tinter(t, targsChanged) 1204 if newt == t { 1205 newt = nil 1206 } 1207 1208 case types.TMAP: 1209 newkey := ts.typ1(t.Key()) 1210 newval := ts.typ1(t.Elem()) 1211 if newkey != t.Key() || newval != t.Elem() || targsChanged { 1212 newt = types.NewMap(newkey, newval) 1213 } 1214 1215 case types.TCHAN: 1216 elem := t.Elem() 1217 newelem := ts.typ1(elem) 1218 if newelem != elem || targsChanged { 1219 newt = types.NewChan(newelem, t.ChanDir()) 1220 } 1221 case types.TFORW: 1222 if ts.SubstForwFunc != nil { 1223 return ts.SubstForwFunc(forw) 1224 } else { 1225 assert(false) 1226 } 1227 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, 1228 types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, 1229 types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR: 1230 newt = t.Underlying() 1231 case types.TUNION: 1232 nt := t.NumTerms() 1233 newterms := make([]*types.Type, nt) 1234 tildes := make([]bool, nt) 1235 changed := false 1236 for i := 0; i < nt; i++ { 1237 term, tilde := t.Term(i) 1238 tildes[i] = tilde 1239 newterms[i] = ts.typ1(term) 1240 if newterms[i] != term { 1241 changed = true 1242 } 1243 } 1244 if changed { 1245 newt = types.NewUnion(newterms, tildes) 1246 } 1247 default: 1248 panic(fmt.Sprintf("Bad type in (*TSubster).Typ: %v", t.Kind())) 1249 } 1250 if newt == nil { 1251 // Even though there were typeparams in the type, there may be no 1252 // change if this is a function type for a function call (which will 1253 // have its own tparams/targs in the function instantiation). 1254 return t 1255 } 1256 1257 if forw != nil { 1258 forw.SetUnderlying(newt) 1259 newt = forw 1260 } 1261 1262 if !newt.HasTParam() && !newt.IsFuncArgStruct() { 1263 // Calculate the size of any new types created. These will be 1264 // deferred until the top-level ts.Typ() or g.typ() (if this is 1265 // called from g.fillinMethods()). 1266 types.CheckSize(newt) 1267 } 1268 1269 if t.Kind() != types.TINTER && t.Methods().Len() > 0 { 1270 // Fill in the method info for the new type. 1271 var newfields []*types.Field 1272 newfields = make([]*types.Field, t.Methods().Len()) 1273 for i, f := range t.Methods().Slice() { 1274 t2 := ts.typ1(f.Type) 1275 oldsym := f.Nname.Sym() 1276 newsym := MakeFuncInstSym(oldsym, ts.Targs, true, true) 1277 var nname *ir.Name 1278 if newsym.Def != nil { 1279 nname = newsym.Def.(*ir.Name) 1280 } else { 1281 nname = ir.NewNameAt(f.Pos, newsym) 1282 nname.SetType(t2) 1283 ir.MarkFunc(nname) 1284 newsym.Def = nname 1285 } 1286 newfields[i] = types.NewField(f.Pos, f.Sym, t2) 1287 newfields[i].Nname = nname 1288 } 1289 newt.Methods().Set(newfields) 1290 if !newt.HasTParam() && !newt.HasShape() { 1291 // Generate all the methods for a new fully-instantiated type. 1292 1293 NeedInstType(newt) 1294 } 1295 } 1296 return newt 1297} 1298 1299// tstruct substitutes type params in types of the fields of a structure type. For 1300// each field, tstruct copies the Nname, and translates it if Nname is in 1301// ts.vars. To always force the creation of a new (top-level) struct, 1302// regardless of whether anything changed with the types or names of the struct's 1303// fields, set force to true. 1304func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type { 1305 if t.NumFields() == 0 { 1306 if t.HasTParam() || t.HasShape() { 1307 // For an empty struct, we need to return a new type, 1308 // since it may now be fully instantiated (HasTParam 1309 // becomes false). 1310 return types.NewStruct(t.Pkg(), nil) 1311 } 1312 return t 1313 } 1314 var newfields []*types.Field 1315 if force { 1316 newfields = make([]*types.Field, t.NumFields()) 1317 } 1318 for i, f := range t.Fields().Slice() { 1319 t2 := ts.typ1(f.Type) 1320 if (t2 != f.Type || f.Nname != nil) && newfields == nil { 1321 newfields = make([]*types.Field, t.NumFields()) 1322 for j := 0; j < i; j++ { 1323 newfields[j] = t.Field(j) 1324 } 1325 } 1326 if newfields != nil { 1327 newfields[i] = types.NewField(f.Pos, f.Sym, t2) 1328 newfields[i].Embedded = f.Embedded 1329 newfields[i].Note = f.Note 1330 if f.IsDDD() { 1331 newfields[i].SetIsDDD(true) 1332 } 1333 if f.Nointerface() { 1334 newfields[i].SetNointerface(true) 1335 } 1336 if f.Nname != nil && ts.Vars != nil { 1337 v := ts.Vars[f.Nname.(*ir.Name)] 1338 if v != nil { 1339 // This is the case where we are 1340 // translating the type of the function we 1341 // are substituting, so its dcls are in 1342 // the subst.ts.vars table, and we want to 1343 // change to reference the new dcl. 1344 newfields[i].Nname = v 1345 } else { 1346 // This is the case where we are 1347 // translating the type of a function 1348 // reference inside the function we are 1349 // substituting, so we leave the Nname 1350 // value as is. 1351 newfields[i].Nname = f.Nname 1352 } 1353 } 1354 } 1355 } 1356 if newfields != nil { 1357 news := types.NewStruct(t.Pkg(), newfields) 1358 news.StructType().Funarg = t.StructType().Funarg 1359 return news 1360 } 1361 return t 1362 1363} 1364 1365// tinter substitutes type params in types of the methods of an interface type. 1366func (ts *Tsubster) tinter(t *types.Type, force bool) *types.Type { 1367 if t.Methods().Len() == 0 { 1368 if t.HasTParam() { 1369 // For an empty interface, we need to return a new type, 1370 // since it may now be fully instantiated (HasTParam 1371 // becomes false). 1372 return types.NewInterface(t.Pkg(), nil, false) 1373 } 1374 return t 1375 } 1376 var newfields []*types.Field 1377 if force { 1378 newfields = make([]*types.Field, t.Methods().Len()) 1379 } 1380 for i, f := range t.Methods().Slice() { 1381 t2 := ts.typ1(f.Type) 1382 if (t2 != f.Type || f.Nname != nil) && newfields == nil { 1383 newfields = make([]*types.Field, t.Methods().Len()) 1384 for j := 0; j < i; j++ { 1385 newfields[j] = t.Methods().Index(j) 1386 } 1387 } 1388 if newfields != nil { 1389 newfields[i] = types.NewField(f.Pos, f.Sym, t2) 1390 } 1391 } 1392 if newfields != nil { 1393 return types.NewInterface(t.Pkg(), newfields, t.IsImplicit()) 1394 } 1395 return t 1396} 1397 1398// genericSym returns the name of the base generic type for the type named by 1399// sym. It simply returns the name obtained by removing everything after the 1400// first bracket ("["). 1401func genericTypeName(sym *types.Sym) string { 1402 return sym.Name[0:strings.Index(sym.Name, "[")] 1403} 1404 1405// Shapify takes a concrete type and a type param index, and returns a GCshape type that can 1406// be used in place of the input type and still generate identical code. 1407// No methods are added - all methods calls directly on a shape should 1408// be done by converting to an interface using the dictionary. 1409// 1410// For now, we only consider two types to have the same shape, if they have exactly 1411// the same underlying type or they are both pointer types. 1412// 1413// Shape types are also distinguished by the index of the type in a type param/arg 1414// list. We need to do this so we can distinguish and substitute properly for two 1415// type params in the same function that have the same shape for a particular 1416// instantiation. 1417func Shapify(t *types.Type, index int) *types.Type { 1418 assert(!t.IsShape()) 1419 // Map all types with the same underlying type to the same shape. 1420 u := t.Underlying() 1421 1422 // All pointers have the same shape. 1423 // TODO: Make unsafe.Pointer the same shape as normal pointers. 1424 // Note: pointers to arrays are special because of slice-to-array-pointer 1425 // conversions. See issue 49295. 1426 if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY { 1427 u = types.Types[types.TUINT8].PtrTo() 1428 } 1429 1430 if shapeMap == nil { 1431 shapeMap = map[int]map[*types.Type]*types.Type{} 1432 } 1433 submap := shapeMap[index] 1434 if submap == nil { 1435 submap = map[*types.Type]*types.Type{} 1436 shapeMap[index] = submap 1437 } 1438 if s := submap[u]; s != nil { 1439 return s 1440 } 1441 1442 // LinkString specifies the type uniquely, but has no spaces. 1443 nm := fmt.Sprintf("%s_%d", u.LinkString(), index) 1444 sym := types.ShapePkg.Lookup(nm) 1445 if sym.Def != nil { 1446 // Use any existing type with the same name 1447 submap[u] = sym.Def.Type() 1448 return submap[u] 1449 } 1450 name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym) 1451 s := types.NewNamed(name) 1452 sym.Def = name 1453 s.SetUnderlying(u) 1454 s.SetIsShape(true) 1455 s.SetHasShape(true) 1456 name.SetType(s) 1457 name.SetTypecheck(1) 1458 submap[u] = s 1459 return s 1460} 1461 1462var shapeMap map[int]map[*types.Type]*types.Type 1463