Skip to content

Commit 44abb0a

Browse files
committed
go/types/internal/play: display type structure
Display the complete recursive structure of a types.Type, in the style of ast.Fprint. Change-Id: I408c9b1f1beb214e0184381e97085e606ad8a5a1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/649617 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 3c245da commit 44abb0a

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

go/types/internal/play/play.go

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build go1.23
6+
57
// The play program is a playground for go/types: a simple web-based
68
// text editor into which the user can enter a Go program, select a
79
// region, and see type information about it.
@@ -35,7 +37,6 @@ import (
3537

3638
// TODO(adonovan):
3739
// - show line numbers next to textarea.
38-
// - show a (tree) breakdown of the representation of the expression's type.
3940
// - mention this in the go/types tutorial.
4041
// - display versions of go/types and go command.
4142

@@ -297,6 +298,10 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
297298
}
298299
fmt.Fprintf(out, "\n\n")
299300

301+
fmt.Fprintf(out, "Type:\n")
302+
describeType(out, obj.Type())
303+
fmt.Fprintf(out, "\n")
304+
300305
// method set
301306
if methods := typeutil.IntuitiveMethodSet(obj.Type(), nil); len(methods) > 0 {
302307
fmt.Fprintf(out, "Methods:\n")
@@ -318,6 +323,65 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
318323
}
319324
}
320325

326+
// describeType formats t to out in a way that makes it clear what methods to call on t to
327+
// get at its parts.
328+
// describeType assumes t was constructed by the type checker, so it doesn't check
329+
// for recursion. The type checker replaces recursive alias types, which are illegal,
330+
// with a BasicType that says as much. Other types that it constructs are recursive
331+
// only via a name, and this function does not traverse names.
332+
func describeType(out *strings.Builder, t types.Type) {
333+
depth := -1
334+
335+
var ft func(string, types.Type)
336+
ft = func(prefix string, t types.Type) {
337+
depth++
338+
defer func() { depth-- }()
339+
340+
for range depth {
341+
fmt.Fprint(out, ". ")
342+
}
343+
344+
fmt.Fprintf(out, "%s%T:", prefix, t)
345+
switch t := t.(type) {
346+
case *types.Basic:
347+
fmt.Fprintf(out, " Name: %q\n", t.Name())
348+
case *types.Pointer:
349+
fmt.Fprintln(out)
350+
ft("Elem: ", t.Elem())
351+
case *types.Slice:
352+
fmt.Fprintln(out)
353+
ft("Elem: ", t.Elem())
354+
case *types.Array:
355+
fmt.Fprintf(out, " Len: %d\n", t.Len())
356+
ft("Elem: ", t.Elem())
357+
case *types.Map:
358+
fmt.Fprintln(out)
359+
ft("Key: ", t.Key())
360+
ft("Elem: ", t.Elem())
361+
case *types.Chan:
362+
fmt.Fprintf(out, " Dir: %s\n", chanDirs[t.Dir()])
363+
ft("Elem: ", t.Elem())
364+
case *types.Alias:
365+
fmt.Fprintf(out, " Name: %q\n", t.Obj().Name())
366+
ft("Rhs: ", t.Rhs())
367+
default:
368+
// For types we may have missed or which have too much to bother with,
369+
// print their string representation.
370+
// TODO(jba): print more about struct types (their fields) and interface and named
371+
// types (their methods).
372+
fmt.Fprintf(out, " %s\n", t)
373+
}
374+
}
375+
376+
ft("", t)
377+
}
378+
379+
var chanDirs = []string{
380+
"SendRecv",
381+
"SendOnly",
382+
"RecvOnly",
383+
}
384+
321385
func handleRoot(w http.ResponseWriter, req *http.Request) { io.WriteString(w, mainHTML) }
322386
func handleJS(w http.ResponseWriter, req *http.Request) { io.WriteString(w, mainJS) }
323387
func handleCSS(w http.ResponseWriter, req *http.Request) { io.WriteString(w, mainCSS) }

0 commit comments

Comments
 (0)