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  	"fmt"
    10  )
    11  
    12  // An Alias represents an alias type.
    13  // Whether or not Alias types are created is controlled by the
    14  // gotypesalias setting with the GODEBUG environment variable.
    15  // For gotypesalias=1, alias declarations produce an Alias type.
    16  // Otherwise, the alias information is only in the type name,
    17  // which points directly to the actual (aliased) type.
    18  type Alias struct {
    19  	obj     *TypeName      // corresponding declared alias object
    20  	orig    *Alias         // original, uninstantiated alias
    21  	tparams *TypeParamList // type parameters, or nil
    22  	targs   *TypeList      // type arguments, or nil
    23  	fromRHS Type           // RHS of type alias declaration; may be an alias
    24  	actual  Type           // actual (aliased) type; never an alias
    25  }
    26  
    27  // NewAlias creates a new Alias type with the given type name and rhs.
    28  // rhs must not be nil.
    29  func NewAlias(obj *TypeName, rhs Type) *Alias {
    30  	alias := (*Checker)(nil).newAlias(obj, rhs)
    31  	// Ensure that alias.actual is set (#65455).
    32  	alias.cleanup()
    33  	return alias
    34  }
    35  
    36  // Obj returns the type name for the declaration defining the alias type a.
    37  // For instantiated types, this is same as the type name of the origin type.
    38  func (a *Alias) Obj() *TypeName { return a.orig.obj }
    39  
    40  func (a *Alias) String() string { return TypeString(a, nil) }
    41  
    42  // Underlying returns the [underlying type] of the alias type a, which is the
    43  // underlying type of the aliased type. Underlying types are never Named,
    44  // TypeParam, or Alias types.
    45  //
    46  // [underlying type]: https://go.dev/ref/spec#Underlying_types.
    47  func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
    48  
    49  // Origin returns the generic Alias type of which a is an instance.
    50  // If a is not an instance of a generic alias, Origin returns a.
    51  func (a *Alias) Origin() *Alias { return a.orig }
    52  
    53  // TypeParams returns the type parameters of the alias type a, or nil.
    54  // A generic Alias and its instances have the same type parameters.
    55  func (a *Alias) TypeParams() *TypeParamList { return a.tparams }
    56  
    57  // SetTypeParams sets the type parameters of the alias type a.
    58  // The alias a must not have type arguments.
    59  func (a *Alias) SetTypeParams(tparams []*TypeParam) {
    60  	assert(a.targs == nil)
    61  	a.tparams = bindTParams(tparams)
    62  }
    63  
    64  // TypeArgs returns the type arguments used to instantiate the Alias type.
    65  // If a is not an instance of a generic alias, the result is nil.
    66  func (a *Alias) TypeArgs() *TypeList { return a.targs }
    67  
    68  // Rhs returns the type R on the right-hand side of an alias
    69  // declaration "type A = R", which may be another alias.
    70  func (a *Alias) Rhs() Type { return a.fromRHS }
    71  
    72  // Unalias returns t if it is not an alias type;
    73  // otherwise it follows t's alias chain until it
    74  // reaches a non-alias type which is then returned.
    75  // Consequently, the result is never an alias type.
    76  func Unalias(t Type) Type {
    77  	if a0, _ := t.(*Alias); a0 != nil {
    78  		return unalias(a0)
    79  	}
    80  	return t
    81  }
    82  
    83  func unalias(a0 *Alias) Type {
    84  	if a0.actual != nil {
    85  		return a0.actual
    86  	}
    87  	var t Type
    88  	for a := a0; a != nil; a, _ = t.(*Alias) {
    89  		t = a.fromRHS
    90  	}
    91  	if t == nil {
    92  		panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
    93  	}
    94  
    95  	// Memoize the type only if valid.
    96  	// In the presence of unfinished cyclic declarations, Unalias
    97  	// would otherwise latch the invalid value (#66704).
    98  	// TODO(adonovan): rethink, along with checker.typeDecl's use
    99  	// of Invalid to mark unfinished aliases.
   100  	if t != Typ[Invalid] {
   101  		a0.actual = t
   102  	}
   103  
   104  	return t
   105  }
   106  
   107  // asNamed returns t as *Named if that is t's
   108  // actual type. It returns nil otherwise.
   109  func asNamed(t Type) *Named {
   110  	n, _ := Unalias(t).(*Named)
   111  	return n
   112  }
   113  
   114  // newAlias creates a new Alias type with the given type name and rhs.
   115  // rhs must not be nil.
   116  func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
   117  	assert(rhs != nil)
   118  	a := new(Alias)
   119  	a.obj = obj
   120  	a.orig = a
   121  	a.fromRHS = rhs
   122  	if obj.typ == nil {
   123  		obj.typ = a
   124  	}
   125  
   126  	// Ensure that a.actual is set at the end of type checking.
   127  	if check != nil {
   128  		check.needsCleanup(a)
   129  	}
   130  
   131  	return a
   132  }
   133  
   134  // newAliasInstance creates a new alias instance for the given origin and type
   135  // arguments, recording pos as the position of its synthetic object (for error
   136  // reporting).
   137  func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
   138  	assert(len(targs) > 0)
   139  	obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
   140  	rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
   141  	res := check.newAlias(obj, rhs)
   142  	res.orig = orig
   143  	res.tparams = orig.tparams
   144  	res.targs = newTypeList(targs)
   145  	return res
   146  }
   147  
   148  func (a *Alias) cleanup() {
   149  	// Ensure a.actual is set before types are published,
   150  	// so Unalias is a pure "getter", not a "setter".
   151  	actual := Unalias(a)
   152  
   153  	if actual == Typ[Invalid] {
   154  		// We don't set a.actual to Typ[Invalid] during type checking,
   155  		// as it may indicate that the RHS is not fully set up.
   156  		a.actual = actual
   157  	}
   158  }
   159  

View as plain text