]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: start translating type params in noder2
authorDan Scales <danscales@google.com>
Fri, 29 Jan 2021 01:43:18 +0000 (17:43 -0800)
committerDan Scales <danscales@google.com>
Sat, 30 Jan 2021 00:42:35 +0000 (00:42 +0000)
Also, make some fmt changes so that the type parameters and the
typeparam type are displayed in -W=2.

You can now parse a simple generic function (but not generic calls or generic
types) and print out the noder IR via 'go tool compile -G=2 -W=2 func.go'

Change-Id: I1f070fc4a96174a447763ad37999e61c25905901
Reviewed-on: https://go-review.googlesource.com/c/go/+/287833
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
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
src/cmd/compile/internal/types/fmt.go
src/cmd/compile/internal/types/size.go
src/cmd/compile/internal/types/type.go
src/cmd/compile/internal/types2/type.go

index de191acc9055bd371796b86d6cc171a70c1ac900..b4ad9cfc5b8c94fbbe01cf6be842ec4b9e073700 100644 (file)
@@ -100,6 +100,12 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
 
                return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...))
 
+       case *types2.TypeParam:
+               tp := types.NewTypeParam(g.tpkg(typ), g.typ(typ.Bound()))
+               // Save the name of the type parameter in the sym of the type.
+               tp.SetSym(g.sym(typ.Obj()))
+               return tp
+
        default:
                base.FatalfAt(src.NoXPos, "unhandled type: %v (%T)", typ, typ)
                panic("unreachable")
@@ -107,6 +113,13 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
 }
 
 func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
+       tparams2 := sig.TParams()
+       tparams := make([]*types.Field, len(tparams2))
+       for i := range tparams {
+               tp := tparams2[i]
+               tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ(tp.Type()))
+       }
+
        do := func(typ *types2.Tuple) []*types.Field {
                fields := make([]*types.Field, typ.Len())
                for i := range fields {
@@ -114,14 +127,13 @@ func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type
                }
                return fields
        }
-
        params := do(sig.Params())
        results := do(sig.Results())
        if sig.Variadic() {
                params[len(params)-1].SetIsDDD(true)
        }
 
-       return types.NewSignature(g.tpkg(sig), recv, nil, params, results)
+       return types.NewSignature(g.tpkg(sig), recv, tparams, params, results)
 }
 
 func (g *irgen) param(v *types2.Var) *types.Field {
index da224d40192a717ad3176819277bb8cdfffbb43a..c59f62e302d8127b48a0c3e276e7585ac133d9c2 100644 (file)
@@ -318,7 +318,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
        }
 
        // Unless the 'L' flag was specified, if the type has a name, just print that name.
