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

     1  // Copyright 2023 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  )
    10  
    11  // An Alias represents an alias type.
    12  //
    13  // Alias types are created by alias declarations such as:
    14  //
    15  //	type A = int
    16  //
    17  // The type on the right-hand side of the declaration can be accessed
    18  // using [Alias.Rhs]. This type may itself be an alias.
    19  // Call [Unalias] to obtain the first non-alias type in a chain of
    20  // alias type declarations.
    21  //
    22  // Like a defined ([Named]) type, an alias type has a name.
    23  // Use the [Alias.Obj] method to access its [TypeName] object.
    24  type Alias struct {
    25  	obj     *TypeName      // corresponding declared alias object
    26  	orig    *Alias         // original, uninstantiated alias
    27  	tparams *TypeParamList // type parameters, or nil
    28  	targs   *TypeList      // type arguments, or nil
    29  	fromRHS Type           // RHS of type alias declaration; may be an alias
    30  	actual  Type           // actual (aliased) type; never an alias
    31  	check   *Checker       // for cycle detection and cleanup; nil after cleanup
    32  }
    33  
    34  // NewAlias creates a new Alias type with the given type name and rhs.
    35  // If rhs is nil, the alias is incomplete.
    36  func NewAlias(obj *TypeName, rhs Type) *Alias {
    37  	alias := (*Checker)(nil).newAlias(obj, rhs)
    38  	// Ensure that alias.actual is set (go.dev/issue/65455).
    39  	if rhs != nil {
    40  		alias.cleanup()
    41  	}
    42  	return alias
    43  }
    44  
    45  // Obj returns the type name for the declaration defining the alias type a.
    46  // For instantiated types, this is same as the type name of the origin type.
    47  func (a *Alias) Obj() *TypeName { return a.orig.obj }
    48  
    49  func (a *Alias) String() string { return TypeString(a, nil) }
    50  
    51  // Underlying returns the [underlying type] of the alias type a, which is the
    52  // underlying type of the aliased type. Underlying types are never Named,
    53  // TypeParam, or Alias types.
    54  //
    55  // [underlying type]: https://go.dev/ref/spec#Underlying_types.
    56  func (a *Alias) Underlying() Type {
    57  	u := unalias(a)
    58  	if u == nil {
    59  		// Before CL 825744, Underlying() returned unalias(a).Underlying(). If the alias
    60  		// was incomplete (its RHS had not yet been set or resolved), unalias(a) returned
    61  		// nil, causing an immediate unhandled nil-pointer dereference panic.
    62  		//
    63  		// Callers must ensure an alias has been completed before querying its underlying type.
    64  		panic("Underlying() called on incomplete Alias")
    65  	}
    66  	return u.Underlying()
    67  }
    68  
    69  // Origin returns the generic Alias type of which a is an instance.
    70  // If a is not an instance of a generic alias, Origin returns a.
    71  func (a *Alias) Origin() *Alias { return a.orig }
    72  
    73  // TypeParams returns the type parameters of the alias type a, or nil.
    74  // A generic Alias and its instances have the same type parameters.
    75  func (a *Alias) TypeParams() *TypeParamList { return a.tparams }
    76  
    77  // SetTypeParams sets the type parameters of the alias type a.
    78  // The alias a must not have type arguments.
    79  func (a *Alias) SetTypeParams(tparams []*TypeParam) {
    80  	assert(a.targs == nil)
    81  	a.tparams = bindTParams(tparams)
    82  }
    83  
    84  // TypeArgs returns the type arguments used to instantiate the Alias type.
    85  // If a is not an instance of a generic alias, the result is nil.
    86  func (a *Alias) TypeArgs() *TypeList { return a.targs }
    87  
    88  // Rhs returns the type R on the right-hand side of an alias
    89  // declaration "type A = R", which may be another alias.
    90  func (a *Alias) Rhs() Type {
    91  	if a.fromRHS == nil {
    92  		// Before CL 825744, Rhs() returned a.fromRHS directly without checking for nil.
    93  		// If the alias was incomplete, callers expecting a non-nil Type could panic.
    94  		//
    95  		// An incomplete alias has no defined RHS. Rhs panics if called on an incomplete
    96  		// alias. Users must complete the alias first.
    97  		panic("Rhs() called on incomplete Alias")
    98  	}
    99  	return a.fromRHS
   100  }
   101  
   102  // Unalias returns t if it is not an alias type;
   103  // otherwise it follows t's alias chain until it
   104  // reaches a non-alias type which is then returned.
   105  // Consequently, the result is never an alias type.
   106  // Returns nil if the alias is incomplete.
   107  func Unalias(t Type) Type {
   108  	if a0, _ := t.(*Alias); a0 != nil {
   109  		return unalias(a0)
   110  	}
   111  	return t
   112  }
   113  
   114  func unalias(a0 *Alias) Type {
   115  	if a0.actual != nil {
   116  		return a0.actual
   117  	}
   118  	var t Type
   119  	for a := a0; a != nil; a, _ = t.(*Alias) {
   120  		t = a.fromRHS
   121  	}
   122  	// Memoize during type checking (single-threaded) avoids future
   123  	// quadratic chain traversal. Once a0.check becomes nil, unalias
   124  	// is a pure getter to prevent concurrent write races (go.dev/issue/81138).
   125  	if a0.check != nil && t != nil {
   126  		a0.actual = t
   127  	}
   128  	return t
   129  }
   130  
   131  // asNamed returns t as *Named if that is t's
   132  // actual type. It returns nil otherwise.
   133  func asNamed(t Type) *Named {
   134  	n, _ := Unalias(t).(*Named)
   135  	return n
   136  }
   137  
   138  // newAlias creates a new Alias type with the given type name and rhs.
   139  // If rhs is nil, the alias is incomplete.
   140  func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
   141  	a := new(Alias)
   142  	a.obj = obj
   143  	a.orig = a
   144  	a.fromRHS = rhs
   145  	a.check = check
   146  	if obj.typ == nil {
   147  		obj.typ = a
   148  	}
   149  
   150  	// Ensure that a.actual is set at the end of type checking.
   151  	if check != nil {
   152  		check.needsCleanup(a)
   153  	}
   154  
   155  	return a
   156  }
   157  
   158  // newAliasInstance creates a new alias instance for the given origin and type
   159  // arguments, recording pos as the position of its synthetic object (for error
   160  // reporting).
   161  func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
   162  	assert(len(targs) > 0)
   163  	obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
   164  	rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
   165  	res := check.newAlias(obj, rhs)
   166  	res.orig = orig
   167  	res.tparams = orig.tparams
   168  	res.targs = newTypeList(targs)
   169  	// Ensure that res.actual is set before returning an instance constructed
   170  	// outside of package type checking (e.g. via types.Instantiate). When check != nil,
   171  	// res was added to check.cleanups by newAlias and will be cleaned up at the end
   172  	// of checking. But when check == nil, no cleanup pass will run, so we must clean
   173  	// up eagerly to prevent concurrent calls to Unalias from racing on res.actual (go.dev/issue/81138).
   174  	if check == nil {
   175  		res.cleanup()
   176  	}
   177  	return res
   178  }
   179  
   180  func (a *Alias) cleanup() {
   181  	// Before CL 825744, an incomplete alias produced during type checking (e.g.
   182  	// due to a cycle or syntax error) could be left with fromRHS == nil and
   183  	// actual == nil. Callers traversing the published types would then panic
   184  	// when inspecting the alias.
   185  	//
   186  	// Here, we normalize incomplete aliases to Typ[Invalid] so the published
   187  	// package graph never contains buried nils.
   188  	//
   189  	// Invariant: The type checker must never return Typ[Invalid] unless an error was
   190  	// reported. If an alias created during package checking has a nil RHS at
   191  	// cleanup time, ensure an error is reported.
   192  	if a.fromRHS == nil {
   193  		if a.check != nil && a.check.firstErr == nil {
   194  			a.check.internalErrorf(a.obj, "alias %v has nil RHS", a.obj.name)
   195  		}
   196  		a.fromRHS = Typ[Invalid]
   197  	}
   198  	// Ensure a.actual is set before types are published,
   199  	// so unalias is a pure "getter", not a "setter".
   200  	a.actual = unalias(a)
   201  	a.check = nil
   202  }
   203  

View as plain text