]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/types2/alias.go
go/types, types2: implement Alias proposal (export API)
[gostls13.git] / src / cmd / compile / internal / types2 / alias.go
index 375046b98351cf90c435569ea63eb6035872117e..2cc57721f9ddab02057354d626db5ffe9c367616 100644 (file)
@@ -4,14 +4,80 @@
 
 package types2
 
-// This file will eventually define an Alias type.
-// For now it declares asNamed. Once Alias types
-// exist, asNamed will need to indirect through
-// them as needed.
+import "fmt"
+
+// An Alias represents an alias type.
+// Whether or not Alias types are created is controlled by the
+// gotypesalias setting with the GODEBUG environment variable.
+// For gotypesalias=1, alias declarations produce an Alias type.
+// Otherwise, the alias information is only in the type name,
+// which points directly to the actual (aliased) type.
+type Alias struct {
+       obj     *TypeName // corresponding declared alias object
+       fromRHS Type      // RHS of type alias declaration; may be an alias
+       actual  Type      // actual (aliased) type; never an alias
+}
+
+// NewAlias creates a new Alias type with the given type name and rhs.
+// rhs must not be nil.
+func NewAlias(obj *TypeName, rhs Type) *Alias {
+       return (*Checker)(nil).newAlias(obj, rhs)
+}
+
+func (a *Alias) Obj() *TypeName   { return a.obj }
+func (a *Alias) Underlying() Type { return a.actual.Underlying() }
+func (a *Alias) String() string   { return TypeString(a, nil) }
+
+// Type accessors
+
+// Unalias returns t if it is not an alias type;
+// otherwise it follows t's alias chain until it
+// reaches a non-alias type which is then returned.
+// Consequently, the result is never an alias type.
+func Unalias(t Type) Type {
+       if a0, _ := t.(*Alias); a0 != nil {
+               if a0.actual != nil {
+                       return a0.actual
+               }
+               for a := a0; ; {
+                       t = a.fromRHS
+                       a, _ = t.(*Alias)
+                       if a == nil {
+                               break
+                       }
+               }
+               if t == nil {
+                       panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
+               }
+               a0.actual = t
+       }
+       return t
+}
 
 // asNamed returns t as *Named if that is t's
 // actual type. It returns nil otherwise.
 func asNamed(t Type) *Named {
-       n, _ := t.(*Named)
+       n, _ := Unalias(t).(*Named)
        return n
 }
+
+// newAlias creates a new Alias type with the given type name and rhs.
+// rhs must not be nil.
+func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
+       assert(rhs != nil)
+       a := &Alias{obj, rhs, nil}
+       if obj.typ == nil {
+               obj.typ = a
+       }
+
+       // Ensure that a.actual is set at the end of type checking.
+       if check != nil {
+               check.needsCleanup(a)
+       }
+
+       return a
+}
+
+func (a *Alias) cleanup() {
+       Unalias(a)
+}