@@ -7,7 +7,10 @@ package go2go
7
7
import (
8
8
"fmt"
9
9
"go/ast"
10
+ "go/token"
10
11
"go/types"
12
+ "strconv"
13
+ "strings"
11
14
)
12
15
13
16
// lookupType returns the types.Type for an AST expression.
@@ -27,13 +30,13 @@ func (t *translator) lookupType(e ast.Expr) types.Type {
27
30
// Uninstantiated AST expressions will be listed in t.importer.info.Types.
28
31
func (t * translator ) setType (e ast.Expr , nt types.Type ) {
29
32
if ot , ok := t .importer .info .Types [e ]; ok {
30
- if ! types . IdenticalIgnoreTags (ot .Type , nt ) {
33
+ if ! t . sameType (ot .Type , nt ) {
31
34
panic ("expression type changed" )
32
35
}
33
36
return
34
37
}
35
38
if ot , ok := t .types [e ]; ok {
36
- if ! types . IdenticalIgnoreTags (ot , nt ) {
39
+ if ! t . sameType (ot , nt ) {
37
40
panic ("expression type changed" )
38
41
}
39
42
return
@@ -459,3 +462,165 @@ func (t *translator) tupleWithoutTags(tuple *types.Tuple) *types.Tuple {
459
462
}
460
463
return types .NewTuple (vars ... )
461
464
}
465
+
466
+ // typeToAST converts a types.Type to an ast.Expr.
467
+ func (t * translator ) typeToAST (typ types.Type ) ast.Expr {
468
+ var r ast.Expr
469
+ switch typ := typ .(type ) {
470
+ case * types.Basic :
471
+ r = ast .NewIdent (typ .Name ())
472
+ case * types.Array :
473
+ r = & ast.ArrayType {
474
+ Len : & ast.BasicLit {
475
+ Kind : token .INT ,
476
+ Value : strconv .FormatInt (typ .Len (), 10 ),
477
+ },
478
+ Elt : t .typeToAST (typ .Elem ()),
479
+ }
480
+ case * types.Slice :
481
+ r = & ast.ArrayType {
482
+ Elt : t .typeToAST (typ .Elem ()),
483
+ }
484
+ case * types.Struct :
485
+ var fields []* ast.Field
486
+ n := typ .NumFields ()
487
+ for i := 0 ; i < n ; i ++ {
488
+ tf := typ .Field (i )
489
+ var names []* ast.Ident
490
+ if ! tf .Embedded () {
491
+ names = []* ast.Ident {
492
+ ast .NewIdent (tf .Name ()),
493
+ }
494
+ }
495
+ var atag * ast.BasicLit
496
+ if tag := typ .Tag (i ); tag != "" {
497
+ atag = & ast.BasicLit {
498
+ Kind : token .STRING ,
499
+ Value : strconv .Quote (tag ),
500
+ }
501
+ }
502
+ af := & ast.Field {
503
+ Names : names ,
504
+ Type : t .typeToAST (tf .Type ()),
505
+ Tag : atag ,
506
+ }
507
+ fields = append (fields , af )
508
+ }
509
+ r = & ast.StructType {
510
+ Fields : & ast.FieldList {
511
+ List : fields ,
512
+ },
513
+ }
514
+ case * types.Pointer :
515
+ r = & ast.StarExpr {
516
+ X : t .typeToAST (typ .Elem ()),
517
+ }
518
+ case * types.Tuple :
519
+ // We should only see this in a types.Signature,
520
+ // where we handle it specially, since there is
521
+ // no ast.Expr that can represent this.
522
+ panic ("unexpected types.Tuple" )
523
+ case * types.Signature :
524
+ if len (typ .TParams ()) > 0 {
525
+ // We should only see type parameters for
526
+ // a package scope function declaration.
527
+ panic ("unexpected type parameters" )
528
+ }
529
+ r = & ast.FuncType {
530
+ Params : t .tupleToFieldList (typ .Params ()),
531
+ Results : t .tupleToFieldList (typ .Params ()),
532
+ }
533
+ case * types.Interface :
534
+ var methods []* ast.Field
535
+ nm := typ .NumExplicitMethods ()
536
+ for i := 0 ; i < nm ; i ++ {
537
+ m := typ .ExplicitMethod (i )
538
+ f := & ast.Field {
539
+ Names : []* ast.Ident {
540
+ ast .NewIdent (m .Name ()),
541
+ },
542
+ Type : t .typeToAST (m .Type ()),
543
+ }
544
+ methods = append (methods , f )
545
+ }
546
+ ne := typ .NumEmbeddeds ()
547
+ for i := 0 ; i < ne ; i ++ {
548
+ e := typ .EmbeddedType (i )
549
+ f := & ast.Field {
550
+ Type : t .typeToAST (e ),
551
+ }
552
+ methods = append (methods , f )
553
+ }
554
+ r = & ast.InterfaceType {
555
+ Methods : & ast.FieldList {
556
+ List : methods ,
557
+ },
558
+ }
559
+ case * types.Map :
560
+ r = & ast.MapType {
561
+ Key : t .typeToAST (typ .Key ()),
562
+ Value : t .typeToAST (typ .Elem ()),
563
+ }
564
+ case * types.Chan :
565
+ var dir ast.ChanDir
566
+ switch typ .Dir () {
567
+ case types .SendRecv :
568
+ dir = ast .SEND | ast .RECV
569
+ case types .SendOnly :
570
+ dir = ast .SEND
571
+ case types .RecvOnly :
572
+ dir = ast .RECV
573
+ default :
574
+ panic ("unsupported channel direction" )
575
+ }
576
+ r = & ast.ChanType {
577
+ Dir : dir ,
578
+ Value : t .typeToAST (typ .Elem ()),
579
+ }
580
+ case * types.Named :
581
+ if len (typ .TArgs ()) > 0 {
582
+ _ , id := t .lookupInstantiatedType (typ )
583
+ r = id
584
+ } else {
585
+ var sb strings.Builder
586
+ tn := typ .Obj ()
587
+ if tn .Pkg () != nil && tn .Pkg () != t .tpkg {
588
+ sb .WriteString (tn .Pkg ().Name ())
589
+ sb .WriteByte ('.' )
590
+ }
591
+ sb .WriteString (tn .Name ())
592
+ r = ast .NewIdent (sb .String ())
593
+ }
594
+ case * types.TypeParam :
595
+ // This should have been instantiated already.
596
+ panic ("unexpected type parameter" )
597
+ default :
598
+ panic (fmt .Sprintf ("unimplemented Type %T" , typ ))
599
+ }
600
+
601
+ t .setType (r , typ )
602
+ return r
603
+ }
604
+
605
+ // tupleToFieldList converts a tupes.Tuple to a ast.FieldList.
606
+ func (t * translator ) tupleToFieldList (tuple * types.Tuple ) * ast.FieldList {
607
+ var fields []* ast.Field
608
+ n := tuple .Len ()
609
+ for i := 0 ; i < n ; i ++ {
610
+ v := tuple .At (i )
611
+ var names []* ast.Ident
612
+ if v .Name () != "" {
613
+ names = []* ast.Ident {
614
+ ast .NewIdent (v .Name ()),
615
+ }
616
+ }
617
+ f := & ast.Field {
618
+ Names : names ,
619
+ Type : t .typeToAST (v .Type ()),
620
+ }
621
+ fields = append (fields , f )
622
+ }
623
+ return & ast.FieldList {
624
+ List : fields ,
625
+ }
626
+ }
0 commit comments