@@ -381,6 +381,76 @@ func firstInSrc(path []Object) int {
381
381
return fst
382
382
}
383
383
384
+ type (
385
+ decl interface {
386
+ node () ast.Node
387
+ }
388
+
389
+ importDecl struct { spec * ast.ImportSpec }
390
+ constDecl struct {
391
+ spec * ast.ValueSpec
392
+ iota int
393
+ typ ast.Expr
394
+ init []ast.Expr
395
+ }
396
+ varDecl struct { spec * ast.ValueSpec }
397
+ typeDecl struct { spec * ast.TypeSpec }
398
+ funcDecl struct { decl * ast.FuncDecl }
399
+ )
400
+
401
+ func (d importDecl ) node () ast.Node { return d .spec }
402
+ func (d constDecl ) node () ast.Node { return d .spec }
403
+ func (d varDecl ) node () ast.Node { return d .spec }
404
+ func (d typeDecl ) node () ast.Node { return d .spec }
405
+ func (d funcDecl ) node () ast.Node { return d .decl }
406
+
407
+ func (check * Checker ) walkDecls (decls []ast.Decl , f func (decl )) {
408
+ for _ , d := range decls {
409
+ check .walkDecl (d , f )
410
+ }
411
+ }
412
+
413
+ func (check * Checker ) walkDecl (d ast.Decl , f func (decl )) {
414
+ switch d := d .(type ) {
415
+ case * ast.BadDecl :
416
+ // ignore
417
+ case * ast.GenDecl :
418
+ var last * ast.ValueSpec // last ValueSpec with type or init exprs seen
419
+ for iota , s := range d .Specs {
420
+ switch s := s .(type ) {
421
+ case * ast.ImportSpec :
422
+ f (importDecl {s })
423
+ case * ast.ValueSpec :
424
+ switch d .Tok {
425
+ case token .CONST :
426
+ // determine which initialization expressions to use
427
+ switch {
428
+ case s .Type != nil || len (s .Values ) > 0 :
429
+ last = s
430
+ case last == nil :
431
+ last = new (ast.ValueSpec ) // make sure last exists
432
+ }
433
+ check .arityMatch (s , last )
434
+ f (constDecl {spec : s , iota : iota , init : last .Values , typ : last .Type })
435
+ case token .VAR :
436
+ check .arityMatch (s , nil )
437
+ f (varDecl {s })
438
+ default :
439
+ check .invalidAST (s .Pos (), "invalid token %s" , d .Tok )
440
+ }
441
+ case * ast.TypeSpec :
442
+ f (typeDecl {s })
443
+ default :
444
+ check .invalidAST (s .Pos (), "unknown ast.Spec node %T" , s )
445
+ }
446
+ }
447
+ case * ast.FuncDecl :
448
+ f (funcDecl {d })
449
+ default :
450
+ check .invalidAST (d .Pos (), "unknown ast.Decl node %T" , d )
451
+ }
452
+ }
453
+
384
454
func (check * Checker ) constDecl (obj * Const , typ , init ast.Expr ) {
385
455
assert (obj .typ == nil )
386
456
@@ -664,133 +734,105 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
664
734
}
665
735
}
666
736
667
- func (check * Checker ) declStmt (decl ast.Decl ) {
737
+ func (check * Checker ) declStmt (d ast.Decl ) {
668
738
pkg := check .pkg
669
739
670
- switch d := decl .(type ) {
671
- case * ast.BadDecl :
672
- // ignore
740
+ check .walkDecl (d , func (d decl ) {
741
+ switch d := d .(type ) {
742
+ case constDecl :
743
+ top := len (check .delayed )
673
744
674
- case * ast.GenDecl :
675
- var last * ast.ValueSpec // last ValueSpec with type or init exprs seen
676
- for iota , spec := range d .Specs {
677
- switch s := spec .(type ) {
678
- case * ast.ValueSpec :
679
- switch d .Tok {
680
- case token .CONST :
681
- top := len (check .delayed )
745
+ // declare all constants
746
+ lhs := make ([]* Const , len (d .spec .Names ))
747
+ for i , name := range d .spec .Names {
748
+ obj := NewConst (name .Pos (), pkg , name .Name , nil , constant .MakeInt64 (int64 (d .iota )))
749
+ lhs [i ] = obj
682
750
683
- // determine which init exprs to use
684
- switch {
685
- case s .Type != nil || len (s .Values ) > 0 :
686
- last = s
687
- case last == nil :
688
- last = new (ast.ValueSpec ) // make sure last exists
689
- }
690
-
691
- // declare all constants
692
- lhs := make ([]* Const , len (s .Names ))
693
- for i , name := range s .Names {
694
- obj := NewConst (name .Pos (), pkg , name .Name , nil , constant .MakeInt64 (int64 (iota )))
695
- lhs [i ] = obj
696
-
697
- var init ast.Expr
698
- if i < len (last .Values ) {
699
- init = last .Values [i ]
700
- }
751
+ var init ast.Expr
752
+ if i < len (d .init ) {
753
+ init = d .init [i ]
754
+ }
701
755
702
- check .constDecl (obj , last . Type , init )
703
- }
756
+ check .constDecl (obj , d . typ , init )
757
+ }
704
758
705
- check .arityMatch (s , last )
759
+ // process function literals in init expressions before scope changes
760
+ check .processDelayed (top )
706
761
707
- // process function literals in init expressions before scope changes
708
- check .processDelayed (top )
762
+ // spec: "The scope of a constant or variable identifier declared
763
+ // inside a function begins at the end of the ConstSpec or VarSpec
764
+ // (ShortVarDecl for short variable declarations) and ends at the
765
+ // end of the innermost containing block."
766
+ scopePos := d .spec .End ()
767
+ for i , name := range d .spec .Names {
768
+ check .declare (check .scope , name , lhs [i ], scopePos )
769
+ }
709
770
710
- // spec: "The scope of a constant or variable identifier declared
711
- // inside a function begins at the end of the ConstSpec or VarSpec
712
- // (ShortVarDecl for short variable declarations) and ends at the
713
- // end of the innermost containing block."
714
- scopePos := s .End ()
715
- for i , name := range s .Names {
716
- check .declare (check .scope , name , lhs [i ], scopePos )
717
- }
771
+ case varDecl :
772
+ top := len (check .delayed )
718
773
719
- case token .VAR :
720
- top := len (check .delayed )
774
+ lhs0 := make ([]* Var , len (d .spec .Names ))
775
+ for i , name := range d .spec .Names {
776
+ lhs0 [i ] = NewVar (name .Pos (), pkg , name .Name , nil )
777
+ }
721
778
722
- lhs0 := make ([]* Var , len (s .Names ))
723
- for i , name := range s .Names {
724
- lhs0 [i ] = NewVar (name .Pos (), pkg , name .Name , nil )
779
+ // initialize all variables
780
+ for i , obj := range lhs0 {
781
+ var lhs []* Var
782
+ var init ast.Expr
783
+ switch len (d .spec .Values ) {
784
+ case len (d .spec .Names ):
785
+ // lhs and rhs match
786
+ init = d .spec .Values [i ]
787
+ case 1 :
788
+ // rhs is expected to be a multi-valued expression
789
+ lhs = lhs0
790
+ init = d .spec .Values [0 ]
791
+ default :
792
+ if i < len (d .spec .Values ) {
793
+ init = d .spec .Values [i ]
725
794
}
726
-
727
- // initialize all variables
728
- for i , obj := range lhs0 {
729
- var lhs []* Var
730
- var init ast.Expr
731
- switch len (s .Values ) {
732
- case len (s .Names ):
733
- // lhs and rhs match
734
- init = s .Values [i ]
735
- case 1 :
736
- // rhs is expected to be a multi-valued expression
737
- lhs = lhs0
738
- init = s .Values [0 ]
739
- default :
740
- if i < len (s .Values ) {
741
- init = s .Values [i ]
742
- }
743
- }
744
- check .varDecl (obj , lhs , s .Type , init )
745
- if len (s .Values ) == 1 {
746
- // If we have a single lhs variable we are done either way.
747
- // If we have a single rhs expression, it must be a multi-
748
- // valued expression, in which case handling the first lhs
749
- // variable will cause all lhs variables to have a type
750
- // assigned, and we are done as well.
751
- if debug {
752
- for _ , obj := range lhs0 {
753
- assert (obj .typ != nil )
754
- }
755
- }
756
- break
795
+ }
796
+ check .varDecl (obj , lhs , d .spec .Type , init )
797
+ if len (d .spec .Values ) == 1 {
798
+ // If we have a single lhs variable we are done either way.
799
+ // If we have a single rhs expression, it must be a multi-
800
+ // valued expression, in which case handling the first lhs
801
+ // variable will cause all lhs variables to have a type
802
+ // assigned, and we are done as well.
803
+ if debug {
804
+ for _ , obj := range lhs0 {
805
+ assert (obj .typ != nil )
757
806
}
758
807
}
759
-
760
- check .arityMatch (s , nil )
761
-
762
- // process function literals in init expressions before scope changes
763
- check .processDelayed (top )
764
-
765
- // declare all variables
766
- // (only at this point are the variable scopes (parents) set)
767
- scopePos := s .End () // see constant declarations
768
- for i , name := range s .Names {
769
- // see constant declarations
770
- check .declare (check .scope , name , lhs0 [i ], scopePos )
771
- }
772
-
773
- default :
774
- check .invalidAST (s .Pos (), "invalid token %s" , d .Tok )
808
+ break
775
809
}
810
+ }
776
811
777
- case * ast.TypeSpec :
778
- obj := NewTypeName (s .Name .Pos (), pkg , s .Name .Name , nil )
779
- // spec: "The scope of a type identifier declared inside a function
780
- // begins at the identifier in the TypeSpec and ends at the end of
781
- // the innermost containing block."
782
- scopePos := s .Name .Pos ()
783
- check .declare (check .scope , s .Name , obj , scopePos )
784
- // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
785
- obj .setColor (grey + color (check .push (obj )))
786
- check .typeDecl (obj , s .Type , nil , s .Assign .IsValid ())
787
- check .pop ().setColor (black )
788
- default :
789
- check .invalidAST (s .Pos (), "const, type, or var declaration expected" )
812
+ // process function literals in init expressions before scope changes
813
+ check .processDelayed (top )
814
+
815
+ // declare all variables
816
+ // (only at this point are the variable scopes (parents) set)
817
+ scopePos := d .spec .End () // see constant declarations
818
+ for i , name := range d .spec .Names {
819
+ // see constant declarations
820
+ check .declare (check .scope , name , lhs0 [i ], scopePos )
790
821
}
791
- }
792
822
793
- default :
794
- check .invalidAST (d .Pos (), "unknown ast.Decl node %T" , d )
795
- }
823
+ case typeDecl :
824
+ obj := NewTypeName (d .spec .Name .Pos (), pkg , d .spec .Name .Name , nil )
825
+ // spec: "The scope of a type identifier declared inside a function
826
+ // begins at the identifier in the TypeSpec and ends at the end of
827
+ // the innermost containing block."
828
+ scopePos := d .spec .Name .Pos ()
829
+ check .declare (check .scope , d .spec .Name , obj , scopePos )
830
+ // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
831
+ obj .setColor (grey + color (check .push (obj )))
832
+ check .typeDecl (obj , d .spec .Type , nil , d .spec .Assign .IsValid ())
833
+ check .pop ().setColor (black )
834
+ default :
835
+ check .invalidAST (d .node ().Pos (), "unknown ast.Decl node %T" , d .node ())
836
+ }
837
+ })
796
838
}
0 commit comments