5656// - a type defined in the runtime package, without the 'runtime.' prefix
5757// - anytype to match all possible types
5858// - an expression of the form T1|T2 where both T1 and T2 can be arbitrary type expressions
59+ //
60+ // GO VERSION RESTRICTIONS
61+ //
62+ // A rtype comment of this form:
63+ //
64+ // // +rtype go1.24 ...
65+ //
66+ // Will only be applied to versions of Go following version 1.24.0
5967
6068package main
6169
@@ -70,6 +78,7 @@ import (
7078 "log"
7179 "os"
7280 "path/filepath"
81+ "runtime"
7382 "sort"
7483 "strconv"
7584 "strings"
@@ -78,6 +87,7 @@ import (
7887)
7988
8089const magicCommentPrefix = "+rtype"
90+ const gover = "go1."
8191
8292var fset = & token.FileSet {}
8393var checkVarTypeRules = []* checkVarType {}
@@ -97,6 +107,7 @@ type rtypeCmnt struct {
97107type checkVarType struct {
98108 V , T string // V must have type T
99109 pos token.Pos
110+ firstMinor
100111}
101112
102113func (c * checkVarType ) String () string {
@@ -111,6 +122,7 @@ type checkFieldType struct {
111122 S , F , T string // S.F must have type T
112123 opt bool
113124 pos token.Pos
125+ firstMinor
114126}
115127
116128func (c * checkFieldType ) String () string {
@@ -122,6 +134,13 @@ type checkConstVal struct {
122134 C string // const C = V
123135 V constant.Value
124136 pos token.Pos
137+ firstMinor
138+ }
139+
140+ type firstMinor int
141+
142+ func (firstMinor firstMinor ) versionOk (curminor int ) bool {
143+ return curminor >= int (firstMinor )
125144}
126145
127146func (c * checkConstVal ) String () string {
@@ -255,31 +274,38 @@ func process(pkg *packages.Package, rtcmnt *rtypeCmnt, cmntmap ast.CommentMap, r
255274 tinfo := pkg .TypesInfo
256275 fields := strings .Split (rtcmnt .txt , " " )
257276
277+ firstMinor := 0
278+
279+ if strings .HasPrefix (fields [1 ], gover ) {
280+ firstMinor , _ = strconv .Atoi (fields [1 ][len (gover ):])
281+ fields = fields [1 :]
282+ }
283+
258284 switch fields [1 ] {
259285 case "-var" :
260286 // -var V T
261287 // requests that variable V is of type T
262- addCheckVarType (fields [2 ], fields [3 ], rtcmnt .slash )
288+ addCheckVarType (fields [2 ], fields [3 ], rtcmnt .slash , firstMinor )
263289 case "-field" :
264290 // -field S.F T
265291 // requests that field F of type S is of type T
266292 v := strings .Split (fields [2 ], "." )
267- addCheckFieldType (v [0 ], v [1 ], fields [3 ], false , rtcmnt .slash )
293+ addCheckFieldType (v [0 ], v [1 ], fields [3 ], false , rtcmnt .slash , firstMinor )
268294 default :
269295 ok := false
270296 if ident := isProcVariableDecl (rtcmnt .stmt , tinfo ); ident != nil {
271297 if len (fields ) == 2 {
272- processProcVariableUses (rtcmnt .toplevel , tinfo , ident , cmntmap , rtcmnts , fields [1 ])
298+ processProcVariableUses (rtcmnt .toplevel , tinfo , ident , cmntmap , rtcmnts , fields [1 ], firstMinor )
273299 ok = true
274300 } else if len (fields ) == 3 && fields [1 ] == "-opt" {
275- processProcVariableUses (rtcmnt .toplevel , tinfo , ident , cmntmap , rtcmnts , fields [2 ])
301+ processProcVariableUses (rtcmnt .toplevel , tinfo , ident , cmntmap , rtcmnts , fields [2 ], firstMinor )
276302 ok = true
277303 }
278304 } else if ident := isConstDecl (rtcmnt .toplevel , rtcmnt .node ); len (fields ) == 2 && ident != nil {
279- addCheckConstVal (fields [1 ], constValue (tinfo .Defs [ident ]), rtcmnt .slash )
305+ addCheckConstVal (fields [1 ], constValue (tinfo .Defs [ident ]), rtcmnt .slash , firstMinor )
280306 ok = true
281307 } else if F := isStringCaseClause (rtcmnt .stmt ); F != "" && len (fields ) == 4 && fields [1 ] == "-fieldof" {
282- addCheckFieldType (fields [2 ], F , fields [3 ], false , rtcmnt .slash )
308+ addCheckFieldType (fields [2 ], F , fields [3 ], false , rtcmnt .slash , firstMinor )
283309 ok = true
284310 }
285311 if ! ok {
@@ -359,7 +385,7 @@ func isStringCaseClause(stmt ast.Stmt) string {
359385// processProcVariableUses scans the body of the function declaration 'decl'
360386// looking for uses of 'procVarIdent' which is assumed to be an identifier
361387// for a *proc.Variable variable.
362- func processProcVariableUses (decl ast.Node , tinfo * types.Info , procVarIdent * ast.Ident , cmntmap ast.CommentMap , rtcmnts []* rtypeCmnt , S string ) {
388+ func processProcVariableUses (decl ast.Node , tinfo * types.Info , procVarIdent * ast.Ident , cmntmap ast.CommentMap , rtcmnts []* rtypeCmnt , S string , firstMinor int ) {
363389 if len (S ) > 0 && S [0 ] == '*' {
364390 S = S [1 :]
365391 }
@@ -435,7 +461,7 @@ func processProcVariableUses(decl ast.Node, tinfo *types.Info, procVarIdent *ast
435461 }
436462 }
437463 F , _ := strconv .Unquote (arg0 .Value )
438- addCheckFieldType (S , F , typ , opt , fncall .Pos ())
464+ addCheckFieldType (S , F , typ , opt , fncall .Pos (), firstMinor )
439465 //printNode(fset, fncall)
440466 default :
441467 pos := fset .Position (n .Pos ())
@@ -454,18 +480,18 @@ func findComment(slash token.Pos, rtcmnts []*rtypeCmnt) int {
454480 return - 1
455481}
456482
457- func addCheckVarType (V , T string , pos token.Pos ) {
458- checkVarTypeRules = append (checkVarTypeRules , & checkVarType {V , T , pos })
483+ func addCheckVarType (V , T string , pos token.Pos , firstMinor_ int ) {
484+ checkVarTypeRules = append (checkVarTypeRules , & checkVarType {V , T , pos , firstMinor ( firstMinor_ ) })
459485}
460486
461- func addCheckFieldType (S , F , T string , opt bool , pos token.Pos ) {
487+ func addCheckFieldType (S , F , T string , opt bool , pos token.Pos , firstMinor_ int ) {
462488 if ! strings .Contains (S , "|" ) {
463- checkFieldTypeRules [S ] = append (checkFieldTypeRules [S ], & checkFieldType {S , F , T , opt , pos })
489+ checkFieldTypeRules [S ] = append (checkFieldTypeRules [S ], & checkFieldType {S , F , T , opt , pos , firstMinor ( firstMinor_ ) })
464490 }
465491}
466492
467- func addCheckConstVal (C string , V constant.Value , pos token.Pos ) {
468- checkConstValRules [C ] = append (checkConstValRules [C ], & checkConstVal {C , V , pos })
493+ func addCheckConstVal (C string , V constant.Value , pos token.Pos , firstMinor_ int ) {
494+ checkConstValRules [C ] = append (checkConstValRules [C ], & checkConstVal {C , V , pos , firstMinor ( firstMinor_ ) })
469495}
470496
471497// report writes a report of all rules derived from the proc package to stdout.
@@ -548,7 +574,7 @@ func check() {
548574 pkgmap := map [string ]* packages.Package {}
549575 allok := true
550576
551- for _ , rule := range checkVarTypeRules {
577+ for _ , rule := range versionOkFilter ( checkVarTypeRules ) {
552578 pos := fset .Position (rule .pos )
553579 def := lookupPackage (pkgmap , "runtime" ).Types .Scope ().Lookup (rule .V )
554580 if def == nil {
@@ -569,7 +595,10 @@ func check() {
569595 }
570596 sort .Strings (Ss )
571597 for _ , S := range Ss {
572- rules := checkFieldTypeRules [S ]
598+ rules := versionOkFilter (checkFieldTypeRules [S ])
599+ if len (rules ) == 0 {
600+ continue
601+ }
573602 pos := fset .Position (rules [0 ].pos )
574603
575604 def := lookupTypeDef (pkgmap , S )
@@ -617,7 +646,10 @@ func check() {
617646 }
618647 sort .Strings (Cs )
619648 for _ , C := range Cs {
620- rules := checkConstValRules [C ]
649+ rules := versionOkFilter (checkConstValRules [C ])
650+ if len (rules ) == 0 {
651+ continue
652+ }
621653 pos := fset .Position (rules [0 ].pos )
622654 def := findConst (pkgmap , C )
623655 if def == nil {
@@ -716,3 +748,14 @@ func relative(s string) string {
716748 }
717749 return r
718750}
751+
752+ func versionOkFilter [T interface { versionOk (int ) bool }](rules []T ) []T {
753+ curminor , _ := strconv .Atoi (strings .Split (runtime .Version ()[len (gover ):], "." )[0 ])
754+ r := []T {}
755+ for _ , rule := range rules {
756+ if rule .versionOk (curminor ) {
757+ rules = append (rules , rule )
758+ }
759+ }
760+ return r
761+ }
0 commit comments