-       if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] {
+       if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] && t.Kind() != TTYPEPARAM {
                switch mode {
                case fmtTypeID, fmtTypeIDName:
                        if verb == 'S' {
@@ -478,6 +478,9 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                        }
                        b.WriteString("func")
                }
+               if t.NumTParams() > 0 {
+                       tconv2(b, t.TParams(), 0, mode, visited)
+               }
                tconv2(b, t.Params(), 0, mode, visited)
 
                switch t.NumResults() {
@@ -515,7 +518,11 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                }
 
                if funarg := t.StructType().Funarg; funarg != FunargNone {
-                       b.WriteByte('(')
+                       open, close := '(', ')'
+                       if funarg == FunargTparams {
+                               open, close = '[', ']'
+                       }
+                       b.WriteByte(byte(open))
                        fieldVerb := 'v'
                        switch mode {
                        case fmtTypeID, fmtTypeIDName, fmtGo:
@@ -528,7 +535,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                                }
                                fldconv(b, f, fieldVerb, mode, visited, funarg)
                        }
-                       b.WriteByte(')')
+                       b.WriteByte(byte(close))
                } else {
                        b.WriteString("struct {")
                        for i, f := range t.Fields().Slice() {
@@ -554,6 +561,15 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
        case TUNSAFEPTR:
                b.WriteString("unsafe.Pointer")
 
+       case TTYPEPARAM:
+               if t.Sym() != nil {
+                       sconv2(b, t.Sym(), 'v', mode)
+               } else {
+                       b.WriteString("tp")
+                       // Print out the pointer value for now to disambiguate type params
+                       b.WriteString(fmt.Sprintf("%p", t))
+               }
+
        case Txxx:
                b.WriteString("Txxx")
 
index 98540eefb651daf647142d563dcf45e5e68fb763..d1203e4a219219e5345241d752e304c0c7c6bb31 100644 (file)
@@ -499,6 +499,11 @@ func CalcSize(t *Type) {
                        base.Warn("bad type %v %d\n", t1, w)
                }
                t.Align = 1
+
+       case TTYPEPARAM:
+               // TODO(danscales) - remove when we eliminate the need
+               // to do CalcSize in noder2 (which shouldn't be needed in the noder)
+               w = int64(PtrSize)
        }
 
        if PtrSize == 4 && w != int64(int32(w)) {
index 1d6edcda47205c6fb7b730b5ea9a926263a84437..8d07b88ecd2798caa174e32abf0ce7596a79f0b9 100644 (file)
@@ -204,7 +204,8 @@ func (t *Type) SetRecur(b bool)      { t.flags.set(typeRecur, b) }
 func (t *Type) Kind() Kind { return t.kind }
 
 // Sym returns the name of type t.
-func (t *Type) Sym() *Sym { return t.sym }
+func (t *Type) Sym() *Sym       { return t.sym }
+func (t *Type) SetSym(sym *Sym) { t.sym = sym }
 
 // Underlying returns the underlying type of type t.
 func (t *Type) Underlying() *Type { return t.underlying }
@@ -285,7 +286,7 @@ type Func struct {
        Receiver *Type // function receiver
        Results  *Type // function results
        Params   *Type // function params
-       Tparams  *Type // type params of receiver (if method) or function
+       TParams  *Type // type params of receiver (if method) or function
 
        pkg *Pkg
 
@@ -512,6 +513,8 @@ func New(et Kind) *Type {
                t.Extra = new(Tuple)
        case TRESULTS:
                t.Extra = new(Results)
+       case TTYPEPARAM:
+               t.Extra = new(Interface)
        }
        return t
 }
@@ -769,10 +772,12 @@ func (t *Type) wantEtype(et Kind) {
 }
 
 func (t *Type) Recvs() *Type   { return t.FuncType().Receiver }
+func (t *Type) TParams() *Type { return t.FuncType().TParams }
 func (t *Type) Params() *Type  { return t.FuncType().Params }
 func (t *Type) Results() *Type { return t.FuncType().Results }
 
 func (t *Type) NumRecvs() int   { return t.FuncType().Receiver.NumFields() }
+func (t *Type) NumTParams() int { return t.FuncType().TParams.NumFields() }
 func (t *Type) NumParams() int  { return t.FuncType().Params.NumFields() }
 func (t *Type) NumResults() int { return t.FuncType().Results.NumFields() }
 
@@ -1648,6 +1653,15 @@ func NewInterface(pkg *Pkg, methods []*Field) *Type {
        return t
 }
 
+// NewTypeParam returns a new type param with the given constraint (which may
+// not really be needed except for the type checker).
+func NewTypeParam(pkg *Pkg, constraint *Type) *Type {
+       t := New(TTYPEPARAM)
+       t.methods = constraint.methods
+       t.Extra.(*Interface).pkg = pkg
+       return t
+}
+
 // NewSignature returns a new function type for the given receiver,
 // parametes, results, and type parameters, any of which may be nil.
 func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Type {
@@ -1669,7 +1683,7 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ
        }
 
        ft.Receiver = funargs(recvs, FunargRcvr)
-       ft.Tparams = funargs(tparams, FunargTparams)
+       ft.TParams = funargs(tparams, FunargTparams)
        ft.Params = funargs(params, FunargParams)
        ft.Results = funargs(results, FunargResults)
        ft.pkg = pkg
index 22901b2ba976f8d30ef5c018c9ec874991d06597..7e51a138b5f0d702c2e7c7f73152e034a3695dd0 100644 (file)
@@ -837,6 +837,10 @@ type TypeParam struct {
        aType
 }
 
+func (t *TypeParam) Obj() *TypeName {
+       return t.obj
+}
+
 // NewTypeParam returns a new TypeParam.
 func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
        assert(bound != nil)