Source file src/cmd/compile/internal/types2/version.go

     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 types2
     6  
     7  import (
     8  	"cmd/compile/internal/syntax"
     9  	"fmt"
    10  	"go/version"
    11  	"internal/goversion"
    12  )
    13  
    14  // A goVersion is a Go language version string of the form "go1.%d"
    15  // where d is the minor version number. goVersion strings don't
    16  // contain release numbers ("go1.20.1" is not a valid goVersion).
    17  type goVersion string
    18  
    19  // asGoVersion returns v as a goVersion (e.g., "go1.20.1" becomes "go1.20").
    20  // If v is not a valid Go version, the result is the empty string.
    21  func asGoVersion(v string) goVersion {
    22  	return goVersion(version.Lang(v))
    23  }
    24  
    25  // isValid reports whether v is a valid Go version.
    26  func (v goVersion) isValid() bool {
    27  	return v != ""
    28  }
    29  
    30  // cmp returns -1, 0, or +1 depending on whether x < y, x == y, or x > y,
    31  // interpreted as Go versions.
    32  func (x goVersion) cmp(y goVersion) int {
    33  	return version.Compare(string(x), string(y))
    34  }
    35  
    36  var (
    37  	// Go versions that introduced language changes
    38  	go1_9  = asGoVersion("go1.9")
    39  	go1_13 = asGoVersion("go1.13")
    40  	go1_14 = asGoVersion("go1.14")
    41  	go1_17 = asGoVersion("go1.17")
    42  	go1_18 = asGoVersion("go1.18")
    43  	go1_20 = asGoVersion("go1.20")
    44  	go1_21 = asGoVersion("go1.21")
    45  	go1_22 = asGoVersion("go1.22")
    46  	go1_23 = asGoVersion("go1.23")
    47  
    48  	// current (deployed) Go version
    49  	go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version))
    50  )
    51  
    52  // allowVersion reports whether the current package at the given position
    53  // is allowed to use version v. If the position is unknown, the specified
    54  // module version (Config.GoVersion) is used. If that version is invalid,
    55  // allowVersion returns true.
    56  func (check *Checker) allowVersion(at poser, v goVersion) bool {
    57  	fileVersion := check.conf.GoVersion
    58  	if pos := at.Pos(); pos.IsKnown() {
    59  		fileVersion = check.versions[base(pos)]
    60  	}
    61  
    62  	// We need asGoVersion (which calls version.Lang) below
    63  	// because fileVersion may be the (unaltered) Config.GoVersion
    64  	// string which may contain dot-release information.
    65  	version := asGoVersion(fileVersion)
    66  
    67  	return !version.isValid() || version.cmp(v) >= 0
    68  }
    69  
    70  // verifyVersionf is like allowVersion but also accepts a format string and arguments
    71  // which are used to report a version error if allowVersion returns false.
    72  func (check *Checker) verifyVersionf(at poser, v goVersion, format string, args ...interface{}) bool {
    73  	if !check.allowVersion(at, v) {
    74  		check.versionErrorf(at, v, format, args...)
    75  		return false
    76  	}
    77  	return true
    78  }
    79  
    80  // base finds the underlying PosBase of the source file containing pos,
    81  // skipping over intermediate PosBase layers created by //line directives.
    82  // The positions must be known.
    83  func base(pos syntax.Pos) *syntax.PosBase {
    84  	assert(pos.IsKnown())
    85  	b := pos.Base()
    86  	for {
    87  		bb := b.Pos().Base()
    88  		if bb == nil || bb == b {
    89  			break
    90  		}
    91  		b = bb
    92  	}
    93  	return b
    94  }
    95  

View as plain text