2
2
// Use of this source code is governed by a BSD-style
3
3
// license that can be found in the LICENSE file.
4
4
5
+ //go:build go1.23
6
+
5
7
// The play program is a playground for go/types: a simple web-based
6
8
// text editor into which the user can enter a Go program, select a
7
9
// region, and see type information about it.
@@ -35,7 +37,6 @@ import (
35
37
36
38
// TODO(adonovan):
37
39
// - show line numbers next to textarea.
38
- // - show a (tree) breakdown of the representation of the expression's type.
39
40
// - mention this in the go/types tutorial.
40
41
// - display versions of go/types and go command.
41
42
@@ -297,6 +298,10 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
297
298
}
298
299
fmt .Fprintf (out , "\n \n " )
299
300
301
+ fmt .Fprintf (out , "Type:\n " )
302
+ describeType (out , obj .Type ())
303
+ fmt .Fprintf (out , "\n " )
304
+
300
305
// method set
301
306
if methods := typeutil .IntuitiveMethodSet (obj .Type (), nil ); len (methods ) > 0 {
302
307
fmt .Fprintf (out , "Methods:\n " )
@@ -318,6 +323,65 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
318
323
}
319
324
}
320
325
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
+
321
385
func handleRoot (w http.ResponseWriter , req * http.Request ) { io .WriteString (w , mainHTML ) }
322
386
func handleJS (w http.ResponseWriter , req * http.Request ) { io .WriteString (w , mainJS ) }
323
387
func handleCSS (w http.ResponseWriter , req * http.Request ) { io .WriteString (w , mainCSS ) }
0 commit comments