github.com/bir3/gocompiler@v0.9.2202/src/go/types/subst.go (about)

     1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
     2  
     3  // Copyright 2018 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // This file implements type parameter substitution.
     8  
     9  package types
    10  
    11  import (
    12  	"github.com/bir3/gocompiler/src/go/token"
    13  )
    14  
    15  type substMap map[*TypeParam]Type
    16  
    17  // makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
    18  // If targs[i] is nil, tpars[i] is not substituted.
    19  func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
    20  	assert(len(tpars) == len(targs))
    21  	proj := make(substMap, len(tpars))
    22  	for i, tpar := range tpars {
    23  		proj[tpar] = targs[i]
    24  	}
    25  	return proj
    26  }
    27  
    28  // makeRenameMap is like makeSubstMap, but creates a map used to rename type
    29  // parameters in from with the type parameters in to.
    30  func makeRenameMap(from, to []*TypeParam) substMap {
    31  	assert(len(from) == len(to))
    32  	proj := make(substMap, len(from))
    33  	for i, tpar := range from {
    34  		proj[tpar] = to[i]
    35  	}
    36  	return proj
    37  }
    38  
    39  func (m substMap) empty() bool {
    40  	return len(m) == 0
    41  }
    42  
    43  func (m substMap) lookup(tpar *TypeParam) Type {
    44  	if t := m[tpar]; t != nil {
    45  		return t
    46  	}
    47  	return tpar
    48  }
    49  
    50  // subst returns the type typ with its type parameters tpars replaced by the
    51  // corresponding type arguments targs, recursively. subst doesn't modify the
    52  // incoming type. If a substitution took place, the result type is different
    53  // from the incoming type.
    54  //
    55  // If expanding is non-nil, it is the instance type currently being expanded.
    56  // One of expanding or ctxt must be non-nil.
    57  func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, expanding *Named, ctxt *Context) Type {
    58  	assert(expanding != nil || ctxt != nil)
    59  
    60  	if smap.empty() {
    61  		return typ
    62  	}
    63  
    64  	// common cases
    65  	switch t := typ.(type) {
    66  	case *Basic:
    67  		return typ	// nothing to do
    68  	case *TypeParam:
    69  		return smap.lookup(t)
    70  	}
    71  
    72  	// general case
    73  	subst := subster{
    74  		pos:		pos,
    75  		smap:		smap,
    76  		check:		check,
    77  		expanding:	expanding,
    78  		ctxt:		ctxt,
    79  	}
    80  	return subst.typ(typ)
    81  }
    82  
    83  type subster struct {
    84  	pos		token.Pos
    85  	smap		substMap
    86  	check		*Checker	// nil if called via Instantiate
    87  	expanding	*Named		// if non-nil, the instance that is being expanded
    88  	ctxt		*Context
    89  }
    90  
    91  func (subst *subster) typ(typ Type) Type {
    92  	switch t := typ.(type) {
    93  	case nil:
    94  		// Call typOrNil if it's possible that typ is nil.
    95  		panic("nil typ")
    96  
    97  	case *Basic:
    98  		// nothing to do
    99  
   100  	case *Array:
   101  		elem := subst.typOrNil(t.elem)
   102  		if elem != t.elem {
   103  			return &Array{len: t.len, elem: elem}
   104  		}
   105  
   106  	case *Slice:
   107  		elem := subst.typOrNil(t.elem)
   108  		if elem != t.elem {
   109  			return &Slice{elem: elem}
   110  		}
   111  
   112  	case *Struct:
   113  		if fields, copied := subst.varList(t.fields); copied {
   114  			s := &Struct{fields: fields, tags: t.tags}
   115  			s.markComplete()
   116  			return s
   117  		}
   118  
   119  	case *Pointer:
   120  		base := subst.typ(t.base)
   121  		if base != t.base {
   122  			return &Pointer{base: base}
   123  		}
   124  
   125  	case *Tuple:
   126  		return subst.tuple(t)
   127  
   128  	case *Signature:
   129  		// Preserve the receiver: it is handled during *Interface and *Named type
   130  		// substitution.
   131  		//
   132  		// Naively doing the substitution here can lead to an infinite recursion in
   133  		// the case where the receiver is an interface. For example, consider the
   134  		// following declaration:
   135  		//
   136  		//  type T[A any] struct { f interface{ m() } }
   137  		//
   138  		// In this case, the type of f is an interface that is itself the receiver
   139  		// type of all of its methods. Because we have no type name to break
   140  		// cycles, substituting in the recv results in an infinite loop of
   141  		// recv->interface->recv->interface->...
   142  		recv := t.recv
   143  
   144  		params := subst.tuple(t.params)
   145  		results := subst.tuple(t.results)
   146  		if params != t.params || results != t.results {
   147  			return &Signature{
   148  				rparams:	t.rparams,
   149  				// TODO(gri) why can't we nil out tparams here, rather than in instantiate?
   150  				tparams:	t.tparams,
   151  				// instantiated signatures have a nil scope
   152  				recv:		recv,
   153  				params:		params,
   154  				results:	results,
   155  				variadic:	t.variadic,
   156  			}
   157  		}
   158  
   159  	case *Union:
   160  		terms, copied := subst.termlist(t.terms)
   161  		if copied {
   162  			// term list substitution may introduce duplicate terms (unlikely but possible).
   163  			// This is ok; lazy type set computation will determine the actual type set
   164  			// in normal form.
   165  			return &Union{terms}
   166  		}
   167  
   168  	case *Interface:
   169  		methods, mcopied := subst.funcList(t.methods)
   170  		embeddeds, ecopied := subst.typeList(t.embeddeds)
   171  		if mcopied || ecopied {
   172  			iface := subst.check.newInterface()
   173  			iface.embeddeds = embeddeds
   174  			iface.embedPos = t.embedPos
   175  			iface.implicit = t.implicit
   176  			assert(t.complete)	// otherwise we are copying incomplete data
   177  			iface.complete = t.complete
   178  			// If we've changed the interface type, we may need to replace its
   179  			// receiver if the receiver type is the original interface. Receivers of
   180  			// *Named type are replaced during named type expansion.
   181  			//
   182  			// Notably, it's possible to reach here and not create a new *Interface,
   183  			// even though the receiver type may be parameterized. For example:
   184  			//
   185  			//  type T[P any] interface{ m() }
   186  			//
   187  			// In this case the interface will not be substituted here, because its
   188  			// method signatures do not depend on the type parameter P, but we still
   189  			// need to create new interface methods to hold the instantiated
   190  			// receiver. This is handled by Named.expandUnderlying.
   191  			iface.methods, _ = replaceRecvType(methods, t, iface)
   192  
   193  			// If check != nil, check.newInterface will have saved the interface for later completion.
   194  			if subst.check == nil {	// golang/go#61561: all newly created interfaces must be completed
   195  				iface.typeSet()
   196  			}
   197  			return iface
   198  		}
   199  
   200  	case *Map:
   201  		key := subst.typ(t.key)
   202  		elem := subst.typ(t.elem)
   203  		if key != t.key || elem != t.elem {
   204  			return &Map{key: key, elem: elem}
   205  		}
   206  
   207  	case *Chan:
   208  		elem := subst.typ(t.elem)
   209  		if elem != t.elem {
   210  			return &Chan{dir: t.dir, elem: elem}
   211  		}
   212  
   213  	case *Named:
   214  		// dump is for debugging
   215  		dump := func(string, ...interface{}) {}
   216  		if subst.check != nil && subst.check.conf._Trace {
   217  			subst.check.indent++
   218  			defer func() {
   219  				subst.check.indent--
   220  			}()
   221  			dump = func(format string, args ...interface{}) {
   222  				subst.check.trace(subst.pos, format, args...)
   223  			}
   224  		}
   225  
   226  		// subst is called during expansion, so in this function we need to be
   227  		// careful not to call any methods that would cause t to be expanded: doing
   228  		// so would result in deadlock.
   229  		//
   230  		// So we call t.Origin().TypeParams() rather than t.TypeParams().
   231  		orig := t.Origin()
   232  		n := orig.TypeParams().Len()
   233  		if n == 0 {
   234  			dump(">>> %s is not parameterized", t)
   235  			return t	// type is not parameterized
   236  		}
   237  
   238  		var newTArgs []Type
   239  		if t.TypeArgs().Len() != n {
   240  			return Typ[Invalid]	// error reported elsewhere
   241  		}
   242  
   243  		// already instantiated
   244  		dump(">>> %s already instantiated", t)
   245  		// For each (existing) type argument targ, determine if it needs
   246  		// to be substituted; i.e., if it is or contains a type parameter
   247  		// that has a type argument for it.
   248  		for i, targ := range t.TypeArgs().list() {
   249  			dump(">>> %d targ = %s", i, targ)
   250  			new_targ := subst.typ(targ)
   251  			if new_targ != targ {
   252  				dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
   253  				if newTArgs == nil {
   254  					newTArgs = make([]Type, n)
   255  					copy(newTArgs, t.TypeArgs().list())
   256  				}
   257  				newTArgs[i] = new_targ
   258  			}
   259  		}
   260  
   261  		if newTArgs == nil {
   262  			dump(">>> nothing to substitute in %s", t)
   263  			return t	// nothing to substitute
   264  		}
   265  
   266  		// Create a new instance and populate the context to avoid endless
   267  		// recursion. The position used here is irrelevant because validation only
   268  		// occurs on t (we don't call validType on named), but we use subst.pos to
   269  		// help with debugging.
   270  		return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt)
   271  
   272  	case *TypeParam:
   273  		return subst.smap.lookup(t)
   274  
   275  	default:
   276  		unreachable()
   277  	}
   278  
   279  	return typ
   280  }
   281  
   282  // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
   283  // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
   284  // where an array/slice element is accessed before it is set up.
   285  func (subst *subster) typOrNil(typ Type) Type {
   286  	if typ == nil {
   287  		return Typ[Invalid]
   288  	}
   289  	return subst.typ(typ)
   290  }
   291  
   292  func (subst *subster) var_(v *Var) *Var {
   293  	if v != nil {
   294  		if typ := subst.typ(v.typ); typ != v.typ {
   295  			return substVar(v, typ)
   296  		}
   297  	}
   298  	return v
   299  }
   300  
   301  func substVar(v *Var, typ Type) *Var {
   302  	copy := *v
   303  	copy.typ = typ
   304  	copy.origin = v.Origin()
   305  	return &copy
   306  }
   307  
   308  func (subst *subster) tuple(t *Tuple) *Tuple {
   309  	if t != nil {
   310  		if vars, copied := subst.varList(t.vars); copied {
   311  			return &Tuple{vars: vars}
   312  		}
   313  	}
   314  	return t
   315  }
   316  
   317  func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
   318  	out = in
   319  	for i, v := range in {
   320  		if w := subst.var_(v); w != v {
   321  			if !copied {
   322  				// first variable that got substituted => allocate new out slice
   323  				// and copy all variables
   324  				new := make([]*Var, len(in))
   325  				copy(new, out)
   326  				out = new
   327  				copied = true
   328  			}
   329  			out[i] = w
   330  		}
   331  	}
   332  	return
   333  }
   334  
   335  func (subst *subster) func_(f *Func) *Func {
   336  	if f != nil {
   337  		if typ := subst.typ(f.typ); typ != f.typ {
   338  			return substFunc(f, typ)
   339  		}
   340  	}
   341  	return f
   342  }
   343  
   344  func substFunc(f *Func, typ Type) *Func {
   345  	copy := *f
   346  	copy.typ = typ
   347  	copy.origin = f.Origin()
   348  	return &copy
   349  }
   350  
   351  func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
   352  	out = in
   353  	for i, f := range in {
   354  		if g := subst.func_(f); g != f {
   355  			if !copied {
   356  				// first function that got substituted => allocate new out slice
   357  				// and copy all functions
   358  				new := make([]*Func, len(in))
   359  				copy(new, out)
   360  				out = new
   361  				copied = true
   362  			}
   363  			out[i] = g
   364  		}
   365  	}
   366  	return
   367  }
   368  
   369  func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
   370  	out = in
   371  	for i, t := range in {
   372  		if u := subst.typ(t); u != t {
   373  			if !copied {
   374  				// first function that got substituted => allocate new out slice
   375  				// and copy all functions
   376  				new := make([]Type, len(in))
   377  				copy(new, out)
   378  				out = new
   379  				copied = true
   380  			}
   381  			out[i] = u
   382  		}
   383  	}
   384  	return
   385  }
   386  
   387  func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
   388  	out = in
   389  	for i, t := range in {
   390  		if u := subst.typ(t.typ); u != t.typ {
   391  			if !copied {
   392  				// first function that got substituted => allocate new out slice
   393  				// and copy all functions
   394  				new := make([]*Term, len(in))
   395  				copy(new, out)
   396  				out = new
   397  				copied = true
   398  			}
   399  			out[i] = NewTerm(t.tilde, u)
   400  		}
   401  	}
   402  	return
   403  }
   404  
   405  // replaceRecvType updates any function receivers that have type old to have
   406  // type new. It does not modify the input slice; if modifications are required,
   407  // the input slice and any affected signatures will be copied before mutating.
   408  //
   409  // The resulting out slice contains the updated functions, and copied reports
   410  // if anything was modified.
   411  func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
   412  	out = in
   413  	for i, method := range in {
   414  		sig := method.Type().(*Signature)
   415  		if sig.recv != nil && sig.recv.Type() == old {
   416  			if !copied {
   417  				// Allocate a new methods slice before mutating for the first time.
   418  				// This is defensive, as we may share methods across instantiations of
   419  				// a given interface type if they do not get substituted.
   420  				out = make([]*Func, len(in))
   421  				copy(out, in)
   422  				copied = true
   423  			}
   424  			newsig := *sig
   425  			newsig.recv = substVar(sig.recv, new)
   426  			out[i] = substFunc(method, &newsig)
   427  		}
   428  	}
   429  	return
   430  }