]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: get type aliases working with generic types
authorDan Scales <danscales@google.com>
Mon, 24 May 2021 21:15:48 +0000 (14:15 -0700)
committerDan Scales <danscales@google.com>
Wed, 26 May 2021 21:38:54 +0000 (21:38 +0000)
Generic types can the source type of a type alias, so modify g.typ0() to
be able to deal with base generic types.

Added test aliasimp.go that tests aliasing of local generic types and
imported generic types.

Change-Id: I1c398193819d47a36b014cc1f9bb55107e9a565b
Reviewed-on: https://go-review.googlesource.com/c/go/+/322194
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/noder/types.go
test/typeparam/aliasimp.dir/a.go [new file with mode: 0644]
test/typeparam/aliasimp.dir/main.go [new file with mode: 0644]
test/typeparam/aliasimp.go [new file with mode: 0644]

index c6e97d4206b15a718b2e6f7d80cbd15a1f93d6d2..ae10e03a2471e83c370a159f63f17c66d2021d74 100644 (file)
@@ -91,50 +91,49 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
        case *types2.Basic:
                return g.basic(typ)
        case *types2.Named:
-               if typ.TParams() != nil {
+               // If tparams is set, but targs is not, typ is a base generic
+               // type. typ is appearing as part of the source type of an alias,
+               // since that is the only use of a generic type that doesn't
+               // involve instantiation. We just translate the named type in the
+               // normal way below using g.obj().
+               if typ.TParams() != nil && typ.TArgs() != nil {
                        // typ is an instantiation of a defined (named) generic type.
                        // This instantiation should also be a defined (named) type.
                        // types2 gives us the substituted type in t.Underlying()
                        // The substituted type may or may not still have type
                        // params. We might, for example, be substituting one type
                        // param for another type param.
-
-                       if typ.TArgs() == nil {
-                               base.Fatalf("In typ0, Targs should be set if TParams is set")
-                       }
-
-                       // When converted to types.Type, typ must have a name,
-                       // based on the names of the type arguments. We need a
-                       // name to deal with recursive generic types (and it also
-                       // looks better when printing types).
+                       //
+                       // When converted to types.Type, typ has a unique name,
+                       // based on the names of the type arguments.
                        instName := instTypeName2(typ.Obj().Name(), typ.TArgs())
                        s := g.pkg(typ.Obj().Pkg()).Lookup(instName)
                        if s.Def != nil {
-                               // We have already encountered this instantiation,
-                               // so use the type we previously created, since there
+                               // We have already encountered this instantiation.
+                               // Use the type we previously created, since there
                                // must be exactly one instance of a defined type.
                                return s.Def.Type()
                        }
 
                        // Create a forwarding type first and put it in the g.typs
-                       // map, in order to deal with recursive generic types.
-                       // Fully set up the extra ntyp information (Def, RParams,
-                       // which may set HasTParam) before translating the
-                       // underlying type itself, so we handle recursion
-                       // correctly, including via method signatures.
+                       // map, in order to deal with recursive generic types
+                       // (including via method signatures).. Set up the extra
+                       // ntyp information (Def, RParams, which may set
+                       // HasTParam) before translating the underlying type
+                       // itself, so we handle recursion correctly.
                        ntyp := typecheck.NewIncompleteNamedType(g.pos(typ.Obj().Pos()), s)
                        g.typs[typ] = ntyp
 
                        // If ntyp still has type params, then we must be
                        // referencing something like 'value[T2]', as when
-                       // specifying the generic receiver of a method,
-                       // where value was defined as "type value[T any]
-                       // ...". Save the type args, which will now be the
-                       // new type  of the current type.
+                       // specifying the generic receiver of a method, where
+                       // value was defined as "type value[T any] ...". Save the
+                       // type args, which will now be the new typeparams of the
+                       // current type.
                        //
                        // If ntyp does not have type params, we are saving the
-                       // concrete types used to instantiate this type. We'll use
-                       // these when instantiating the methods of the
+                       // non-generic types used to instantiate this type. We'll
+                       // use these when instantiating the methods of the
                        // instantiated type.
                        rparams := make([]*types.Type, len(typ.TArgs()))
                        for i, targ := range typ.TArgs() {
diff --git a/test/typeparam/aliasimp.dir/a.go b/test/typeparam/aliasimp.dir/a.go
new file mode 100644 (file)
index 0000000..3fac4aa
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type Rimp[T any] struct {
+        F T
+}
diff --git a/test/typeparam/aliasimp.dir/main.go b/test/typeparam/aliasimp.dir/main.go
new file mode 100644 (file)
index 0000000..6638fa9
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "a"
+
+type R[T any] struct {
+        F T
+}
+
+type S = R
+
+type Sint = R[int]
+
+type Simp = a.Rimp
+
+type SimpString Simp[string]
+
+func main() {
+       var s S[int]
+       if s.F != 0 {
+               panic(s.F)
+       }
+       var s2 Sint
+       if s2.F != 0 {
+               panic(s2.F)
+       }
+       var s3 Simp[string]
+       if s3.F != "" {
+               panic(s3.F)
+       }
+       var s4 SimpString
+       if s4.F != "" {
+               panic(s4.F)
+       }
+}
diff --git a/test/typeparam/aliasimp.go b/test/typeparam/aliasimp.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored