]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/version.go
go/types, types2: remove local version processing in favor of go/version
[gostls13.git] / src / cmd / compile / internal / types2 / 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 types2
6
7 import (
8         "cmd/compile/internal/syntax"
9         "fmt"
10         "go/version"
11         "internal/goversion"
12         "strings"
13 )
14
15 // A goVersion is a Go language version string of the form "go1.%d"
16 // where d is the minor version number. goVersion strings don't
17 // contain release numbers ("go1.20.1" is not a valid goVersion).
18 type goVersion string
19
20 // asGoVersion returns v as a goVersion (e.g., "go1.20.1" becomes "go1.20").
21 // If v is not a valid Go version, the result is the empty string.
22 func asGoVersion(v string) goVersion {
23         return goVersion(version.Lang(v))
24 }
25
26 // isValid reports whether v is a valid Go version.
27 func (v goVersion) isValid() bool {
28         return v != ""
29 }
30
31 // cmp returns -1, 0, or +1 depending on whether x < y, x == y, or x > y,
32 // interpreted as Go versions.
33 func (x goVersion) cmp(y goVersion) int {
34         return version.Compare(string(x), string(y))
35 }
36
37 var (
38         // Go versions that introduced language changes
39         go1_9  = asGoVersion("go1.9")
40         go1_13 = asGoVersion("go1.13")
41         go1_14 = asGoVersion("go1.14")
42         go1_17 = asGoVersion("go1.17")
43         go1_18 = asGoVersion("go1.18")
44         go1_20 = asGoVersion("go1.20")
45         go1_21 = asGoVersion("go1.21")
46
47         // current (deployed) Go version
48         go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version))
49 )
50
51 // langCompat reports an error if the representation of a numeric
52 // literal is not compatible with the current language version.
53 func (check *Checker) langCompat(lit *syntax.BasicLit) {
54         s := lit.Value
55         if len(s) <= 2 || check.allowVersion(check.pkg, lit, go1_13) {
56                 return
57         }
58         // len(s) > 2
59         if strings.Contains(s, "_") {
60                 check.versionErrorf(lit, go1_13, "underscores in numeric literals")
61                 return
62         }
63         if s[0] != '0' {
64                 return
65         }
66         radix := s[1]
67         if radix == 'b' || radix == 'B' {
68                 check.versionErrorf(lit, go1_13, "binary literals")
69                 return
70         }
71         if radix == 'o' || radix == 'O' {
72                 check.versionErrorf(lit, go1_13, "0o/0O-style octal literals")
73                 return
74         }
75         if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') {
76                 check.versionErrorf(lit, go1_13, "hexadecimal floating-point literals")
77         }
78 }
79
80 // allowVersion reports whether the given package is allowed to use version v.
81 func (check *Checker) allowVersion(pkg *Package, at poser, v goVersion) bool {
82         // We assume that imported packages have all been checked,
83         // so we only have to check for the local package.
84         if pkg != check.pkg {
85                 return true
86         }
87
88         // If no explicit file version is specified,
89         // fileVersion corresponds to the module version.
90         var fileVersion goVersion
91         if pos := at.Pos(); pos.IsKnown() {
92                 // We need version.Lang below because file versions
93                 // can be (unaltered) Config.GoVersion strings that
94                 // may contain dot-release information.
95                 fileVersion = asGoVersion(check.versions[base(pos)])
96         }
97         return !fileVersion.isValid() || fileVersion.cmp(v) >= 0
98 }
99
100 // verifyVersionf is like allowVersion but also accepts a format string and arguments
101 // which are used to report a version error if allowVersion returns false. It uses the
102 // current package.
103 func (check *Checker) verifyVersionf(at poser, v goVersion, format string, args ...interface{}) bool {
104         if !check.allowVersion(check.pkg, at, v) {
105                 check.versionErrorf(at, v, format, args...)
106                 return false
107         }
108         return true
109 }
110
111 // base finds the underlying PosBase of the source file containing pos,
112 // skipping over intermediate PosBase layers created by //line directives.
113 // The positions must be known.
114 func base(pos syntax.Pos) *syntax.PosBase {
115         assert(pos.IsKnown())
116         b := pos.Base()
117         for {
118                 bb := b.Pos().Base()
119                 if bb == nil || bb == b {
120                         break
121                 }
122                 b = bb
123         }
124         return b
125 }