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  

View as plain text