github.com/AndrienkoAleksandr/go@v0.0.19/src/go/build/constraint/vers.go (about) 1 // Copyright 2023 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 constraint 6 7 import ( 8 "strconv" 9 "strings" 10 ) 11 12 // GoVersion returns the minimum Go version implied by a given build expression. 13 // If the expression can be satisfied without any Go version tags, GoVersion returns an empty string. 14 // 15 // For example: 16 // 17 // GoVersion(linux && go1.22) = "go1.22" 18 // GoVersion((linux && go1.22) || (windows && go1.20)) = "go1.20" => go1.20 19 // GoVersion(linux) = "" 20 // GoVersion(linux || (windows && go1.22)) = "" 21 // GoVersion(!go1.22) = "" 22 // 23 // GoVersion assumes that any tag or negated tag may independently be true, 24 // so that its analysis can be purely structural, without SAT solving. 25 // “Impossible” subexpressions may therefore affect the result. 26 // 27 // For example: 28 // 29 // GoVersion((linux && !linux && go1.20) || go1.21) = "go1.20" 30 func GoVersion(x Expr) string { 31 v := minVersion(x, +1) 32 if v < 0 { 33 return "" 34 } 35 if v == 0 { 36 return "go1" 37 } 38 return "go1." + strconv.Itoa(v) 39 } 40 41 // minVersion returns the minimum Go major version (9 for go1.9) 42 // implied by expression z, or if sign < 0, by expression !z. 43 func minVersion(z Expr, sign int) int { 44 switch z := z.(type) { 45 default: 46 return -1 47 case *AndExpr: 48 op := andVersion 49 if sign < 0 { 50 op = orVersion 51 } 52 return op(minVersion(z.X, sign), minVersion(z.Y, sign)) 53 case *OrExpr: 54 op := orVersion 55 if sign < 0 { 56 op = andVersion 57 } 58 return op(minVersion(z.X, sign), minVersion(z.Y, sign)) 59 case *NotExpr: 60 return minVersion(z.X, -sign) 61 case *TagExpr: 62 if sign < 0 { 63 // !foo implies nothing 64 return -1 65 } 66 if z.Tag == "go1" { 67 return 0 68 } 69 _, v, _ := stringsCut(z.Tag, "go1.") 70 n, err := strconv.Atoi(v) 71 if err != nil { 72 // not a go1.N tag 73 return -1 74 } 75 return n 76 } 77 } 78 79 // TODO: Delete, replace calls with strings.Cut once Go bootstrap toolchain is bumped. 80 func stringsCut(s, sep string) (before, after string, found bool) { 81 if i := strings.Index(s, sep); i >= 0 { 82 return s[:i], s[i+len(sep):], true 83 } 84 return s, "", false 85 } 86 87 // andVersion returns the minimum Go version 88 // implied by the AND of two minimum Go versions, 89 // which is the max of the versions. 90 func andVersion(x, y int) int { 91 if x > y { 92 return x 93 } 94 return y 95 } 96 97 // orVersion returns the minimum Go version 98 // implied by the OR of two minimum Go versions, 99 // which is the min of the versions. 100 func orVersion(x, y int) int { 101 if x < y { 102 return x 103 } 104 return y 105 }