]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/version.go
go/types, cmd/compile/internal/types2: use per-file 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         "errors"
10         "strings"
11 )
12
13 // langCompat reports an error if the representation of a numeric
14 // literal is not compatible with the current language version.
15 func (check *Checker) langCompat(lit *syntax.BasicLit) {
16         s := lit.Value
17         if len(s) <= 2 || check.allowVersion(check.pkg, lit.Pos(), 1, 13) {
18                 return
19         }
20         // len(s) > 2
21         if strings.Contains(s, "_") {
22                 check.versionErrorf(lit, "go1.13", "underscores in numeric literals")
23                 return
24         }
25         if s[0] != '0' {
26                 return
27         }
28         radix := s[1]
29         if radix == 'b' || radix == 'B' {
30                 check.versionErrorf(lit, "go1.13", "binary literals")
31                 return
32         }
33         if radix == 'o' || radix == 'O' {
34                 check.versionErrorf(lit, "go1.13", "0o/0O-style octal literals")
35                 return
36         }
37         if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') {
38                 check.versionErrorf(lit, "go1.13", "hexadecimal floating-point literals")
39         }
40 }
41
42 // allowVersion reports whether the given package
43 // is allowed to use version major.minor.
44 func (check *Checker) allowVersion(pkg *Package, pos syntax.Pos, major, minor int) bool {
45         // We assume that imported packages have all been checked,
46         // so we only have to check for the local package.
47         if pkg != check.pkg {
48                 return true
49         }
50
51         // If the source file declares its Go version, use that to decide.
52         if check.posVers != nil {
53                 if v, ok := check.posVers[base(pos)]; ok && v.major >= 1 {
54                         return v.major > major || v.major == major && v.minor >= minor
55                 }
56         }
57
58         // Otherwise fall back to the version in the checker.
59         ma, mi := check.version.major, check.version.minor
60         return ma == 0 && mi == 0 || ma > major || ma == major && mi >= minor
61 }
62
63 // base finds the underlying PosBase of the source file containing pos,
64 // skipping over intermediate PosBase layers created by //line directives.
65 func base(pos syntax.Pos) *syntax.PosBase {
66         b := pos.Base()
67         for {
68                 bb := b.Pos().Base()
69                 if bb == nil || bb == b {
70                         break
71                 }
72                 b = bb
73         }
74         return b
75 }
76
77 type version struct {
78         major, minor int
79 }
80
81 var errVersionSyntax = errors.New("invalid Go version syntax")
82
83 // parseGoVersion parses a Go version string (such as "go1.12")
84 // and returns the version, or an error. If s is the empty
85 // string, the version is 0.0.
86 func parseGoVersion(s string) (v version, err error) {
87         if s == "" {
88                 return
89         }
90         if !strings.HasPrefix(s, "go") {
91                 return version{}, errVersionSyntax
92         }
93         s = s[len("go"):]
94         i := 0
95         for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
96                 if i >= 10 || i == 0 && s[i] == '0' {
97                         return version{}, errVersionSyntax
98                 }
99                 v.major = 10*v.major + int(s[i]) - '0'
100         }
101         if i > 0 && i == len(s) {
102                 return
103         }
104         if i == 0 || s[i] != '.' {
105                 return version{}, errVersionSyntax
106         }
107         s = s[i+1:]
108         if s == "0" {
109                 // We really should not accept "go1.0",
110                 // but we didn't reject it from the start
111                 // and there are now programs that use it.
112                 // So accept it.
113                 return
114         }
115         i = 0
116         for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
117                 if i >= 10 || i == 0 && s[i] == '0' {
118                         return version{}, errVersionSyntax
119                 }
120                 v.minor = 10*v.minor + int(s[i]) - '0'
121         }
122         if i > 0 && i == len(s) {
123                 return
124         }
125         return version{}, errVersionSyntax
126 }
127
128 func (v version) equal(u version) bool {
129         return v.major == u.major && v.minor == u.minor
130 }
131
132 func (v version) before(u version) bool {
133         return v.major < u.major || v.major == u.major && v.minor < u.minor
134 }
135
136 func (v version) after(u version) bool {
137         return v.major > u.major || v.major == u.major && v.minor > u.minor
138 }