github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/go/types/version.go (about) 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 "errors" 9 "fmt" 10 "go/ast" 11 "go/token" 12 "strings" 13 ) 14 15 // A version represents a released Go version. 16 type version struct { 17 major, minor int 18 } 19 20 func (v version) String() string { 21 return fmt.Sprintf("go%d.%d", v.major, v.minor) 22 } 23 24 func (v version) equal(u version) bool { 25 return v.major == u.major && v.minor == u.minor 26 } 27 28 func (v version) before(u version) bool { 29 return v.major < u.major || v.major == u.major && v.minor < u.minor 30 } 31 32 func (v version) after(u version) bool { 33 return v.major > u.major || v.major == u.major && v.minor > u.minor 34 } 35 36 // Go versions that introduced language changes. 37 var ( 38 go0_0 = version{0, 0} // no version specified 39 go1_9 = version{1, 9} 40 go1_13 = version{1, 13} 41 go1_14 = version{1, 14} 42 go1_17 = version{1, 17} 43 go1_18 = version{1, 18} 44 go1_20 = version{1, 20} 45 go1_21 = version{1, 21} 46 ) 47 48 var errVersionSyntax = errors.New("invalid Go version syntax") 49 50 // parseGoVersion parses a Go version string (such as "go1.12") 51 // and returns the version, or an error. If s is the empty 52 // string, the version is 0.0. 53 func parseGoVersion(s string) (v version, err error) { 54 if s == "" { 55 return 56 } 57 if !strings.HasPrefix(s, "go") { 58 return version{}, errVersionSyntax 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 version{}, errVersionSyntax 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 version{}, errVersionSyntax 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 version{}, errVersionSyntax 86 } 87 v.minor = 10*v.minor + int(s[i]) - '0' 88 } 89 if i > 0 && i == len(s) { 90 return 91 } 92 return version{}, errVersionSyntax 93 } 94 95 // langCompat reports an error if the representation of a numeric 96 // literal is not compatible with the current language version. 97 func (check *Checker) langCompat(lit *ast.BasicLit) { 98 s := lit.Value 99 if len(s) <= 2 || check.allowVersion(check.pkg, lit, go1_13) { 100 return 101 } 102 // len(s) > 2 103 if strings.Contains(s, "_") { 104 check.versionErrorf(lit, go1_13, "underscores in numeric literals") 105 return 106 } 107 if s[0] != '0' { 108 return 109 } 110 radix := s[1] 111 if radix == 'b' || radix == 'B' { 112 check.versionErrorf(lit, go1_13, "binary literals") 113 return 114 } 115 if radix == 'o' || radix == 'O' { 116 check.versionErrorf(lit, go1_13, "0o/0O-style octal literals") 117 return 118 } 119 if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { 120 check.versionErrorf(lit, go1_13, "hexadecimal floating-point literals") 121 } 122 } 123 124 // allowVersion reports whether the given package 125 // is allowed to use version major.minor. 126 func (check *Checker) allowVersion(pkg *Package, at positioner, v version) bool { 127 // We assume that imported packages have all been checked, 128 // so we only have to check for the local package. 129 if pkg != check.pkg { 130 return true 131 } 132 133 // If the source file declares its Go version, use that to decide. 134 if check.posVers != nil { 135 if src, ok := check.posVers[check.fset.File(at.Pos())]; ok && src.major >= 1 { 136 return !src.before(v) 137 } 138 } 139 140 // Otherwise fall back to the version in the checker. 141 return check.version.equal(go0_0) || !check.version.before(v) 142 } 143 144 // verifyVersionf is like allowVersion but also accepts a format string and arguments 145 // which are used to report a version error if allowVersion returns false. 146 func (check *Checker) verifyVersionf(pkg *Package, at positioner, v version, format string, args ...interface{}) bool { 147 if !check.allowVersion(pkg, at, v) { 148 check.versionErrorf(at, v, format, args...) 149 return false 150 } 151 return true 152 }