github.com/AndrienkoAleksandr/go@v0.0.19/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  	"go/token"
    16  	. "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  		if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
   128  			return Typ[Invalid]
   129  		}
   130  		if tparams.Len() == 0 {
   131  			return orig // nothing to do (minor optimization)
   132  		}
   133  		sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), nil, ctxt).(*Signature)
   134  		// If the signature doesn't use its type parameters, subst
   135  		// will not make a copy. In that case, make a copy now (so
   136  		// we can set tparams to nil w/o causing side-effects).
   137  		if sig == orig {
   138  			copy := *sig
   139  			sig = &copy
   140  		}
   141  		// After instantiating a generic signature, it is not generic
   142  		// anymore; we need to set tparams to nil.
   143  		sig.tparams = nil
   144  		res = sig
   145  
   146  	default:
   147  		// only types and functions can be generic
   148  		panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
   149  	}
   150  
   151  	// Update all contexts; it's possible that we've lost a race.
   152  	return updateContexts(res)
   153  }
   154  
   155  // validateTArgLen verifies that the length of targs and tparams matches,
   156  // reporting an error if not. If validation fails and check is nil,
   157  // validateTArgLen panics.
   158  func (check *Checker) validateTArgLen(pos token.Pos, ntparams, ntargs int) bool {
   159  	if ntargs != ntparams {
   160  		// TODO(gri) provide better error message
   161  		if check != nil {
   162  			check.errorf(atPos(pos), WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams)
   163  			return false
   164  		}
   165  		panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
   166  	}
   167  	return true
   168  }
   169  
   170  func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) {
   171  	smap := makeSubstMap(tparams, targs)
   172  	for i, tpar := range tparams {
   173  		// Ensure that we have a (possibly implicit) interface as type bound (go.dev/issue/51048).
   174  		tpar.iface()
   175  		// The type parameter bound is parameterized with the same type parameters
   176  		// as the instantiated type; before we can use it for bounds checking we
   177  		// need to instantiate it with the type arguments with which we instantiated
   178  		// the parameterized type.
   179  		bound := check.subst(pos, tpar.bound, smap, nil, ctxt)
   180  		var cause string
   181  		if !check.implements(pos, targs[i], bound, true, &cause) {
   182  			return i, errors.New(cause)
   183  		}
   184  	}
   185  	return -1, nil
   186  }
   187  
   188  // implements checks if V implements T. The receiver may be nil if implements
   189  // is called through an exported API call such as AssignableTo. If constraint
   190  // is set, T is a type constraint.
   191  //
   192  // If the provided cause is non-nil, it may be set to an error string
   193  // explaining why V does not implement (or satisfy, for constraints) T.
   194  func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, cause *string) bool {
   195  	Vu := under(V)
   196  	Tu := under(T)
   197  	if Vu == Typ[Invalid] || Tu == Typ[Invalid] {
   198  		return true // avoid follow-on errors
   199  	}
   200  	if p, _ := Vu.(*Pointer); p != nil && under(p.base) == Typ[Invalid] {
   201  		return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
   202  	}
   203  
   204  	verb := "implement"
   205  	if constraint {
   206  		verb = "satisfy"
   207  	}
   208  
   209  	Ti, _ := Tu.(*Interface)
   210  	if Ti == nil {
   211  		if cause != nil {
   212  			var detail string
   213  			if isInterfacePtr(Tu) {
   214  				detail = check.sprintf("type %s is pointer to interface, not interface", T)
   215  			} else {
   216  				detail = check.sprintf("%s is not an interface", T)
   217  			}
   218  			*cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
   219  		}
   220  		return false
   221  	}
   222  
   223  	// Every type satisfies the empty interface.
   224  	if Ti.Empty() {
   225  		return true
   226  	}
   227  	// T is not the empty interface (i.e., the type set of T is restricted)
   228  
   229  	// An interface V with an empty type set satisfies any interface.
   230  	// (The empty set is a subset of any set.)
   231  	Vi, _ := Vu.(*Interface)
   232  	if Vi != nil && Vi.typeSet().IsEmpty() {
   233  		return true
   234  	}
   235  	// type set of V is not empty
   236  
   237  	// No type with non-empty type set satisfies the empty type set.
   238  	if Ti.typeSet().IsEmpty() {
   239  		if cause != nil {
   240  			*cause = check.sprintf("cannot %s %s (empty type set)", verb, T)
   241  		}
   242  		return false
   243  	}
   244  
   245  	// V must implement T's methods, if any.
   246  	if m, _ := check.missingMethod(V, T, true, Identical, cause); m != nil /* !Implements(V, T) */ {
   247  		if cause != nil {
   248  			*cause = check.sprintf("%s does not %s %s %s", V, verb, T, *cause)
   249  		}
   250  		return false
   251  	}
   252  
   253  	// Only check comparability if we don't have a more specific error.
   254  	checkComparability := func() bool {
   255  		if !Ti.IsComparable() {
   256  			return true
   257  		}
   258  		// If T is comparable, V must be comparable.
   259  		// If V is strictly comparable, we're done.
   260  		if comparable(V, false /* strict comparability */, nil, nil) {
   261  			return true
   262  		}
   263  		// For constraint satisfaction, use dynamic (spec) comparability
   264  		// so that ordinary, non-type parameter interfaces implement comparable.
   265  		if constraint && comparable(V, true /* spec comparability */, nil, nil) {
   266  			// V is comparable if we are at Go 1.20 or higher.
   267  			if check == nil || check.allowVersion(check.pkg, atPos(pos), go1_20) { // atPos needed so that go/types generate passes
   268  				return true
   269  			}
   270  			if cause != nil {
   271  				*cause = check.sprintf("%s to %s comparable requires go1.20 or later", V, verb)
   272  			}
   273  			return false
   274  		}
   275  		if cause != nil {
   276  			*cause = check.sprintf("%s does not %s comparable", V, verb)
   277  		}
   278  		return false
   279  	}
   280  
   281  	// V must also be in the set of types of T, if any.
   282  	// Constraints with empty type sets were already excluded above.
   283  	if !Ti.typeSet().hasTerms() {
   284  		return checkComparability() // nothing to do
   285  	}
   286  
   287  	// If V is itself an interface, each of its possible types must be in the set
   288  	// of T types (i.e., the V type set must be a subset of the T type set).
   289  	// Interfaces V with empty type sets were already excluded above.
   290  	if Vi != nil {
   291  		if !Vi.typeSet().subsetOf(Ti.typeSet()) {
   292  			// TODO(gri) report which type is missing
   293  			if cause != nil {
   294  				*cause = check.sprintf("%s does not %s %s", V, verb, T)
   295  			}
   296  			return false
   297  		}
   298  		return checkComparability()
   299  	}
   300  
   301  	// Otherwise, V's type must be included in the iface type set.
   302  	var alt Type
   303  	if Ti.typeSet().is(func(t *term) bool {
   304  		if !t.includes(V) {
   305  			// If V ∉ t.typ but V ∈ ~t.typ then remember this type
   306  			// so we can suggest it as an alternative in the error
   307  			// message.
   308  			if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
   309  				tt := *t
   310  				tt.tilde = true
   311  				if tt.includes(V) {
   312  					alt = t.typ
   313  				}
   314  			}
   315  			return true
   316  		}
   317  		return false
   318  	}) {
   319  		if cause != nil {
   320  			var detail string
   321  			switch {
   322  			case alt != nil:
   323  				detail = check.sprintf("possibly missing ~ for %s in %s", alt, T)
   324  			case mentions(Ti, V):
   325  				detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T)
   326  			default:
   327  				detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms)
   328  			}
   329  			*cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
   330  		}
   331  		return false
   332  	}
   333  
   334  	return checkComparability()
   335  }
   336  
   337  // mentions reports whether type T "mentions" typ in an (embedded) element or term
   338  // of T (whether typ is in the type set of T or not). For better error messages.
   339  func mentions(T, typ Type) bool {
   340  	switch T := T.(type) {
   341  	case *Interface:
   342  		for _, e := range T.embeddeds {
   343  			if mentions(e, typ) {
   344  				return true
   345  			}
   346  		}
   347  	case *Union:
   348  		for _, t := range T.terms {
   349  			if mentions(t.typ, typ) {
   350  				return true
   351  			}
   352  		}
   353  	default:
   354  		if Identical(T, typ) {
   355  			return true
   356  		}
   357  	}
   358  	return false
   359  }