github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/template.go (about) 1 /* 2 Copyright 2021 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package gox 15 16 import ( 17 "fmt" 18 "go/constant" 19 "go/token" 20 "go/types" 21 "log" 22 "math/big" 23 24 "github.com/goplus/gox/internal" 25 ) 26 27 // ---------------------------------------------------------------------------- 28 29 type Contract interface { 30 Match(pkg *Package, t types.Type) bool 31 String() string 32 } 33 34 type TemplateParamType struct { 35 name string 36 contract Contract 37 idxFlag int 38 } 39 40 func NewTemplateParamType(idx int, name string, contract Contract) *TemplateParamType { 41 return &TemplateParamType{idxFlag: idx, name: name, contract: contract} 42 } 43 44 func (p *TemplateParamType) Underlying() types.Type { return p } 45 func (p *TemplateParamType) String() string { 46 return fmt.Sprintf("TemplateParamType{name: %v}", p.name) 47 } 48 49 func (p *TemplateParamType) idx() int { 50 return p.idxFlag &^ paramAllowUntyped 51 } 52 53 func (p *TemplateParamType) allowUntyped() bool { 54 return (p.idxFlag & paramAllowUntyped) != 0 55 } 56 57 const ( 58 paramAllowUntyped = 0x10000 59 ) 60 61 // ---------------------------------------------------------------------------- 62 63 type unboundFuncParam struct { 64 tBound types.Type 65 typ *TemplateParamType 66 parg *internal.Elem 67 } 68 69 func (p *unboundFuncParam) boundTo(pkg *Package, t types.Type, parg *internal.Elem) { 70 if !p.typ.allowUntyped() { 71 t = DefaultConv(pkg, t, parg) 72 } 73 p.tBound, p.parg = t, parg 74 } 75 76 func (p *unboundFuncParam) Underlying() types.Type { return p } 77 func (p *unboundFuncParam) String() string { 78 return fmt.Sprintf("unboundFuncParam{typ: %v}", p.tBound) 79 } 80 81 type unboundProxyParam struct { 82 real types.Type 83 } 84 85 func (p *unboundProxyParam) Underlying() types.Type { return p } 86 func (p *unboundProxyParam) String() string { 87 return fmt.Sprintf("unboundProxyParam{typ: %v}", p.real) 88 } 89 90 func getElemTypeIf(t types.Type, parg *internal.Elem) types.Type { 91 if parg != nil && parg.CVal != nil { 92 if tb, ok := t.(*types.Basic); ok && (tb.Info()&types.IsFloat) != 0 { 93 if constant.ToInt(parg.CVal).Kind() == constant.Int { 94 return types.Typ[types.UntypedInt] 95 } 96 } 97 } 98 return t 99 } 100 101 type boundTypeError struct { 102 a, b types.Type 103 } 104 105 func (p *boundTypeError) Error() string { 106 return fmt.Sprintf("boundType %v => %v failed", p.a, p.b) 107 } 108 109 func boundType(pkg *Package, arg, param types.Type, parg *internal.Elem) error { 110 switch p := param.(type) { 111 case *unboundFuncParam: // template function param 112 if p.tBound == nil { 113 if !p.typ.contract.Match(pkg, arg) { 114 return fmt.Errorf("TODO: contract.Match %v => %v failed", arg, p.typ.contract) 115 } 116 p.boundTo(pkg, arg, parg) 117 } else if !AssignableConv(pkg, getElemTypeIf(arg, parg), p.tBound, parg) { 118 if !(isUntyped(pkg, p.tBound) && AssignableConv(pkg, p.tBound, arg, p.parg)) { 119 return &boundTypeError{a: arg, b: p.tBound} 120 } 121 p.tBound = arg 122 } 123 return nil 124 case *unboundProxyParam: 125 switch param := p.real.(type) { 126 case *types.Pointer: 127 switch t := arg.(type) { 128 case *types.Pointer: 129 return boundType(pkg, t.Elem(), param.Elem(), nil) // TODO: expr = nil 130 case *refType: 131 return boundType(pkg, t.typ, param.Elem(), nil) 132 } 133 case *types.Array: 134 if t, ok := arg.(*types.Array); ok && param.Len() == t.Len() { 135 return boundType(pkg, t.Elem(), param.Elem(), nil) // TODO: expr = nil 136 } 137 case *types.Map: 138 if t, ok := arg.(*types.Map); ok { 139 if err1 := boundType(pkg, t.Key(), param.Key(), nil); err1 != nil { // TODO: expr = nil 140 return &boundTypeError{a: t.Key(), b: param.Key()} 141 } 142 return boundType(pkg, t.Elem(), param.Elem(), nil) // TODO: expr = nil 143 } 144 case *types.Chan: 145 if t, ok := arg.(*types.Chan); ok { 146 if dir := t.Dir(); dir == param.Dir() || dir == types.SendRecv { 147 return boundType(pkg, t.Elem(), param.Elem(), nil) // TODO: expr = nil 148 } 149 } 150 case *types.Struct: 151 panic("TODO: boundType struct") 152 default: 153 log.Panicln("TODO: boundType - unknown type:", param) 154 } 155 return fmt.Errorf("TODO: bound %v => unboundProxyParam", arg) 156 case *types.Slice: 157 typ := arg 158 retry: 159 switch t := typ.(type) { 160 case *types.Slice: 161 return boundType(pkg, t.Elem(), p.Elem(), nil) // TODO: expr = nil 162 case *types.Named: 163 typ = pkg.cb.getUnderlying(t) 164 goto retry 165 } 166 return fmt.Errorf("TODO: bound slice failed - %v not a slice", arg) 167 case *types.Signature: 168 panic("TODO: boundType function signature") 169 default: 170 if AssignableConv(pkg, arg, param, parg) { 171 return nil 172 } 173 } 174 return fmt.Errorf("TODO: bound %v => %v", arg, param) 175 } 176 177 // Default returns the default "typed" type for an "untyped" type; 178 // it returns the incoming type for all other types. The default type 179 // for untyped nil is untyped nil. 180 func Default(pkg *Package, t types.Type) types.Type { 181 return DefaultConv(pkg, t, nil) 182 } 183 184 func DefaultConv(pkg *Package, t types.Type, pv *Element) types.Type { 185 switch typ := t.(type) { 186 case *types.Named: 187 o := typ.Obj() 188 if at := o.Pkg(); at != nil { 189 name := o.Name() + "_Default" 190 if typName := at.Scope().Lookup(name); typName != nil { 191 if tn, ok := typName.(*types.TypeName); ok && tn.IsAlias() { 192 typ := tn.Type() 193 if pv != nil { 194 if ok = assignable(pkg, t, typ.(*types.Named), pv); !ok { 195 log.Panicln("==> DefaultConv failed:", t, typ) 196 } 197 if debugMatch { 198 log.Println("==> DefaultConv", t, typ) 199 } 200 } 201 return typ 202 } 203 } 204 } 205 case *inferFuncType: 206 return typ.Instance() 207 case *types.Signature: 208 if funcs, ok := CheckOverloadFunc(typ); ok { 209 if len(funcs) == 1 { 210 o := funcs[0] 211 if pv != nil { 212 pv.Val = toObjectExpr(pkg, o) 213 } 214 return o.Type() 215 } 216 log.Panicln("==> DefaultConv failed: overload functions have no default type") 217 } 218 default: 219 return types.Default(t) 220 } 221 return t 222 } 223 224 func ConvertibleTo(pkg *Package, V, T types.Type) bool { 225 pkg.cb.ensureLoaded(V) 226 pkg.cb.ensureLoaded(T) 227 if V == types.Typ[types.UnsafePointer] { 228 if _, ok := T.(*types.Pointer); ok { 229 return true 230 } 231 } 232 return types.ConvertibleTo(V, T) 233 } 234 235 // AssignableTo reports whether a value of type V is assignable to a variable of type T. 236 func AssignableTo(pkg *Package, V, T types.Type) bool { 237 return AssignableConv(pkg, V, T, nil) 238 } 239 240 func AssignableConv(pkg *Package, V, T types.Type, pv *Element) bool { 241 pkg.cb.ensureLoaded(V) 242 pkg.cb.ensureLoaded(T) 243 V, T = realType(V), realType(T) 244 switch v := V.(type) { 245 case *refType: // ref type 246 if t, ok := T.(*types.Pointer); ok { 247 V, T = v.typ, t.Elem() 248 } else { 249 V = v.typ 250 } 251 case *inferFuncType: 252 V = v.Instance() 253 case *types.Signature: 254 if funcs, ok := CheckOverloadFunc(v); ok { 255 if len(funcs) == 1 { 256 o := funcs[0] 257 V = o.Type() 258 if pv != nil { 259 pv.Val = toObjectExpr(pkg, o) 260 pv.Type = V 261 } 262 } 263 } 264 default: 265 V = getElemTypeIf(V, pv) 266 } 267 if types.AssignableTo(V, T) { 268 if t, ok := T.(*types.Basic); ok { // untyped type 269 vkind := V.(*types.Basic).Kind() 270 tkind := t.Kind() 271 switch { 272 case vkind >= types.UntypedInt && vkind <= types.UntypedComplex: 273 if tkind <= types.Uintptr && pv != nil && outOfRange(tkind, pv.CVal) { 274 if debugMatch { 275 log.Printf("==> AssignableConv %v (%v): value is out of %v range", V, pv.CVal, T) 276 } 277 return false 278 } 279 if tkind >= types.UntypedInt && tkind <= types.UntypedComplex { 280 if vkind == tkind || vkind == types.UntypedRune { 281 return true 282 } 283 return tkind != types.UntypedRune && tkind > vkind 284 } 285 if vkind == types.UntypedFloat { 286 return tkind >= types.Float32 287 } 288 if vkind == types.UntypedComplex { 289 return tkind >= types.Complex64 290 } 291 } 292 } 293 return true 294 } 295 if t, ok := T.(*types.Named); ok { 296 ok = assignable(pkg, V, t, pv) 297 if debugMatch && pv != nil { 298 log.Println("==> AssignableConv", V, T, ok) 299 } 300 return ok 301 } 302 if pkg.implicitCast != nil { 303 return pkg.implicitCast(pkg, V, T, pv) 304 } 305 return false 306 } 307 308 func outOfRange(tkind types.BasicKind, cval constant.Value) bool { 309 // untyped int may not a constant. For an example: 310 // func GetValue(shift uint) uint { 311 // return 1 << shift 312 // } 313 if cval == nil { 314 return false 315 } 316 rg := tkindRanges[tkind] 317 return constant.Compare(cval, token.LSS, rg[0]) || constant.Compare(cval, token.GTR, rg[1]) 318 } 319 320 const ( 321 intSize = 32 << (^uint(0) >> 63) 322 intptrSize = 32 << (^uintptr(0) >> 63) 323 maxUint = (1 << intSize) - 1 324 maxUintptr = (1 << intptrSize) - 1 325 maxUint8 = (1 << 8) - 1 326 maxUint16 = (1 << 16) - 1 327 maxUint32 = (1 << 32) - 1 328 maxUint64 = (1 << 64) - 1 329 minInt = -(1 << (intSize - 1)) 330 maxInt = (1 << (intSize - 1)) - 1 331 minInt8 = -(1 << (8 - 1)) 332 maxInt8 = (1 << (8 - 1)) - 1 333 minInt16 = -(1 << (16 - 1)) 334 maxInt16 = (1 << (16 - 1)) - 1 335 minInt32 = -(1 << (32 - 1)) 336 maxInt32 = (1 << (32 - 1)) - 1 337 minInt64 = -(1 << (64 - 1)) 338 maxInt64 = (1 << (64 - 1)) - 1 339 ) 340 341 var ( 342 tkindRanges = [...][2]constant.Value{ 343 types.Int: {constant.MakeInt64(minInt), constant.MakeInt64(maxInt)}, 344 types.Int8: {constant.MakeInt64(minInt8), constant.MakeInt64(maxInt8)}, 345 types.Int16: {constant.MakeInt64(minInt16), constant.MakeInt64(maxInt16)}, 346 types.Int32: {constant.MakeInt64(minInt32), constant.MakeInt64(maxInt32)}, 347 types.Int64: {constant.MakeInt64(minInt64), constant.MakeInt64(maxInt64)}, 348 types.Uint: {constant.MakeInt64(0), constant.MakeUint64(maxUint)}, 349 types.Uint8: {constant.MakeInt64(0), constant.MakeUint64(maxUint8)}, 350 types.Uint16: {constant.MakeInt64(0), constant.MakeUint64(maxUint16)}, 351 types.Uint32: {constant.MakeInt64(0), constant.MakeUint64(maxUint32)}, 352 types.Uint64: {constant.MakeInt64(0), constant.MakeUint64(maxUint64)}, 353 types.Uintptr: {constant.MakeInt64(0), constant.MakeUint64(maxUintptr)}, 354 } 355 ) 356 357 func assignable(pkg *Package, v types.Type, t *types.Named, pv *internal.Elem) bool { 358 o := t.Obj() 359 if at := o.Pkg(); at != nil { 360 tname := o.Name() 361 scope := at.Scope() 362 name := tname + "_Init" 363 if ini := scope.Lookup(name); ini != nil { 364 if v == types.Typ[types.UntypedInt] { 365 switch t { 366 case pkg.utBigInt, pkg.utBigRat: 367 if pv != nil { 368 switch cv := constant.Val(pv.CVal).(type) { 369 case *big.Int: 370 nv := pkg.cb.UntypedBigInt(cv).stk.Pop() 371 pv.Type, pv.Val = nv.Type, nv.Val 372 } 373 } 374 return true 375 } 376 } 377 if pv.CVal != nil { 378 if checkUntypedOverflows(scope, tname, pv) { 379 return false 380 } 381 } 382 fn := &internal.Elem{Val: toObjectExpr(pkg, ini), Type: ini.Type()} 383 arg := &internal.Elem{Type: v} 384 if pv != nil { 385 arg.Val, arg.CVal, arg.Src = pv.Val, pv.CVal, pv.Src 386 } 387 ret, err := matchFuncCall(pkg, fn, []*internal.Elem{arg}, 0) 388 if err == nil { 389 if pv != nil { 390 pv.Val = ret.Val 391 } 392 return true 393 } 394 } 395 } 396 return false 397 } 398 399 func ComparableTo(pkg *Package, varg, targ *Element) bool { 400 V, T := varg.Type, targ.Type 401 if v, ok := V.(*types.Basic); ok { 402 if (v.Info() & types.IsUntyped) != 0 { 403 return untypedComparable(pkg, v, varg, T) 404 } 405 } 406 if t, ok := T.(*types.Basic); ok { 407 if (t.Info() & types.IsUntyped) != 0 { 408 return untypedComparable(pkg, t, targ, V) 409 } 410 } 411 if getUnderlying(pkg, V) == getUnderlying(pkg, T) { 412 return true 413 } 414 return AssignableConv(pkg, V, T, varg) || AssignableConv(pkg, T, V, targ) 415 } 416 417 func untypedComparable(pkg *Package, v *types.Basic, varg *Element, t types.Type) bool { 418 kind := v.Kind() 419 if kind == types.UntypedNil { 420 retry: 421 switch tt := t.(type) { 422 case *types.Interface, *types.Slice, *types.Pointer, *types.Map, *types.Signature, *types.Chan: 423 return true 424 case *types.Basic: 425 return tt.Kind() == types.UnsafePointer // invalid: nil == nil 426 case *types.Named: 427 t = pkg.cb.getUnderlying(tt) 428 goto retry 429 } 430 } else { 431 switch u := getUnderlying(pkg, t).(type) { 432 case *types.Basic: 433 switch v.Kind() { 434 case types.UntypedBool: 435 return (u.Info() & types.IsBoolean) != 0 436 case types.UntypedFloat: 437 if constant.ToInt(varg.CVal).Kind() != constant.Int { 438 return (u.Info() & (types.IsFloat | types.IsComplex)) != 0 439 } 440 fallthrough 441 case types.UntypedInt, types.UntypedRune: 442 return (u.Info() & types.IsNumeric) != 0 443 case types.UntypedComplex: 444 return (u.Info() & types.IsComplex) != 0 445 case types.UntypedString: 446 return (u.Info() & types.IsString) != 0 447 } 448 case *types.Interface: 449 return u.Empty() 450 } 451 } 452 return false 453 } 454 455 // NewSignature returns a new function type for the given receiver, parameters, 456 // and results, either of which may be nil. If variadic is set, the function 457 // is variadic, it must have at least one parameter, and the last parameter 458 // must be of unnamed slice type. 459 func NewSignature(recv *types.Var, params, results *types.Tuple, variadic bool) *types.Signature { 460 return types.NewSignatureType(recv, nil, nil, params, results, variadic) 461 } 462 463 // NewSlice returns a new slice type for the given element type. 464 func NewSlice(elem types.Type) types.Type { 465 return types.NewSlice(elem) 466 } 467 468 // NewMap returns a new map for the given key and element types. 469 func NewMap(key, elem types.Type) types.Type { 470 var t types.Type = types.NewMap(key, elem) 471 if isUnboundParam(key) || isUnboundParam(elem) { 472 t = &unboundProxyParam{real: t} 473 } 474 return t 475 } 476 477 // NewChan returns a new channel type for the given direction and element type. 478 func NewChan(dir types.ChanDir, elem types.Type) types.Type { 479 var t types.Type = types.NewChan(dir, elem) 480 if isUnboundParam(elem) { 481 t = &unboundProxyParam{real: t} 482 } 483 return t 484 } 485 486 // NewArray returns a new array type for the given element type and length. 487 // A negative length indicates an unknown length. 488 func NewArray(elem types.Type, len int64) types.Type { 489 var t types.Type = types.NewArray(elem, len) 490 if isUnboundParam(elem) { 491 t = &unboundProxyParam{real: t} 492 } 493 return t 494 } 495 496 // NewPointer returns a new pointer type for the given element (base) type. 497 func NewPointer(elem types.Type) types.Type { 498 var t types.Type = types.NewPointer(elem) 499 if isUnboundParam(elem) { 500 t = &unboundProxyParam{real: t} 501 } 502 return t 503 } 504 505 func isUnboundParam(typ types.Type) bool { 506 switch t := typ.(type) { 507 case *unboundFuncParam: 508 return true 509 case *TemplateParamType: 510 return true 511 case *unboundProxyParam: 512 return true 513 case *types.Slice: 514 return isUnboundParam(t.Elem()) 515 case *types.Signature: 516 return isUnboundSignature(t) 517 } 518 return false 519 } 520 521 func isUnboundVar(v *types.Var) bool { 522 if v == nil { 523 return false 524 } 525 return isUnboundParam(v.Type()) 526 } 527 528 func isUnboundTuple(t *types.Tuple) bool { 529 for i, n := 0, t.Len(); i < n; i++ { 530 if isUnboundVar(t.At(i)) { 531 return true 532 } 533 } 534 return false 535 } 536 537 func isUnboundSignature(sig *types.Signature) bool { 538 return isUnboundVar(sig.Recv()) || 539 isUnboundTuple(sig.Params()) || 540 isUnboundTuple(sig.Results()) 541 } 542 543 // ---------------------------------------------------------------------------- 544 545 type instantiated struct { 546 tparams []*unboundFuncParam 547 results bool 548 } 549 550 func (p *instantiated) normalize(t types.Type) types.Type { 551 if p != nil && p.results { 552 t, _ = toNormalize(p.tparams, t) 553 } 554 return t 555 } 556 557 func (p *instantiated) normalizeTuple(t *types.Tuple) *types.Tuple { 558 if p != nil && p.results { 559 t, _ = toNormalizeTuple(p.tparams, t) 560 } 561 return t 562 } 563 564 func toNormalize(tparams []*unboundFuncParam, typ types.Type) (types.Type, bool) { 565 switch tt := typ.(type) { 566 case *unboundFuncParam: 567 if tt.tBound == nil { 568 log.Panicln("TODO: unbound type -", tt.typ.name) 569 } 570 return tt.tBound, true 571 case *unboundProxyParam: 572 switch t := tt.real.(type) { 573 case *types.Pointer: 574 elem, _ := toNormalize(tparams, t.Elem()) 575 return types.NewPointer(elem), true 576 case *types.Array: 577 elem, _ := toNormalize(tparams, t.Elem()) 578 return types.NewArray(elem, t.Len()), true 579 case *types.Map: 580 key, _ := toNormalize(tparams, t.Key()) 581 elem, _ := toNormalize(tparams, t.Elem()) 582 return types.NewMap(key, elem), true 583 case *types.Chan: 584 elem, _ := toNormalize(tparams, t.Elem()) 585 return types.NewChan(t.Dir(), elem), true 586 case *types.Struct: 587 panic("TODO: toNormalize struct") 588 default: 589 log.Panicln("TODO: toNormalize - unknown type:", t) 590 } 591 case *unboundType: 592 if tt.tBound == nil { 593 log.Panicln("TODO: unbound type") 594 } 595 return tt.tBound, true 596 case *types.Slice: 597 if elem, ok := toNormalize(tparams, tt.Elem()); ok { 598 return types.NewSlice(elem), true 599 } 600 case *types.Signature: 601 return toNormalizeSignature(tparams, tt) 602 } 603 return typ, false 604 } 605 606 func toNormalizeVar(tparams []*unboundFuncParam, param *types.Var) (*types.Var, bool) { 607 if param == nil { 608 return nil, false 609 } 610 if t, changed := toNormalize(tparams, param.Type()); changed { 611 return types.NewParam(param.Pos(), param.Pkg(), param.Name(), t), true 612 } 613 return param, false 614 } 615 616 func toNormalizeTuple(tparams []*unboundFuncParam, params *types.Tuple) (*types.Tuple, bool) { 617 n := params.Len() 618 vars := make([]*types.Var, n) 619 var ok, changed bool 620 for i := 0; i < n; i++ { 621 if vars[i], ok = toNormalizeVar(tparams, params.At(i)); ok { 622 changed = true 623 } 624 } 625 if changed { 626 return types.NewTuple(vars...), true 627 } 628 return params, false 629 } 630 631 func toNormalizeSignature( 632 tparams []*unboundFuncParam, sig *types.Signature) (*types.Signature, bool) { 633 recv, ok1 := toNormalizeVar(tparams, sig.Recv()) 634 params, ok2 := toNormalizeTuple(tparams, sig.Params()) 635 results, ok3 := toNormalizeTuple(tparams, sig.Results()) 636 if ok1 || ok2 || ok3 { 637 return types.NewSignatureType(recv, nil, nil, params, results, sig.Variadic()), true 638 } 639 return sig, false 640 } 641 642 // ---------------------------------------------------------------------------- 643 644 const ( 645 tokUnaryFlag token.Token = 0x80000 646 tokFlagApproxType token.Token = 0x40000 // ~T 647 tokFlagAll = tokUnaryFlag | tokFlagApproxType 648 ) 649 650 // TemplateSignature: type of template function 651 type TemplateSignature struct { 652 params []*TemplateParamType 653 sig *types.Signature 654 tokFlag token.Token // tok + unary flag, only for builtin operator 655 } 656 657 func (p *TemplateSignature) tok() token.Token { 658 return p.tokFlag &^ tokFlagAll 659 } 660 661 func (p *TemplateSignature) hasApproxType() bool { 662 return (p.tokFlag & tokFlagApproxType) != 0 663 } 664 665 func (p *TemplateSignature) isOp() bool { 666 return (p.tokFlag &^ tokFlagApproxType) != 0 667 } 668 669 func (p *TemplateSignature) isUnaryOp() bool { 670 return (p.tokFlag & tokUnaryFlag) != 0 671 } 672 673 func assertValidTemplateSignature(tsig *TemplateSignature) { 674 for i, param := range tsig.params { 675 if param.idx() != i { 676 panic("TODO: invalid TemplateSignature - incorrect index") 677 } 678 } 679 } 680 681 // NewTemplateSignature creates type of a template function. 682 func NewTemplateSignature( 683 templateParams []*TemplateParamType, 684 recv *types.Var, params, results *types.Tuple, variadic bool, tok ...token.Token) *TemplateSignature { 685 686 var tokFlag token.Token 687 if tok != nil { 688 tokFlag = tok[0] 689 } 690 tsig := &TemplateSignature{ 691 params: templateParams, 692 sig: types.NewSignatureType(recv, nil, nil, params, results, variadic), 693 tokFlag: tokFlag, 694 } 695 if tsig.isOp() { 696 for _, tparam := range templateParams { 697 tparam.idxFlag |= paramAllowUntyped 698 } 699 } 700 assertValidTemplateSignature(tsig) 701 return tsig 702 } 703 704 func (p *TemplateSignature) Underlying() types.Type { return p } 705 func (p *TemplateSignature) String() string { 706 return fmt.Sprintf("TemplateSignature{%v}", p.sig) 707 } 708 709 // TODO: check name 710 func (p *TemplateSignature) instantiate() (*types.Signature, *instantiated) { 711 tparams := make([]*unboundFuncParam, len(p.params)) 712 for i, param := range p.params { 713 tparams[i] = &unboundFuncParam{typ: param} 714 } 715 sig, _, instantiatedResults := toInstantiateSignature(tparams, p.sig) 716 return sig, &instantiated{tparams: tparams, results: instantiatedResults} 717 } 718 719 func toInstantiate(tparams []*unboundFuncParam, typ types.Type) (types.Type, bool) { 720 switch tt := typ.(type) { 721 case *TemplateParamType: 722 return tparams[tt.idx()], true 723 case *unboundProxyParam: 724 switch t := tt.real.(type) { 725 case *types.Pointer: 726 elem, _ := toInstantiate(tparams, t.Elem()) 727 return &unboundProxyParam{types.NewPointer(elem)}, true 728 case *types.Array: 729 elem, _ := toInstantiate(tparams, t.Elem()) 730 return &unboundProxyParam{types.NewArray(elem, t.Len())}, true 731 case *types.Map: 732 key, _ := toInstantiate(tparams, t.Key()) 733 elem, _ := toInstantiate(tparams, t.Elem()) 734 return &unboundProxyParam{types.NewMap(key, elem)}, true 735 case *types.Chan: 736 elem, _ := toInstantiate(tparams, t.Elem()) 737 return &unboundProxyParam{types.NewChan(t.Dir(), elem)}, true 738 case *types.Struct: 739 panic("TODO: instantiate struct") 740 default: 741 log.Panicln("TODO: toInstantiate - unknown type:", t) 742 } 743 case *types.Slice: 744 if elem, ok := toInstantiate(tparams, tt.Elem()); ok { 745 return types.NewSlice(elem), true 746 } 747 case *types.Signature: 748 t, ok, _ := toInstantiateSignature(tparams, tt) 749 return t, ok 750 } 751 return typ, false 752 } 753 754 func toInstantiateVar(tparams []*unboundFuncParam, param *types.Var) (*types.Var, bool) { 755 if param == nil { 756 return nil, false 757 } 758 if t, changed := toInstantiate(tparams, param.Type()); changed { 759 return types.NewParam(param.Pos(), param.Pkg(), param.Name(), t), true 760 } 761 return param, false 762 } 763 764 func toInstantiateTuple(tparams []*unboundFuncParam, params *types.Tuple) (*types.Tuple, bool) { 765 n := params.Len() 766 vars := make([]*types.Var, n) 767 var ok, changed bool 768 for i := 0; i < n; i++ { 769 if vars[i], ok = toInstantiateVar(tparams, params.At(i)); ok { 770 changed = true 771 } 772 } 773 if changed { 774 return types.NewTuple(vars...), true 775 } 776 return params, false 777 } 778 779 func toInstantiateSignature( 780 tparams []*unboundFuncParam, sig *types.Signature) (*types.Signature, bool, bool) { 781 recv, ok1 := toInstantiateVar(tparams, sig.Recv()) 782 params, ok2 := toInstantiateTuple(tparams, sig.Params()) 783 results, ok3 := toInstantiateTuple(tparams, sig.Results()) 784 if ok1 || ok2 || ok3 { 785 return types.NewSignatureType(recv, nil, nil, params, results, sig.Variadic()), true, ok3 786 } 787 return sig, false, ok3 788 } 789 790 // ---------------------------------------------------------------------------- 791 792 // TemplateFunc: template function 793 type TemplateFunc struct { 794 *types.Func 795 sig *TemplateSignature 796 } 797 798 // NewTemplateFunc creates a template function. 799 func NewTemplateFunc(pos token.Pos, pkg *types.Package, name string, tsig *TemplateSignature) *TemplateFunc { 800 return &TemplateFunc{sig: tsig, Func: types.NewFunc(pos, pkg, name, tsig.sig)} 801 } 802 803 // NewTemplateFunc return the type of specified template function. 804 func (p *TemplateFunc) Type() types.Type { 805 return p.sig 806 } 807 808 // ----------------------------------------------------------------------------