Source file src/go/build/constraint/vers.go
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, ok := strings.Cut(z.Tag, "go1.") 70 if !ok { 71 return -1 72 } 73 n, err := strconv.Atoi(v) 74 if err != nil { 75 // not a go1.N tag 76 return -1 77 } 78 return n 79 } 80 } 81 82 // andVersion returns the minimum Go version 83 // implied by the AND of two minimum Go versions, 84 // which is the max of the versions. 85 func andVersion(x, y int) int { 86 if x > y { 87 return x 88 } 89 return y 90 } 91 92 // orVersion returns the minimum Go version 93 // implied by the OR of two minimum Go versions, 94 // which is the min of the versions. 95 func orVersion(x, y int) int { 96 if x < y { 97 return x 98 } 99 return y 100 } 101