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

     1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
     2  
     3  // Copyright 2021 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 instantiation of generic types
     8  // through substitution of type parameters by type arguments.
     9  
    10  package types
    11  
    12  import (
    13  	"errors"
    14  	"fmt"
    15  	"github.com/bir3/gocompiler/src/go/token"
    16  	. "github.com/bir3/gocompiler/src/internal/types/errors"
    17  )
    18  
    19  // Instantiate instantiates the type orig with the given type arguments targs.
    20  // orig must be a *Named or a *Signature type. If there is no error, the
    21  // resulting Type is an instantiated type of the same kind (either a *Named or
    22  // a *Signature). Methods attached to a *Named type are also instantiated, and
    23  // associated with a new *Func that has the same position as the original
    24  // method, but nil function scope.
    25  //
    26  // If ctxt is non-nil, it may be used to de-duplicate the instance against
    27  // previous instances with the same identity. As a special case, generic
    28  // *Signature origin types are only considered identical if they are pointer
    29  // equivalent, so that instantiating distinct (but possibly identical)
    30  // signatures will yield different instances. The use of a shared context does
    31  // not guarantee that identical instances are deduplicated in all cases.
    32  //
    33  // If validate is set, Instantiate verifies that the number of type arguments
    34  // and parameters match, and that the type arguments satisfy their
    35  // corresponding type constraints. If verification fails, the resulting error
    36  // may wrap an *ArgumentError indicating which type argument did not satisfy
    37  // its corresponding type parameter constraint, and why.
    38  //
    39  // If validate is not set, Instantiate does not verify the type argument count
    40  // or whether the type arguments satisfy their constraints. Instantiate is
    41  // guaranteed to not return an error, but may panic. Specifically, for
    42  // *Signature types, Instantiate will panic immediately if the type argument
    43  // count is incorrect; for *Named types, a panic may occur later inside the
    44  // *Named API.
    45  func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) {
    46  	if ctxt == nil {
    47  		ctxt = NewContext()
    48  	}
    49  	if validate {
    50  		var tparams []*TypeParam
    51  		switch t := orig.(type) {
    52  		case *Named:
    53  			tparams = t.TypeParams().list()
    54  		case *Signature:
    55  			tparams = t.TypeParams().list()
    56  		}
    57  		if len(targs) != len(tparams) {
    58  			return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams))
    59  		}
    60  		if i, err := (*Checker)(nil).verify(nopos, tparams, targs, ctxt); err != nil {
    61  			return nil, &ArgumentError{i, err}
    62  		}
    63  	}
    64  
    65  	inst := (*Checker)(nil).instance(nopos, orig, targs, nil, ctxt)
    66  	return inst, nil
    67  }
    68  
    69  // instance instantiates the given original (generic) function or type with the
    70  // provided type arguments and returns the resulting instance. If an identical
    71  // instance exists already in the given contexts, it returns that instance,
    72  // otherwise it creates a new one.
    73  //
    74  // If expanding is non-nil, it is the Named instance type currently being
    75  // expanded. If ctxt is non-nil, it is the context associated with the current
    76  // type-checking pass or call to Instantiate. At least one of expanding or ctxt
    77  // must be non-nil.
    78  //
    79  // For Named types the resulting instance may be unexpanded.
    80  func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding *Named, ctxt *Context) (res Type) {
    81  	// The order of the contexts below matters: we always prefer instances in the
    82  	// expanding instance context in order to preserve reference cycles.
    83  	//
    84  	// Invariant: if expanding != nil, the returned instance will be the instance
    85  	// recorded in expanding.inst.ctxt.
    86  	var ctxts []*Context
    87  	if expanding != nil {
    88  		ctxts = append(ctxts, expanding.inst.ctxt)
    89  	}
    90  	if ctxt != nil {
    91  		ctxts = append(ctxts, ctxt)
    92  	}
    93  	assert(len(ctxts) > 0)
    94  
    95  	// Compute all hashes; hashes may differ across contexts due to different
    96  	// unique IDs for Named types within the hasher.
    97  	hashes := make([]string, len(ctxts))
    98  	for i, ctxt := range ctxts {
    99  		hashes[i] = ctxt.instanceHash(orig, targs)
   100  	}
   101  
   102  	// If local is non-nil, updateContexts return the type recorded in
   103  	// local.
   104  	updateContexts := func(res Type) Type {
   105  		for i := len(ctxts) - 1; i >= 0; i-- {
   106  			res = ctxts[i].update(hashes[i], orig, targs, res)
   107  		}
   108  		return res
   109  	}
   110  
   111  	// typ may already have been instantiated with identical type arguments. In
   112  	// that case, re-use the existing instance.
   113  	for i, ctxt := range ctxts {
   114  		if inst := ctxt.lookup(hashes[i], orig, targs); inst != nil {
   115  			return updateContexts(inst)
   116  		}
   117  	}
   118  
   119  	switch orig := orig.(type) {
   120  	case *Named:
   121  		res = check.newNamedInstance(pos, orig, targs, expanding)	// substituted lazily
   122  
   123  	case *Signature:
   124  		assert(expanding == nil)	// function instances cannot be reached from Named types
   125  
   126  		tparams := orig.TypeParams()
   127  		// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
   128  		if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
   129  			return Typ[Invalid]
   130  		}
   131  		if tparams.Len() == 0 {
   132  			return orig	// nothing to do (minor optimization)
   133  		}
   134  		sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), nil, ctxt).(*Signature)
   135  		// If the signature doesn't use its type parameters, subst
   136  		// will not make a copy. In that case, make a copy now (so
   137  		// we can set tparams to nil w/o causing side-effects).
   138  		if sig == orig {
   139  			copy := *sig
   140  			sig = &copy
   141  		}
   142  		// After instantiating a generic signature, it is not generic
   143  		// anymore; we need to set tparams to nil.
   144  		sig.tparams = nil
   145  		res = sig
   146  
   147  	default:
   148  		// only types and functions can be generic
   149  		panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
   150  	}
   151  
   152  	// Update all contexts; it's possible that we've lost a race.
   153  	return updateContexts(res)
   154  }
   155  
   156  // validateTArgLen checks that the number of type arguments (got) matches the
   157  // number of type parameters (want); if they don't match an error is reported.
   158  // If validation fails and check is nil, validateTArgLen panics.
   159  func (check *Checker) validateTArgLen(pos token.Pos, name string, want, got int) bool {
   160  	var qual string
   161  	switch {
   162  	case got < want:
   163  		qual = "not enough"
   164  	case got > want:
   165  		qual = "too many"
   166  	default:
   167  		return true
   168  	}
   169  
   170  	msg := check.sprintf("%s type arguments for type %s: have %d, want %d", qual, name, got, want)
   171  	if check != nil {
   172  		check.error(atPos(pos), WrongTypeArgCount, msg)
   173  		return false
   174  	}
   175  
   176  	panic(fmt.Sprintf("%v: %s", pos, msg))
   177  }
   178  
   179  func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) {
   180  	smap := makeSubstMap(tparams, targs)
   181  	for i, tpar := range tparams {
   182  		// Ensure that we have a (possibly implicit) interface as type bound (go.dev/issue/51048).
   183  		tpar.iface()
   184  		// The type parameter bound is parameterized with the same type parameters
   185  		// as the instantiated type; before we can use it for bounds checking we
   186  		// need to instantiate it with the type arguments with which we instantiated
   187  		// the parameterized type.
   188  		bound := check.subst(pos, tpar.bound, smap, nil, ctxt)
   189  		var cause string
   190  		if !check.implements(pos, targs[i], bound, true, &cause) {
   191  			return i, errors.New(cause)
   192  		}
   193  	}
   194  	return -1, nil
   195  }
   196  
   197  // implements checks if V implements T. The receiver may be nil if implements
   198  // is called through an exported API call such as AssignableTo. If constraint
   199  // is set, T is a type constraint.
   200  //
   201  // If the provided cause is non-nil, it may be set to an error string
   202  // explaining why V does not implement (or satisfy, for constraints) T.
   203  func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, cause *string) bool {
   204  	Vu := under(V)
   205  	Tu := under(T)
   206  	if !isValid(Vu) || !isValid(Tu) {
   207  		return true	// avoid follow-on errors
   208  	}
   209  	if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
   210  		return true	// avoid follow-on errors (see go.dev/issue/49541 for an example)
   211  	}
   212  
   213  	verb := "implement"
   214  	if constraint {
   215  		verb = "satisfy"
   216  	}
   217  
   218  	Ti, _ := Tu.(*Interface)
   219  	if Ti == nil {
   220  		if cause != nil {
   221  			var detail string
   222  			if isInterfacePtr(Tu) {
   223  				detail = check.sprintf("type %s is pointer to interface, not interface", T)
   224  			} else {
   225  				detail = check.sprintf("%s is not an interface", T)
   226  			}
   227  			*cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
   228  		}
   229  		return false
   230  	}
   231  
   232  	// Every type satisfies the empty interface.
   233  	if Ti.Empty() {
   234  		return true
   235  	}
   236  	// T is not the empty interface (i.e., the type set of T is restricted)
   237  
   238  	// An interface V with an empty type set satisfies any interface.
   239  	// (The empty set is a subset of any set.)
   240  	Vi, _ := Vu.(*Interface)
   241  	if Vi != nil && Vi.typeSet().IsEmpty() {
   242  		return true
   243  	}
   244  	// type set of V is not empty
   245  
   246  	// No type with non-empty type set satisfies the empty type set.
   247  	if Ti.typeSet().IsEmpty() {
   248  		if cause != nil {
   249  			*cause = check.sprintf("cannot %s %s (empty type set)", verb, T)
   250  		}
   251  		return false
   252  	}
   253  
   254  	// V must implement T's methods, if any.
   255  	if m, _ := check.missingMethod(V, T, true, Identical, cause); m != nil /* !Implements(V, T) */ {
   256  		if cause != nil {
   257  			*cause = check.sprintf("%s does not %s %s %s", V, verb, T, *cause)
   258  		}
   259  		return false
   260  	}
   261  
   262  	// Only check comparability if we don't have a more specific error.
   263  	checkComparability := func() bool {
   264  		if !Ti.IsComparable() {
   265  			return true
   266  		}
   267  		// If T is comparable, V must be comparable.
   268  		// If V is strictly comparable, we're done.
   269  		if comparable(V, false /* strict comparability */, nil, nil) {
   270  			return true
   271  		}
   272  		// For constraint satisfaction, use dynamic (spec) comparability
   273  		// so that ordinary, non-type parameter interfaces implement comparable.
   274  		if constraint && comparable(V, true /* spec comparability */, nil, nil) {
   275  			// V is comparable if we are at Go 1.20 or higher.
   276  			if check == nil || check.allowVersion(check.pkg, atPos(pos), go1_20) {	// atPos needed so that go/types generate passes
   277  				return true
   278  			}
   279  			if cause != nil {
   280  				*cause = check.sprintf("%s to %s comparable requires go1.20 or later", V, verb)
   281  			}
   282  			return false
   283  		}
   284  		if cause != nil {
   285  			*cause = check.sprintf("%s does not %s comparable", V, verb)
   286  		}
   287  		return false
   288  	}
   289  
   290  	// V must also be in the set of types of T, if any.
   291  	// Constraints with empty type sets were already excluded above.
   292  	if !Ti.typeSet().hasTerms() {
   293  		return checkComparability()	// nothing to do
   294  	}
   295  
   296  	// If V is itself an interface, each of its possible types must be in the set
   297  	// of T types (i.e., the V type set must be a subset of the T type set).
   298  	// Interfaces V with empty type sets were already excluded above.
   299  	if Vi != nil {
   300  		if !Vi.typeSet().subsetOf(Ti.typeSet()) {
   301  			// TODO(gri) report which type is missing
   302  			if cause != nil {
   303  				*cause = check.sprintf("%s does not %s %s", V, verb, T)
   304  			}
   305  			return false
   306  		}
   307  		return checkComparability()
   308  	}
   309  
   310  	// Otherwise, V's type must be included in the iface type set.
   311  	var alt Type
   312  	if Ti.typeSet().is(func(t *term) bool {
   313  		if !t.includes(V) {
   314  			// If V ∉ t.typ but V ∈ ~t.typ then remember this type
   315  			// so we can suggest it as an alternative in the error
   316  			// message.
   317  			if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
   318  				tt := *t
   319  				tt.tilde = true
   320  				if tt.includes(V) {
   321  					alt = t.typ
   322  				}
   323  			}
   324  			return true
   325  		}
   326  		return false
   327  	}) {
   328  		if cause != nil {
   329  			var detail string
   330  			switch {
   331  			case alt != nil:
   332  				detail = check.sprintf("possibly missing ~ for %s in %s", alt, T)
   333  			case mentions(Ti, V):
   334  				detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T)
   335  			default:
   336  				detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms)
   337  			}
   338  			*cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
   339  		}
   340  		return false
   341  	}
   342  
   343  	return checkComparability()
   344  }
   345  
   346  // mentions reports whether type T "mentions" typ in an (embedded) element or term
   347  // of T (whether typ is in the type set of T or not). For better error messages.
   348  func mentions(T, typ Type) bool {
   349  	switch T := T.(type) {
   350  	case *Interface:
   351  		for _, e := range T.embeddeds {
   352  			if mentions(e, typ) {
   353  				return true
   354  			}
   355  		}
   356  	case *Union:
   357  		for _, t := range T.terms {
   358  			if mentions(t.typ, typ) {
   359  				return true
   360  			}
   361  		}
   362  	default:
   363  		if Identical(T, typ) {
   364  			return true
   365  		}
   366  	}
   367  	return false
   368  }