// Copyright 2012 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 defines operands and associated operations.package typesimport ()// An operandMode specifies the (addressing) mode of an operand.typeoperandModebyteconst (invalidoperandMode = iota// operand is invalidnovalue// operand represents no value (result of a function call w/o result)builtin// operand is a built-in functiontypexpr// operand is a typeconstant_// operand is a constant; the operand's typ is a Basic typevariable// operand is an addressable variablemapindex// operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)value// operand is a computed valuecommaok// like value, but operand may be used in a comma,ok expressioncommaerr// like commaok, but second value is error, not booleancgofunc// operand is a cgo function)varoperandModeString = [...]string{invalid: "invalid operand",novalue: "no value",builtin: "built-in",typexpr: "type",constant_: "constant",variable: "variable",mapindex: "map index expression",value: "value",commaok: "comma, ok expression",commaerr: "comma, error expression",cgofunc: "cgo function",}// An operand represents an intermediate value during type checking.// Operands have an (addressing) mode, the expression evaluating to// the operand, the operand's type, a value for constants, and an id// for built-in functions.// The zero value of operand is a ready to use invalid operand.//typeoperandstruct {modeoperandModeexprast.ExprtypTypevalconstant.ValueidbuiltinId}// Pos returns the position of the expression corresponding to x.// If x is invalid the position is token.NoPos.//func ( *operand) () token.Pos {// x.expr may not be set if x is invalidif .expr == nil {returntoken.NoPos }return .expr.Pos()}// Operand string formats// (not all "untyped" cases can appear due to the type system,// but they fall out naturally here)//// mode format//// invalid <expr> ( <mode> )// novalue <expr> ( <mode> )// builtin <expr> ( <mode> )// typexpr <expr> ( <mode> )//// constant <expr> (<untyped kind> <mode> )// constant <expr> ( <mode> of type <typ>)// constant <expr> (<untyped kind> <mode> <val> )// constant <expr> ( <mode> <val> of type <typ>)//// variable <expr> (<untyped kind> <mode> )// variable <expr> ( <mode> of type <typ>)//// mapindex <expr> (<untyped kind> <mode> )// mapindex <expr> ( <mode> of type <typ>)//// value <expr> (<untyped kind> <mode> )// value <expr> ( <mode> of type <typ>)//// commaok <expr> (<untyped kind> <mode> )// commaok <expr> ( <mode> of type <typ>)//// commaerr <expr> (<untyped kind> <mode> )// commaerr <expr> ( <mode> of type <typ>)//// cgofunc <expr> (<untyped kind> <mode> )// cgofunc <expr> ( <mode> of type <typ>)//func ( *operand, Qualifier) string {// special-case nilif .mode == value && .typ == Typ[UntypedNil] {return"nil" }varbytes.Buffervarstringif .expr != nil { = ExprString(.expr) } else {switch .mode {casebuiltin: = predeclaredFuncs[.id].namecasetypexpr: = TypeString(.typ, )caseconstant_: = .val.String() } }// <expr> (if != "" { .WriteString() .WriteString(" (") }// <untyped kind> := falseswitch .mode {caseinvalid, novalue, builtin, typexpr:// no typedefault:// should have a type, but be cautious (don't crash during printing)if .typ != nil {ifisUntyped(.typ) { .WriteString(.typ.(*Basic).name) .WriteByte(' ')break } = true } }// <mode> .WriteString(operandModeString[.mode])// <val>if .mode == constant_ {if := .val.String(); != { .WriteByte(' ') .WriteString() } }// <typ>if {if .typ != Typ[Invalid] {varstringifisGeneric(.typ) { = " of parameterized type " } else { = " of type " } .WriteString()WriteType(&, .typ, )if , := .typ.(*TypeParam); != nil { .WriteString(" constrained by ")WriteType(&, .bound, ) // do not compute interface type sets here } } else { .WriteString(" with invalid type") } }// )if != "" { .WriteByte(')') }return .String()}func ( *operand) () string {returnoperandString(, nil)}// setConst sets x to the untyped constant for literal lit.func ( *operand) ( token.Token, string) {varBasicKindswitch {casetoken.INT: = UntypedIntcasetoken.FLOAT: = UntypedFloatcasetoken.IMAG: = UntypedComplexcasetoken.CHAR: = UntypedRunecasetoken.STRING: = UntypedStringdefault:unreachable() } := constant.MakeFromLiteral(, , 0)if .Kind() == constant.Unknown { .mode = invalid .typ = Typ[Invalid]return } .mode = constant_ .typ = Typ[] .val = }// isNil reports whether x is the nil value.func ( *operand) () bool {return .mode == value && .typ == Typ[UntypedNil]}// assignableTo reports whether x is assignable to a variable of type T. If the// result is false and a non-nil reason is provided, it may be set to a more// detailed explanation of the failure (result != ""). The returned error code// is only valid if the (first) result is false. The check parameter may be nil// if assignableTo is invoked through an exported API call, i.e., when all// methods have been type-checked.func ( *operand) ( *Checker, Type, *string) (bool, errorCode) {if .mode == invalid || == Typ[Invalid] {returntrue, 0// avoid spurious errors } := .typ// x's type is identical to TifIdentical(, ) {returntrue, 0 } := under() := under() , := .(*TypeParam) , := .(*TypeParam)// x is an untyped value representable by a value of type T.ifisUntyped() {assert( == nil)if != nil {// T is a type parameter: x is assignable to T if it is // representable by each specific type in the type set of T.return .is(func( *term) bool {if == nil {returnfalse }// A term may be a tilde term but the underlying // type of an untyped value doesn't change so we // don't need to do anything special. , , := .implicitTypeAndValue(, .typ)return != nil }), _IncompatibleAssign } , , := .implicitTypeAndValue(, )return != nil, _IncompatibleAssign }// Vu is typed// x's type V and T have identical underlying types // and at least one of V or T is not a named type // and neither V nor T is a type parameter.ifIdentical(, ) && (!hasName() || !hasName()) && == nil && == nil {returntrue, 0 }// T is an interface type and x implements T and T is not a type parameter. // Also handle the case where T is a pointer to an interface.if , := .(*Interface); && == nil || isInterfacePtr() {if := .implements(, ); != nil {if != nil { * = .Error() }returnfalse, _InvalidIfaceAssign }returntrue, 0 }// If V is an interface, check if a missing type assertion is the problem.if , := .(*Interface); != nil && == nil {if .implements(, ) == nil {// T implements V, so give hint about type assertion.if != nil { * = "need type assertion" }returnfalse, _IncompatibleAssign } }// x is a bidirectional channel value, T is a channel // type, x's type V and T have identical element types, // and at least one of V or T is not a named type.if , := .(*Chan); && .dir == SendRecv {if , := .(*Chan); && Identical(.elem, .elem) {return !hasName() || !hasName(), _InvalidChanAssign } }// optimization: if we don't have type parameters, we're doneif == nil && == nil {returnfalse, _IncompatibleAssign } := func( string, ...any) {if != nil && != nil { := .sprintf(, ...)if * != "" { += "\n\t" + * } * = } }// x's type V is not a named type and T is a type parameter, and // x is assignable to each specific type in T's type set.if !hasName() && != nil { := false := _IncompatibleAssign .is(func( *term) bool {if == nil {returnfalse// no specific types } , = .(, .typ, )if ! { ("cannot assign %s to %s (in %s)", .typ, .typ, )returnfalse }returntrue })return , }// x's type V is a type parameter and T is not a named type, // and values x' of each specific type in V's type set are // assignable to T.if != nil && !hasName() { := * // don't clobber outer x := false := _IncompatibleAssign .is(func( *term) bool {if == nil {returnfalse// no specific types } .typ = .typ , = .(, , )if ! { ("cannot assign %s (in %s) to %s", .typ, , )returnfalse }returntrue })return , }returnfalse, _IncompatibleAssign}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)