subst.go (17910B)
1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 import ( 8 "fmt" 9 "go/types" 10 11 "golang.org/x/tools/go/types/typeutil" 12 "golang.org/x/tools/internal/aliases" 13 ) 14 15 // subster defines a type substitution operation of a set of type parameters 16 // to type parameter free replacement types. Substitution is done within 17 // the context of a package-level function instantiation. *Named types 18 // declared in the function are unique to the instantiation. 19 // 20 // For example, given a parameterized function F 21 // 22 // func F[S, T any]() any { 23 // type X struct{ s S; next *X } 24 // var p *X 25 // return p 26 // } 27 // 28 // calling the instantiation F[string, int]() returns an interface 29 // value (*X[string,int], nil) where the underlying value of 30 // X[string,int] is a struct{s string; next *X[string,int]}. 31 // 32 // A nil *subster is a valid, empty substitution map. It always acts as 33 // the identity function. This allows for treating parameterized and 34 // non-parameterized functions identically while compiling to ssa. 35 // 36 // Not concurrency-safe. 37 // 38 // Note: Some may find it helpful to think through some of the most 39 // complex substitution cases using lambda calculus inspired notation. 40 // subst.typ() solves evaluating a type expression E 41 // within the body of a function Fn[m] with the type parameters m 42 // once we have applied the type arguments N. 43 // We can succinctly write this as a function application: 44 // 45 // ((λm. E) N) 46 // 47 // go/types does not provide this interface directly. 48 // So what subster provides is a type substitution operation 49 // 50 // E[m:=N] 51 type subster struct { 52 replacements map[*types.TypeParam]types.Type // values should contain no type params 53 cache map[types.Type]types.Type // cache of subst results 54 origin *types.Func // types.Objects declared within this origin function are unique within this context 55 ctxt *types.Context // speeds up repeated instantiations 56 uniqueness typeutil.Map // determines the uniqueness of the instantiations within the function 57 // TODO(taking): consider adding Pos 58 } 59 60 // Returns a subster that replaces rtparams[i] with rtargs[i] and tparams[i] with targs[i]. 61 // Uses ctxt as a cache. rtargs and targs should not contain any types in rtparams or tparams. 62 // fn is the generic function for which we are substituting. 63 func makeSubster(ctxt *types.Context, fn *types.Func, rtparams *types.TypeParamList, rtargs []types.Type, tparams *types.TypeParamList, targs []types.Type) *subster { 64 got := len(rtargs) + len(targs) 65 want := rtparams.Len() + tparams.Len() 66 if got != want { 67 panic(fmt.Sprintf("makeSubster argument count must match: got %d; want %d", got, want)) 68 } 69 70 subst := &subster{ 71 replacements: make(map[*types.TypeParam]types.Type, want), 72 cache: make(map[types.Type]types.Type), 73 origin: fn.Origin(), 74 ctxt: ctxt, 75 } 76 for i := 0; i < rtparams.Len(); i++ { 77 subst.replacements[rtparams.At(i)] = rtargs[i] 78 } 79 for i := 0; i < tparams.Len(); i++ { 80 subst.replacements[tparams.At(i)] = targs[i] 81 } 82 return subst 83 } 84 85 // typ returns the type of t with the type parameter tparams[i] substituted 86 // for the type targs[i] where subst was created using tparams and targs. 87 func (subst *subster) typ(t types.Type) (res types.Type) { 88 if subst == nil { 89 return t // A nil subst is type preserving. 90 } 91 if r, ok := subst.cache[t]; ok { 92 return r 93 } 94 defer func() { 95 subst.cache[t] = res 96 }() 97 98 switch t := t.(type) { 99 case *types.TypeParam: 100 if r := subst.replacements[t]; r != nil { 101 return r 102 } 103 return t 104 105 case *types.Basic: 106 return t 107 108 case *types.Array: 109 if r := subst.typ(t.Elem()); r != t.Elem() { 110 return types.NewArray(r, t.Len()) 111 } 112 return t 113 114 case *types.Slice: 115 if r := subst.typ(t.Elem()); r != t.Elem() { 116 return types.NewSlice(r) 117 } 118 return t 119 120 case *types.Pointer: 121 if r := subst.typ(t.Elem()); r != t.Elem() { 122 return types.NewPointer(r) 123 } 124 return t 125 126 case *types.Tuple: 127 return subst.tuple(t) 128 129 case *types.Struct: 130 return subst.struct_(t) 131 132 case *types.Map: 133 key := subst.typ(t.Key()) 134 elem := subst.typ(t.Elem()) 135 if key != t.Key() || elem != t.Elem() { 136 return types.NewMap(key, elem) 137 } 138 return t 139 140 case *types.Chan: 141 if elem := subst.typ(t.Elem()); elem != t.Elem() { 142 return types.NewChan(t.Dir(), elem) 143 } 144 return t 145 146 case *types.Signature: 147 return subst.signature(t) 148 149 case *types.Union: 150 return subst.union(t) 151 152 case *types.Interface: 153 return subst.interface_(t) 154 155 case *types.Alias: 156 return subst.alias(t) 157 158 case *types.Named: 159 return subst.named(t) 160 161 case *opaqueType: 162 return t // opaque types are never substituted 163 164 default: 165 panic("unreachable") 166 } 167 } 168 169 // types returns the result of {subst.typ(ts[i])}. 170 func (subst *subster) types(ts []types.Type) []types.Type { 171 res := make([]types.Type, len(ts)) 172 for i := range ts { 173 res[i] = subst.typ(ts[i]) 174 } 175 return res 176 } 177 178 func (subst *subster) tuple(t *types.Tuple) *types.Tuple { 179 if t != nil { 180 if vars := subst.varlist(t); vars != nil { 181 return types.NewTuple(vars...) 182 } 183 } 184 return t 185 } 186 187 type varlist interface { 188 At(i int) *types.Var 189 Len() int 190 } 191 192 // fieldlist is an adapter for structs for the varlist interface. 193 type fieldlist struct { 194 str *types.Struct 195 } 196 197 func (fl fieldlist) At(i int) *types.Var { return fl.str.Field(i) } 198 func (fl fieldlist) Len() int { return fl.str.NumFields() } 199 200 func (subst *subster) struct_(t *types.Struct) *types.Struct { 201 if t != nil { 202 if fields := subst.varlist(fieldlist{t}); fields != nil { 203 tags := make([]string, t.NumFields()) 204 for i, n := 0, t.NumFields(); i < n; i++ { 205 tags[i] = t.Tag(i) 206 } 207 return types.NewStruct(fields, tags) 208 } 209 } 210 return t 211 } 212 213 // varlist returns subst(in[i]) or return nils if subst(v[i]) == v[i] for all i. 214 func (subst *subster) varlist(in varlist) []*types.Var { 215 var out []*types.Var // nil => no updates 216 for i, n := 0, in.Len(); i < n; i++ { 217 v := in.At(i) 218 w := subst.var_(v) 219 if v != w && out == nil { 220 out = make([]*types.Var, n) 221 for j := 0; j < i; j++ { 222 out[j] = in.At(j) 223 } 224 } 225 if out != nil { 226 out[i] = w 227 } 228 } 229 return out 230 } 231 232 func (subst *subster) var_(v *types.Var) *types.Var { 233 if v != nil { 234 if typ := subst.typ(v.Type()); typ != v.Type() { 235 if v.IsField() { 236 return types.NewField(v.Pos(), v.Pkg(), v.Name(), typ, v.Embedded()) 237 } 238 return types.NewParam(v.Pos(), v.Pkg(), v.Name(), typ) 239 } 240 } 241 return v 242 } 243 244 func (subst *subster) union(u *types.Union) *types.Union { 245 var out []*types.Term // nil => no updates 246 247 for i, n := 0, u.Len(); i < n; i++ { 248 t := u.Term(i) 249 r := subst.typ(t.Type()) 250 if r != t.Type() && out == nil { 251 out = make([]*types.Term, n) 252 for j := 0; j < i; j++ { 253 out[j] = u.Term(j) 254 } 255 } 256 if out != nil { 257 out[i] = types.NewTerm(t.Tilde(), r) 258 } 259 } 260 261 if out != nil { 262 return types.NewUnion(out) 263 } 264 return u 265 } 266 267 func (subst *subster) interface_(iface *types.Interface) *types.Interface { 268 if iface == nil { 269 return nil 270 } 271 272 // methods for the interface. Initially nil if there is no known change needed. 273 // Signatures for the method where recv is nil. NewInterfaceType fills in the receivers. 274 var methods []*types.Func 275 initMethods := func(n int) { // copy first n explicit methods 276 methods = make([]*types.Func, iface.NumExplicitMethods()) 277 for i := range n { 278 f := iface.ExplicitMethod(i) 279 norecv := changeRecv(f.Type().(*types.Signature), nil) 280 methods[i] = types.NewFunc(f.Pos(), f.Pkg(), f.Name(), norecv) 281 } 282 } 283 for i := 0; i < iface.NumExplicitMethods(); i++ { 284 f := iface.ExplicitMethod(i) 285 // On interfaces, we need to cycle break on anonymous interface types 286 // being in a cycle with their signatures being in cycles with their receivers 287 // that do not go through a Named. 288 norecv := changeRecv(f.Type().(*types.Signature), nil) 289 sig := subst.typ(norecv) 290 if sig != norecv && methods == nil { 291 initMethods(i) 292 } 293 if methods != nil { 294 methods[i] = types.NewFunc(f.Pos(), f.Pkg(), f.Name(), sig.(*types.Signature)) 295 } 296 } 297 298 var embeds []types.Type 299 initEmbeds := func(n int) { // copy first n embedded types 300 embeds = make([]types.Type, iface.NumEmbeddeds()) 301 for i := range n { 302 embeds[i] = iface.EmbeddedType(i) 303 } 304 } 305 for i := 0; i < iface.NumEmbeddeds(); i++ { 306 e := iface.EmbeddedType(i) 307 r := subst.typ(e) 308 if e != r && embeds == nil { 309 initEmbeds(i) 310 } 311 if embeds != nil { 312 embeds[i] = r 313 } 314 } 315 316 if methods == nil && embeds == nil { 317 return iface 318 } 319 if methods == nil { 320 initMethods(iface.NumExplicitMethods()) 321 } 322 if embeds == nil { 323 initEmbeds(iface.NumEmbeddeds()) 324 } 325 return types.NewInterfaceType(methods, embeds).Complete() 326 } 327 328 func (subst *subster) alias(t *types.Alias) types.Type { 329 // See subster.named. This follows the same strategy. 330 tparams := t.TypeParams() 331 targs := t.TypeArgs() 332 tname := t.Obj() 333 torigin := t.Origin() 334 335 if !declaredWithin(tname, subst.origin) { 336 // t is declared outside of the function origin. So t is a package level type alias. 337 if targs.Len() == 0 { 338 // No type arguments so no instantiation needed. 339 return t 340 } 341 342 // Instantiate with the substituted type arguments. 343 newTArgs := subst.typelist(targs) 344 return subst.instantiate(torigin, newTArgs) 345 } 346 347 if targs.Len() == 0 { 348 // t is declared within the function origin and has no type arguments. 349 // 350 // Example: This corresponds to A or B in F, but not A[int]: 351 // 352 // func F[T any]() { 353 // type A[S any] = struct{t T, s S} 354 // type B = T 355 // var x A[int] 356 // ... 357 // } 358 // 359 // This is somewhat different than *Named as *Alias cannot be created recursively. 360 361 // Copy and substitute type params. 362 var newTParams []*types.TypeParam 363 for cur := range tparams.TypeParams() { 364 cobj := cur.Obj() 365 cname := types.NewTypeName(cobj.Pos(), cobj.Pkg(), cobj.Name(), nil) 366 ntp := types.NewTypeParam(cname, nil) 367 subst.cache[cur] = ntp // See the comment "Note: Subtle" in subster.named. 368 newTParams = append(newTParams, ntp) 369 } 370 371 // Substitute rhs. 372 rhs := subst.typ(t.Rhs()) 373 374 // Create the fresh alias. 375 obj := aliases.New(tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams) 376 377 // Substitute into all of the constraints after they are created. 378 for i, ntp := range newTParams { 379 bound := tparams.At(i).Constraint() 380 ntp.SetConstraint(subst.typ(bound)) 381 } 382 return obj.Type() 383 } 384 385 // t is declared within the function origin and has type arguments. 386 // 387 // Example: This corresponds to A[int] in F. Cases A and B are handled above. 388 // func F[T any]() { 389 // type A[S any] = struct{t T, s S} 390 // type B = T 391 // var x A[int] 392 // ... 393 // } 394 subOrigin := subst.typ(torigin) 395 subTArgs := subst.typelist(targs) 396 return subst.instantiate(subOrigin, subTArgs) 397 } 398 399 func (subst *subster) named(t *types.Named) types.Type { 400 // A Named type is a user defined type. 401 // Ignoring generics, Named types are canonical: they are identical if 402 // and only if they have the same defining symbol. 403 // Generics complicate things, both if the type definition itself is 404 // parameterized, and if the type is defined within the scope of a 405 // parameterized function. In this case, two named types are identical if 406 // and only if their identifying symbols are identical, and all type 407 // arguments bindings in scope of the named type definition (including the 408 // type parameters of the definition itself) are equivalent. 409 // 410 // Notably: 411 // 1. For type definition type T[P1 any] struct{}, T[A] and T[B] are identical 412 // only if A and B are identical. 413 // 2. Inside the generic func Fn[m any]() any { type T struct{}; return T{} }, 414 // the result of Fn[A] and Fn[B] have identical type if and only if A and 415 // B are identical. 416 // 3. Both 1 and 2 could apply, such as in 417 // func F[m any]() any { type T[x any] struct{}; return T{} } 418 // 419 // A subster replaces type parameters within a function scope, and therefore must 420 // also replace free type parameters in the definitions of local types. 421 // 422 // Note: There are some detailed notes sprinkled throughout that borrow from 423 // lambda calculus notation. These contain some over simplifying math. 424 // 425 // LC: One way to think about subster is that it is a way of evaluating 426 // ((λm. E) N) as E[m:=N]. 427 // Each Named type t has an object *TypeName within a scope S that binds an 428 // underlying type expression U. U can refer to symbols within S (+ S's ancestors). 429 // Let x = t.TypeParams() and A = t.TypeArgs(). 430 // Each Named type t is then either: 431 // U where len(x) == 0 && len(A) == 0 432 // λx. U where len(x) != 0 && len(A) == 0 433 // ((λx. U) A) where len(x) == len(A) 434 // In each case, we will evaluate t[m:=N]. 435 tparams := t.TypeParams() // x 436 targs := t.TypeArgs() // A 437 438 if !declaredWithin(t.Obj(), subst.origin) { 439 // t is declared outside of Fn[m]. 440 // 441 // In this case, we can skip substituting t.Underlying(). 442 // The underlying type cannot refer to the type parameters. 443 // 444 // LC: Let free(E) be the set of free type parameters in an expression E. 445 // Then whenever m ∉ free(E), then E = E[m:=N]. 446 // t ∉ Scope(fn) so therefore m ∉ free(U) and m ∩ x = ∅. 447 if targs.Len() == 0 { 448 // t has no type arguments. So it does not need to be instantiated. 449 // 450 // This is the normal case in real Go code, where t is not parameterized, 451 // declared at some package scope, and m is a TypeParam from a parameterized 452 // function F[m] or method. 453 // 454 // LC: m ∉ free(A) lets us conclude m ∉ free(t). So t=t[m:=N]. 455 return t 456 } 457 458 // t is declared outside of Fn[m] and has type arguments. 459 // The type arguments may contain type parameters m so 460 // substitute the type arguments, and instantiate the substituted 461 // type arguments. 462 // 463 // LC: Evaluate this as ((λx. U) A') where A' = A[m := N]. 464 newTArgs := subst.typelist(targs) 465 return subst.instantiate(t.Origin(), newTArgs) 466 } 467 468 // t is declared within Fn[m]. 469 470 if targs.Len() == 0 { // no type arguments? 471 assert(t == t.Origin(), "local parameterized type abstraction must be an origin type") 472 473 // t has no type arguments. 474 // The underlying type of t may contain the function's type parameters, 475 // replace these, and create a new type. 476 // 477 // Subtle: We short circuit substitution and use a newly created type in 478 // subst, i.e. cache[t]=fresh, to preemptively replace t with fresh 479 // in recursive types during traversal. This both breaks infinite cycles 480 // and allows for constructing types with the replacement applied in 481 // subst.typ(U). 482 // 483 // A new copy of the Named and Typename (and constraints) per function 484 // instantiation matches the semantics of Go, which treats all function 485 // instantiations F[N] as having distinct local types. 486 // 487 // LC: x.Len()=0 can be thought of as a special case of λx. U. 488 // LC: Evaluate (λx. U)[m:=N] as (λx'. U') where U'=U[x:=x',m:=N]. 489 tname := t.Obj() 490 obj := types.NewTypeName(tname.Pos(), tname.Pkg(), tname.Name(), nil) 491 fresh := types.NewNamed(obj, nil, nil) 492 var newTParams []*types.TypeParam 493 for cur := range tparams.TypeParams() { 494 cobj := cur.Obj() 495 cname := types.NewTypeName(cobj.Pos(), cobj.Pkg(), cobj.Name(), nil) 496 ntp := types.NewTypeParam(cname, nil) 497 subst.cache[cur] = ntp 498 newTParams = append(newTParams, ntp) 499 } 500 fresh.SetTypeParams(newTParams) 501 subst.cache[t] = fresh 502 subst.cache[fresh] = fresh 503 fresh.SetUnderlying(subst.typ(t.Underlying())) 504 // Substitute into all of the constraints after they are created. 505 for i, ntp := range newTParams { 506 bound := tparams.At(i).Constraint() 507 ntp.SetConstraint(subst.typ(bound)) 508 } 509 return fresh 510 } 511 512 // t is defined within Fn[m] and t has type arguments (an instantiation). 513 // We reduce this to the two cases above: 514 // (1) substitute the function's type parameters into t.Origin(). 515 // (2) substitute t's type arguments A and instantiate the updated t.Origin() with these. 516 // 517 // LC: Evaluate ((λx. U) A)[m:=N] as (t' A') where t' = (λx. U)[m:=N] and A'=A [m:=N] 518 subOrigin := subst.typ(t.Origin()) 519 subTArgs := subst.typelist(targs) 520 return subst.instantiate(subOrigin, subTArgs) 521 } 522 523 func (subst *subster) instantiate(orig types.Type, targs []types.Type) types.Type { 524 i, err := types.Instantiate(subst.ctxt, orig, targs, false) 525 assert(err == nil, "failed to Instantiate named (Named or Alias) type") 526 if c, _ := subst.uniqueness.At(i).(types.Type); c != nil { 527 return c.(types.Type) 528 } 529 subst.uniqueness.Set(i, i) 530 return i 531 } 532 533 func (subst *subster) typelist(l *types.TypeList) []types.Type { 534 res := make([]types.Type, l.Len()) 535 for i := 0; i < l.Len(); i++ { 536 res[i] = subst.typ(l.At(i)) 537 } 538 return res 539 } 540 541 func (subst *subster) signature(t *types.Signature) types.Type { 542 tparams := t.TypeParams() 543 544 // We are choosing not to support tparams.Len() > 0 until a need has been observed in practice. 545 // 546 // There are some known usages for types.Types coming from types.{Eval,CheckExpr}. 547 // To support tparams.Len() > 0, we just need to do the following [pseudocode]: 548 // targs := {subst.replacements[tparams[i]]]}; Instantiate(ctxt, t, targs, false) 549 550 assert(tparams.Len() == 0, "Substituting types.Signatures with generic functions are currently unsupported.") 551 552 // Either: 553 // (1)non-generic function. 554 // no type params to substitute 555 // (2)generic method and recv needs to be substituted. 556 557 // Receivers can be either: 558 // named 559 // pointer to named 560 // interface 561 // nil 562 // interface is the problematic case. We need to cycle break there! 563 recv := subst.var_(t.Recv()) 564 params := subst.tuple(t.Params()) 565 results := subst.tuple(t.Results()) 566 if recv != t.Recv() || params != t.Params() || results != t.Results() { 567 return types.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) 568 } 569 return t 570 }