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  }