]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/types/version.go
runtime: prevent send on closed channel in wakeableSleep
[gostls13.git] / src / go / types / version.go
1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package types
6
7 import (
8         "fmt"
9         "go/ast"
10         "go/token"
11         "strings"
12 )
13
14 // A version represents a released Go version.
15 type version struct {
16         major, minor int
17 }
18
19 func (v version) String() string {
20         return fmt.Sprintf("go%d.%d", v.major, v.minor)
21 }
22
23 func (v version) equal(u version) bool {
24         return v.major == u.major && v.minor == u.minor
25 }
26
27 func (v version) before(u version) bool {
28         return v.major < u.major || v.major == u.major && v.minor < u.minor
29 }
30
31 func (v version) after(u version) bool {
32         return v.major > u.major || v.major == u.major && v.minor > u.minor
33 }
34
35 // Go versions that introduced language changes.
36 var (
37         go0_0  = version{0, 0} // no version specified
38         go1_9  = version{1, 9}
39         go1_13 = version{1, 13}
40         go1_14 = version{1, 14}
41         go1_17 = version{1, 17}
42         go1_18 = version{1, 18}
43         go1_20 = version{1, 20}
44         go1_21 = version{1, 21}
45 )
46
47 // parseGoVersion parses a Go version string (such as "go1.12")
48 // and returns the version, or an error. If s is the empty
49 // string, the version is 0.0.
50 func parseGoVersion(s string) (v version, err error) {
51         bad := func() (version, error) {
52                 return version{}, fmt.Errorf("invalid Go version syntax %q", s)
53         }
54         if s == "" {
55                 return
56         }
57         if !strings.HasPrefix(s, "go") {
58                 return bad()
59         }
60         s = s[len("go"):]
61         i := 0
62         for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
63                 if i >= 10 || i == 0 && s[i] == '0' {
64                         return bad()
65                 }
66                 v.major = 10*v.major + int(s[i]) - '0'
67         }
68         if i > 0 && i == len(s) {
69                 return
70         }
71         if i == 0 || s[i] != '.' {
72                 return bad()
73         }
74         s = s[i+1:]
75         if s == "0" {
76                 // We really should not accept "go1.0",
77                 // but we didn't reject it from the start
78                 // and there are now programs that use it.
79                 // So accept it.
80                 return
81         }
82         i = 0
83         for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
84                 if i >= 10 || i == 0 && s[i] == '0' {
85                         return bad()
86                 }
87                 v.minor = 10*v.minor + int(s[i]) - '0'
88         }
89         // Accept any suffix after the minor number.
90         // We are only looking for the language version (major.minor)
91         // but want to accept any valid Go version, like go1.21.0
92         // and go1.21rc2.
93         return
94 }
95
96 // langCompat reports an error if the representation of a numeric
97 // literal is not compatible with the current language version.
98 func (check *Checker) langCompat(lit *ast.BasicLit) {
99         s := lit.Value
100         if len(s) <= 2 || check.allowVersion(check.pkg, lit, go1_13) {
101                 return
102         }
103         // len(s) > 2
104         if strings.Contains(s, "_") {
105                 check.versionErrorf(lit, go1_13, "underscores in numeric literals")
106                 return
107         }
108         if s[0] != '0' {
109                 return
110         }
111         radix := s[1]
112         if radix == 'b' || radix == 'B' {
113                 check.versionErrorf(lit, go1_13, "binary literals")
114                 return
115         }
116         if radix == 'o' || radix == 'O' {
117                 check.versionErrorf(lit, go1_13, "0o/0O-style octal literals")
118                 return
119         }
120         if lit.Kind != token.INT && (radix == 'x' || radix == 'X') {
121                 check.versionErrorf(lit, go1_13, "hexadecimal floating-point literals")
122         }
123 }
124
125 // allowVersion reports whether the given package
126 // is allowed to use version major.minor.
127 func (check *Checker) allowVersion(pkg *Package, at positioner, v version) bool {
128         // We assume that imported packages have all been checked,
129         // so we only have to check for the local package.
130         if pkg != check.pkg {
131                 return true
132         }
133
134         // If the source file declares its Go version and at references a valid
135         // position, use that to decide.
136         if pos := at.Pos(); pos.IsValid() && check.posVers != nil {
137                 fileStart := check.fset.File(pos).Pos(0)
138                 if src, ok := check.posVers[fileStart]; ok && src.major >= 1 {
139                         return !src.before(v)
140                 }
141         }
142
143         // Otherwise fall back to the version in the checker.
144         return check.version.equal(go0_0) || !check.version.before(v)
145 }
146
147 // verifyVersionf is like allowVersion but also accepts a format string and arguments
148 // which are used to report a version error if allowVersion returns false. It uses the
149 // current package.
150 func (check *Checker) verifyVersionf(at positioner, v version, format string, args ...interface{}) bool {
151         if !check.allowVersion(check.pkg, at, v) {
152                 check.versionErrorf(at, v, format, args...)
153                 return false
154         }
155         return true
156 }