src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }