// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.// Source: ../../cmd/compile/internal/types2/assignments.go// Copyright 2013 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// This file implements initialization and assignment checks.package typesimport (.)// assignment reports whether x can be assigned to a variable of type T,// if necessary by attempting to convert untyped values to the appropriate// type. context describes the context in which the assignment takes place.// Use T == nil to indicate assignment to an untyped blank identifier.// If the assignment check fails, x.mode is set to invalid.func ( *Checker) ( *operand, Type, string) { .singleValue()switch .mode {caseinvalid:return// error reported beforecasenilvalue:assert(isTypes2)// okcaseconstant_, variable, mapindex, value, commaok, commaerr:// okdefault:// we may get here because of other problems (go.dev/issue/39634, crash 12) // TODO(gri) do we need a new "generic" error code here? .errorf(, IncompatibleAssign, "cannot assign %s to %s in %s", , , ) .mode = invalidreturn }ifisUntyped(.typ) { := // spec: "If an untyped constant is assigned to a variable of interface // type or the blank identifier, the constant is first converted to type // bool, rune, int, float64, complex128 or string respectively, depending // on whether the value is a boolean, rune, integer, floating-point, // complex, or string constant."ifisTypes2 {if .isNil() {if == nil { .errorf(, UntypedNilUse, "use of untyped nil in %s", ) .mode = invalidreturn } } elseif == nil || isNonTypeParamInterface() { = Default(.typ) } } else { // go/typesif == nil || isNonTypeParamInterface() {if == nil && .typ == Typ[UntypedNil] { .errorf(, UntypedNilUse, "use of untyped nil in %s", ) .mode = invalidreturn } = Default(.typ) } } , , := .implicitTypeAndValue(, )if != 0 { := .sprintf("cannot use %s as %s value in %s", , , )switch {caseTruncatedFloat: += " (truncated)"caseNumericOverflow: += " (overflows)"default: = IncompatibleAssign } .error(, , ) .mode = invalidreturn }if != nil { .val = .updateExprVal(.expr, ) }if != .typ { .typ = .updateExprType(.expr, , false) } }// x.typ is typed// A generic (non-instantiated) function value cannot be assigned to a variable.if , := under(.typ).(*Signature); != nil && .TypeParams().Len() > 0 { .errorf(, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", , ) .mode = invalidreturn }// spec: "If a left-hand side is the blank identifier, any typed or // non-constant value except for the predeclared identifier nil may // be assigned to it."if == nil {return } := ""if , := .assignableTo(, , &); ! {if != "" { .errorf(, , "cannot use %s as %s value in %s: %s", , , , ) } else { .errorf(, , "cannot use %s as %s value in %s", , , ) } .mode = invalid }}func ( *Checker) ( *Const, *operand) {if .mode == invalid || !isValid(.typ) || !isValid(.typ) {if .typ == nil { .typ = Typ[Invalid] }return }// rhs must be a constantif .mode != constant_ { .errorf(, InvalidConstInit, "%s is not constant", )if .typ == nil { .typ = Typ[Invalid] }return }assert(isConstType(.typ))// If the lhs doesn't have a type yet, use the type of x.if .typ == nil { .typ = .typ } .assignment(, .typ, "constant declaration")if .mode == invalid {return } .val = .val}// initVar checks the initialization lhs = x in a variable declaration.// If lhs doesn't have a type yet, it is given the type of x,// or Typ[Invalid] in case of an error.// If the initialization check fails, x.mode is set to invalid.func ( *Checker) ( *Var, *operand, string) {if .mode == invalid || !isValid(.typ) || !isValid(.typ) {if .typ == nil { .typ = Typ[Invalid] } .mode = invalidreturn }// If lhs doesn't have a type yet, use the type of x.if .typ == nil { := .typifisUntyped() {// convert untyped types to default typesif == Typ[UntypedNil] { .errorf(, UntypedNilUse, "use of untyped nil in %s", ) .typ = Typ[Invalid] .mode = invalidreturn } = Default() } .typ = } .assignment(, .typ, )}// lhsVar checks a lhs variable in an assignment and returns its type.// lhsVar takes care of not counting a lhs identifier as a "use" of// that identifier. The result is nil if it is the blank identifier,// and Typ[Invalid] if it is an invalid lhs expression.func ( *Checker) ( ast.Expr) Type {// Determine if the lhs is a (possibly parenthesized) identifier. , := ast.Unparen().(*ast.Ident)// Don't evaluate lhs if it is the blank identifier.if != nil && .Name == "_" { .recordDef(, nil)returnnil }// If the lhs is an identifier denoting a variable v, this reference // is not a 'use' of v. Remember current value of v.used and restore // after evaluating the lhs via check.expr.var *Varvarboolif != nil {if := .lookup(.Name); != nil {// It's ok to mark non-local variables, but ignore variables // from other packages to avoid potential race conditions with // dot-imported variables.if , := .(*Var); != nil && .pkg == .pkg { = = .used } } }varoperand .expr(nil, &, )if != nil { .used = // restore v.used }if .mode == invalid || !isValid(.typ) {returnTyp[Invalid] }// spec: "Each left-hand side operand must be addressable, a map index // expression, or the blank identifier. Operands may be parenthesized."switch .mode {caseinvalid:returnTyp[Invalid]casevariable, mapindex:// okdefault:if , := .expr.(*ast.SelectorExpr); {varoperand .expr(nil, &, .X)if .mode == mapindex { .errorf(&, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(.expr))returnTyp[Invalid] } } .errorf(&, UnassignableOperand, "cannot assign to %s (neither addressable nor a map index expression)", .expr)returnTyp[Invalid] }return .typ}// assignVar checks the assignment lhs = rhs (if x == nil), or lhs = x (if x != nil).// If x != nil, it must be the evaluation of rhs (and rhs will be ignored).// If the assignment check fails and x != nil, x.mode is set to invalid.func ( *Checker) (, ast.Expr, *operand, string) { := .lhsVar() // nil if lhs is _if !isValid() {if != nil { .mode = invalid } else { .use() }return }if == nil {var *target// avoid calling ExprString if not neededif != nil {if , := under().(*Signature); { = newTarget(, ExprString()) } } = new(operand) .expr(, , ) }if == nil && == "assignment" { = "assignment to _ identifier" } .assignment(, , )}// operandTypes returns the list of types for the given operands.func operandTypes( []*operand) ( []Type) {for , := range { = append(, .typ) }return}// varTypes returns the list of types for the given variables.func varTypes( []*Var) ( []Type) {for , := range { = append(, .typ) }return}// typesSummary returns a string of the form "(t1, t2, ...)" where the// ti's are user-friendly string representations for the given types.// If variadic is set and the last type is a slice, its string is of// the form "...E" where E is the slice's element type.func ( *Checker) ( []Type, bool) string {var []stringfor , := range {varstringswitch {case == nil:fallthrough// should not happen but be cautiouscase !isValid(): = "unknown type"caseisUntyped():ifisNumeric() {// Do not imply a specific type requirement: // "have number, want float64" is better than // "have untyped int, want float64" or // "have int, want float64". = "number" } else {// If we don't have a number, omit the "untyped" qualifier // for compactness. = strings.Replace(.(*Basic).name, "untyped ", "", -1) }case && == len()-1: = .sprintf("...%s", .(*Slice).elem) }if == "" { = .sprintf("%s", ) } = append(, ) }return"(" + strings.Join(, ", ") + ")"}func measure( int, string) string {if != 1 { += "s" }returnfmt.Sprintf("%d %s", , )}func ( *Checker) ( []ast.Expr, , int) { := measure(, "variable") := measure(, "value") := [0]iflen() == 1 {if , := ast.Unparen().(*ast.CallExpr); != nil { .errorf(, WrongAssignCount, "assignment mismatch: %s but %s returns %s", , .Fun, )return } } .errorf(, WrongAssignCount, "assignment mismatch: %s but %s", , )}func ( *Checker) ( positioner, []*Var, []*operand) { , := len(), len() := "not enough"if > { = [] // report at first extra value = "too many" } elseif > 0 { = [-1] // report at last value } := .newError(WrongResultCount) .addf(, "%s return values", ) .addf(noposn, "have %s", .typesSummary(operandTypes(), false)) .addf(noposn, "want %s", .typesSummary(varTypes(), false)) .report()}// initVars type-checks assignments of initialization expressions orig_rhs// to variables lhs.// If returnStmt is non-nil, initVars type-checks the implicit assignment// of result expressions orig_rhs to function result parameters lhs.func ( *Checker) ( []*Var, []ast.Expr, ast.Stmt) { := "assignment"if != nil { = "return statement" } , := len(), len()// If l == 1 and the rhs is a single call, for a better // error message don't handle it as n:n mapping below. := falseif == 1 { _, = ast.Unparen([0]).(*ast.CallExpr) }// If we have a n:n mapping from lhs variable to rhs expression, // each value can be assigned to its corresponding variable.if == && ! {varoperandfor , := range { := .nameif != nil && == "" { = "result variable" } .expr(newTarget(.typ, ), &, []) .initVar(, &, ) }return }// If we don't have an n:n mapping, the rhs must be a single expression // resulting in 2 or more values; otherwise we have an assignment mismatch.if != 1 {// Only report a mismatch error if there are no other errors on the rhs.if .use(...) {if != nil { := .exprList() .returnError(, , ) } else { .assignError(, , ) } }// ensure that LHS variables have a typefor , := range {if .typ == nil { .typ = Typ[Invalid] } }return } , := .multiExpr([0], == 2 && == nil) = len()if == {for , := range { .initVar(, [], ) }// Only record comma-ok expression if both initializations succeeded // (go.dev/issue/59371).if && [0].mode != invalid && [1].mode != invalid { .recordCommaOkTypes([0], ) }return }// In all other cases we have an assignment mismatch. // Only report a mismatch error if there are no other errors on the rhs.if [0].mode != invalid {if != nil { .returnError(, , ) } else { .assignError(, , ) } }// ensure that LHS variables have a typefor , := range {if .typ == nil { .typ = Typ[Invalid] } }// orig_rhs[0] was already evaluated}// assignVars type-checks assignments of expressions orig_rhs to variables lhs.func ( *Checker) (, []ast.Expr) { , := len(), len()// If l == 1 and the rhs is a single call, for a better // error message don't handle it as n:n mapping below. := falseif == 1 { _, = ast.Unparen([0]).(*ast.CallExpr) }// If we have a n:n mapping from lhs variable to rhs expression, // each value can be assigned to its corresponding variable.if == && ! {for , := range { .assignVar(, [], nil, "assignment") }return }// If we don't have an n:n mapping, the rhs must be a single expression // resulting in 2 or more values; otherwise we have an assignment mismatch.if != 1 {// Only report a mismatch error if there are no other errors on the lhs or rhs. := .useLHS(...) := .use(...)if && { .assignError(, , ) }return } , := .multiExpr([0], == 2) = len()if == {for , := range { .assignVar(, nil, [], "assignment") }// Only record comma-ok expression if both assignments succeeded // (go.dev/issue/59371).if && [0].mode != invalid && [1].mode != invalid { .recordCommaOkTypes([0], ) }return }// In all other cases we have an assignment mismatch. // Only report a mismatch error if there are no other errors on the rhs.if [0].mode != invalid { .assignError(, , ) } .useLHS(...)// orig_rhs[0] was already evaluated}func ( *Checker) ( positioner, , []ast.Expr) { := len(.delayed) := .scope// collect lhs variables := make(map[string]bool, len()) := make([]*Var, len()) := make([]*Var, 0, len()) := falsefor , := range { , := .(*ast.Ident)if == nil { .useLHS()// TODO(gri) This is redundant with a go/parser error. Consider omitting in go/types? .errorf(, BadDecl, "non-name %s on left side of :=", ) = truecontinue } := .Nameif != "_" {if [] { .errorf(, RepeatedDecl, "%s repeated on left side of :=", ) = truecontinue } [] = true }// Use the correct obj if the ident is redeclared. The // variable's scope starts after the declaration; so we // must use Scope.Lookup here and call Scope.Insert // (via check.declare) later.if := .Lookup(); != nil { .recordUse(, )// redeclared object must be a variableif , := .(*Var); != nil { [] = } else { .errorf(, UnassignableOperand, "cannot assign to %s", ) = true }continue }// declare new variable := NewVar(.Pos(), .pkg, , nil) [] = if != "_" { = append(, ) } .recordDef(, ) }// create dummy variables where the lhs is invalidfor , := range {if == nil { [] = NewVar([].Pos(), .pkg, "_", nil) } } .initVars(, , nil)// process function literals in rhs expressions before scope changes .processDelayed()iflen() == 0 && ! { .softErrorf(, NoNewVar, "no new variables on left side of :=")return }// declare new variables // spec: "The scope of a constant or variable identifier declared inside // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl // for short variable declarations) and ends at the end of the innermost // containing block." := endPos([len()-1])for , := range { .declare(, nil, , ) // id = nil: recordDef already called }}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.