Source file src/go/types/instantiate.go

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

View as plain text