Source file src/cmd/compile/internal/types2/named.go

     1  // Copyright 2011 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 types2
     6  
     7  import (
     8  	"cmd/compile/internal/syntax"
     9  	"sync"
    10  )
    11  
    12  // A Named represents a named (defined) type.
    13  type Named struct {
    14  	check      *Checker
    15  	obj        *TypeName      // corresponding declared object for declared types; placeholder for instantiated types
    16  	orig       *Named         // original, uninstantiated type
    17  	fromRHS    Type           // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
    18  	underlying Type           // possibly a *Named during setup; never a *Named once set up completely
    19  	tparams    *TypeParamList // type parameters, or nil
    20  	targs      *TypeList      // type arguments (after instantiation), or nil
    21  
    22  	// methods declared for this type (not the method set of this type).
    23  	// Signatures are type-checked lazily.
    24  	// For non-instantiated types, this is a fully populated list of methods. For
    25  	// instantiated types, this is a 'lazy' list, and methods are instantiated
    26  	// when they are first accessed.
    27  	methods *methodList
    28  
    29  	// resolver may be provided to lazily resolve type parameters, underlying, and methods.
    30  	resolver func(*Context, *Named) (tparams *TypeParamList, underlying Type, methods *methodList)
    31  	once     sync.Once // ensures that tparams, underlying, and methods are resolved before accessing
    32  }
    33  
    34  // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
    35  // If the given type name obj doesn't have a type yet, its type is set to the returned named type.
    36  // The underlying type must not be a *Named.
    37  func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
    38  	if _, ok := underlying.(*Named); ok {
    39  		panic("underlying type must not be *Named")
    40  	}
    41  	return (*Checker)(nil).newNamed(obj, nil, underlying, nil, newMethodList(methods))
    42  }
    43  
    44  func (t *Named) resolve(ctxt *Context) *Named {
    45  	if t.resolver == nil {
    46  		return t
    47  	}
    48  
    49  	t.once.Do(func() {
    50  		// TODO(mdempsky): Since we're passing t to the resolver anyway
    51  		// (necessary because types2 expects the receiver type for methods
    52  		// on defined interface types to be the Named rather than the
    53  		// underlying Interface), maybe it should just handle calling
    54  		// SetTypeParams, SetUnderlying, and AddMethod instead?  Those
    55  		// methods would need to support reentrant calls though. It would
    56  		// also make the API more future-proof towards further extensions
    57  		// (like SetTypeParams).
    58  		t.tparams, t.underlying, t.methods = t.resolver(ctxt, t)
    59  		t.fromRHS = t.underlying // for cycle detection
    60  	})
    61  	return t
    62  }
    63  
    64  // newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
    65  func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParamList, methods *methodList) *Named {
    66  	typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
    67  	if typ.orig == nil {
    68  		typ.orig = typ
    69  	}
    70  	if obj.typ == nil {
    71  		obj.typ = typ
    72  	}
    73  	// Ensure that typ is always expanded and sanity-checked.
    74  	if check != nil {
    75  		check.needsCleanup(typ)
    76  	}
    77  	return typ
    78  }
    79  
    80  func (t *Named) cleanup() {
    81  	// Ensure that every defined type created in the course of type-checking has
    82  	// either non-*Named underlying, or is unresolved.
    83  	//
    84  	// This guarantees that we don't leak any types whose underlying is *Named,
    85  	// because any unresolved instances will lazily compute their underlying by
    86  	// substituting in the underlying of their origin. The origin must have
    87  	// either been imported or type-checked and expanded here, and in either case
    88  	// its underlying will be fully expanded.
    89  	switch t.underlying.(type) {
    90  	case nil:
    91  		if t.resolver == nil {
    92  			panic("nil underlying")
    93  		}
    94  	case *Named:
    95  		t.under() // t.under may add entries to check.cleaners
    96  	}
    97  	t.check = nil
    98  }
    99  
   100  // Obj returns the type name for the declaration defining the named type t. For
   101  // instantiated types, this is same as the type name of the origin type.
   102  func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
   103  
   104  // Origin returns the generic type from which the named type t is
   105  // instantiated. If t is not an instantiated type, the result is t.
   106  func (t *Named) Origin() *Named { return t.orig }
   107  
   108  // TODO(gri) Come up with a better representation and API to distinguish
   109  //           between parameterized instantiated and non-instantiated types.
   110  
   111  // TypeParams returns the type parameters of the named type t, or nil.
   112  // The result is non-nil for an (originally) generic type even if it is instantiated.
   113  func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
   114  
   115  // SetTypeParams sets the type parameters of the named type t.
   116  // t must not have type arguments.
   117  func (t *Named) SetTypeParams(tparams []*TypeParam) {
   118  	assert(t.targs.Len() == 0)
   119  	t.resolve(nil).tparams = bindTParams(tparams)
   120  }
   121  
   122  // TypeArgs returns the type arguments used to instantiate the named type t.
   123  func (t *Named) TypeArgs() *TypeList { return t.targs }
   124  
   125  // NumMethods returns the number of explicit methods defined for t.
   126  //
   127  // For an ordinary or instantiated type t, the receiver base type of these
   128  // methods will be the named type t. For an uninstantiated generic type t, each
   129  // method receiver will be instantiated with its receiver type parameters.
   130  func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() }
   131  
   132  // Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
   133  func (t *Named) Method(i int) *Func {
   134  	t.resolve(nil)
   135  	return t.methods.At(i, func() *Func {
   136  		return t.instantiateMethod(i)
   137  	})
   138  }
   139  
   140  // instiateMethod instantiates the i'th method for an instantiated receiver.
   141  func (t *Named) instantiateMethod(i int) *Func {
   142  	assert(t.TypeArgs().Len() > 0) // t must be an instance
   143  
   144  	// t.orig.methods is not lazy. origm is the method instantiated with its
   145  	// receiver type parameters (the "origin" method).
   146  	origm := t.orig.Method(i)
   147  	assert(origm != nil)
   148  
   149  	check := t.check
   150  	// Ensure that the original method is type-checked.
   151  	if check != nil {
   152  		check.objDecl(origm, nil)
   153  	}
   154  
   155  	origSig := origm.typ.(*Signature)
   156  	rbase, _ := deref(origSig.Recv().Type())
   157  
   158  	// If rbase is t, then origm is already the instantiated method we're looking
   159  	// for. In this case, we return origm to preserve the invariant that
   160  	// traversing Method->Receiver Type->Method should get back to the same
   161  	// method.
   162  	//
   163  	// This occurs if t is instantiated with the receiver type parameters, as in
   164  	// the use of m in func (r T[_]) m() { r.m() }.
   165  	if rbase == t {
   166  		return origm
   167  	}
   168  
   169  	sig := origSig
   170  	// We can only substitute if we have a correspondence between type arguments
   171  	// and type parameters. This check is necessary in the presence of invalid
   172  	// code.
   173  	if origSig.RecvTypeParams().Len() == t.targs.Len() {
   174  		ctxt := check.bestContext(nil)
   175  		smap := makeSubstMap(origSig.RecvTypeParams().list(), t.targs.list())
   176  		sig = check.subst(origm.pos, origSig, smap, ctxt).(*Signature)
   177  	}
   178  
   179  	if sig == origSig {
   180  		// No substitution occurred, but we still need to create a new signature to
   181  		// hold the instantiated receiver.
   182  		copy := *origSig
   183  		sig = &copy
   184  	}
   185  
   186  	var rtyp Type
   187  	if origm.hasPtrRecv() {
   188  		rtyp = NewPointer(t)
   189  	} else {
   190  		rtyp = t
   191  	}
   192  
   193  	sig.recv = substVar(origSig.recv, rtyp)
   194  	return NewFunc(origm.pos, origm.pkg, origm.name, sig)
   195  }
   196  
   197  // SetUnderlying sets the underlying type and marks t as complete.
   198  // t must not have type arguments.
   199  func (t *Named) SetUnderlying(underlying Type) {
   200  	assert(t.targs.Len() == 0)
   201  	if underlying == nil {
   202  		panic("underlying type must not be nil")
   203  	}
   204  	if _, ok := underlying.(*Named); ok {
   205  		panic("underlying type must not be *Named")
   206  	}
   207  	t.resolve(nil).underlying = underlying
   208  	if t.fromRHS == nil {
   209  		t.fromRHS = underlying // for cycle detection
   210  	}
   211  }
   212  
   213  // AddMethod adds method m unless it is already in the method list.
   214  // t must not have type arguments.
   215  func (t *Named) AddMethod(m *Func) {
   216  	assert(t.targs.Len() == 0)
   217  	t.resolve(nil)
   218  	if t.methods == nil {
   219  		t.methods = newMethodList(nil)
   220  	}
   221  	t.methods.Add(m)
   222  }
   223  
   224  func (t *Named) Underlying() Type { return t.resolve(nil).underlying }
   225  func (t *Named) String() string   { return TypeString(t, nil) }
   226  
   227  // ----------------------------------------------------------------------------
   228  // Implementation
   229  
   230  // under returns the expanded underlying type of n0; possibly by following
   231  // forward chains of named types. If an underlying type is found, resolve
   232  // the chain by setting the underlying type for each defined type in the
   233  // chain before returning it. If no underlying type is found or a cycle
   234  // is detected, the result is Typ[Invalid]. If a cycle is detected and
   235  // n0.check != nil, the cycle is reported.
   236  //
   237  // This is necessary because the underlying type of named may be itself a
   238  // named type that is incomplete:
   239  //
   240  //	type (
   241  //		A B
   242  //		B *C
   243  //		C A
   244  //	)
   245  //
   246  // The type of C is the (named) type of A which is incomplete,
   247  // and which has as its underlying type the named type B.
   248  func (n0 *Named) under() Type {
   249  	u := n0.Underlying()
   250  
   251  	// If the underlying type of a defined type is not a defined
   252  	// (incl. instance) type, then that is the desired underlying
   253  	// type.
   254  	var n1 *Named
   255  	switch u1 := u.(type) {
   256  	case nil:
   257  		// After expansion via Underlying(), we should never encounter a nil
   258  		// underlying.
   259  		panic("nil underlying")
   260  	default:
   261  		// common case
   262  		return u
   263  	case *Named:
   264  		// handled below
   265  		n1 = u1
   266  	}
   267  
   268  	if n0.check == nil {
   269  		panic("Named.check == nil but type is incomplete")
   270  	}
   271  
   272  	// Invariant: after this point n0 as well as any named types in its
   273  	// underlying chain should be set up when this function exits.
   274  	check := n0.check
   275  	n := n0
   276  
   277  	seen := make(map[*Named]int) // types that need their underlying resolved
   278  	var path []Object            // objects encountered, for cycle reporting
   279  
   280  loop:
   281  	for {
   282  		seen[n] = len(seen)
   283  		path = append(path, n.obj)
   284  		n = n1
   285  		if i, ok := seen[n]; ok {
   286  			// cycle
   287  			check.cycleError(path[i:])
   288  			u = Typ[Invalid]
   289  			break
   290  		}
   291  		u = n.Underlying()
   292  		switch u1 := u.(type) {
   293  		case nil:
   294  			u = Typ[Invalid]
   295  			break loop
   296  		default:
   297  			break loop
   298  		case *Named:
   299  			// Continue collecting *Named types in the chain.
   300  			n1 = u1
   301  		}
   302  	}
   303  
   304  	for n := range seen {
   305  		// We should never have to update the underlying type of an imported type;
   306  		// those underlying types should have been resolved during the import.
   307  		// Also, doing so would lead to a race condition (was issue #31749).
   308  		// Do this check always, not just in debug mode (it's cheap).
   309  		if n.obj.pkg != check.pkg {
   310  			panic("imported type with unresolved underlying type")
   311  		}
   312  		n.underlying = u
   313  	}
   314  
   315  	return u
   316  }
   317  
   318  func (n *Named) setUnderlying(typ Type) {
   319  	if n != nil {
   320  		n.underlying = typ
   321  	}
   322  }
   323  
   324  func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) {
   325  	n.resolve(nil)
   326  	// If n is an instance, we may not have yet instantiated all of its methods.
   327  	// Look up the method index in orig, and only instantiate method at the
   328  	// matching index (if any).
   329  	i, _ := n.orig.methods.Lookup(pkg, name, foldCase)
   330  	if i < 0 {
   331  		return -1, nil
   332  	}
   333  	// For instances, m.Method(i) will be different from the orig method.
   334  	return i, n.Method(i)
   335  }
   336  
   337  // bestContext returns the best available context. In order of preference:
   338  // - the given ctxt, if non-nil
   339  // - check.ctxt, if check is non-nil
   340  // - a new Context
   341  func (check *Checker) bestContext(ctxt *Context) *Context {
   342  	if ctxt != nil {
   343  		return ctxt
   344  	}
   345  	if check != nil {
   346  		if check.ctxt == nil {
   347  			check.ctxt = NewContext()
   348  		}
   349  		return check.ctxt
   350  	}
   351  	return NewContext()
   352  }
   353  
   354  // expandNamed ensures that the underlying type of n is instantiated.
   355  // The underlying type will be Typ[Invalid] if there was an error.
   356  func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypeParamList, underlying Type, methods *methodList) {
   357  	n.orig.resolve(ctxt)
   358  	assert(n.orig.underlying != nil)
   359  
   360  	check := n.check
   361  
   362  	if _, unexpanded := n.orig.underlying.(*Named); unexpanded {
   363  		// We should only get an unexpanded underlying here during type checking
   364  		// (for example, in recursive type declarations).
   365  		assert(check != nil)
   366  	}
   367  
   368  	// Mismatching arg and tparam length may be checked elsewhere.
   369  	if n.orig.tparams.Len() == n.targs.Len() {
   370  		// We must always have a context, to avoid infinite recursion.
   371  		ctxt = check.bestContext(ctxt)
   372  		h := ctxt.instanceHash(n.orig, n.targs.list())
   373  		// ensure that an instance is recorded for h to avoid infinite recursion.
   374  		ctxt.update(h, n.orig, n.TypeArgs().list(), n)
   375  
   376  		smap := makeSubstMap(n.orig.tparams.list(), n.targs.list())
   377  		underlying = n.check.subst(instPos, n.orig.underlying, smap, ctxt)
   378  		// If the underlying of n is an interface, we need to set the receiver of
   379  		// its methods accurately -- we set the receiver of interface methods on
   380  		// the RHS of a type declaration to the defined type.
   381  		if iface, _ := underlying.(*Interface); iface != nil {
   382  			if methods, copied := replaceRecvType(iface.methods, n.orig, n); copied {
   383  				// If the underlying doesn't actually use type parameters, it's possible
   384  				// that it wasn't substituted. In this case we need to create a new
   385  				// *Interface before modifying receivers.
   386  				if iface == n.orig.underlying {
   387  					old := iface
   388  					iface = check.newInterface()
   389  					iface.embeddeds = old.embeddeds
   390  					iface.complete = old.complete
   391  					iface.implicit = old.implicit // should be false but be conservative
   392  					underlying = iface
   393  				}
   394  				iface.methods = methods
   395  			}
   396  		}
   397  	} else {
   398  		underlying = Typ[Invalid]
   399  	}
   400  
   401  	return n.orig.tparams, underlying, newLazyMethodList(n.orig.methods.Len())
   402  }
   403  
   404  // safeUnderlying returns the underlying of typ without expanding instances, to
   405  // avoid infinite recursion.
   406  //
   407  // TODO(rfindley): eliminate this function or give it a better name.
   408  func safeUnderlying(typ Type) Type {
   409  	if t, _ := typ.(*Named); t != nil {
   410  		return t.underlying
   411  	}
   412  	return typ.Underlying()
   413  }
   414  

View as plain text