...

Source file src/go/types/operand.go

Documentation: go/types

     1  // Copyright 2012 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  // This file defines operands and associated operations.
     6  
     7  package types
     8  
     9  import (
    10  	"bytes"
    11  	"go/ast"
    12  	"go/constant"
    13  	"go/token"
    14  )
    15  
    16  // An operandMode specifies the (addressing) mode of an operand.
    17  type operandMode byte
    18  
    19  const (
    20  	invalid   operandMode = iota // operand is invalid
    21  	novalue                      // operand represents no value (result of a function call w/o result)
    22  	builtin                      // operand is a built-in function
    23  	typexpr                      // operand is a type
    24  	constant_                    // operand is a constant; the operand's typ is a Basic type
    25  	variable                     // operand is an addressable variable
    26  	mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
    27  	value                        // operand is a computed value
    28  	commaok                      // like value, but operand may be used in a comma,ok expression
    29  	commaerr                     // like commaok, but second value is error, not boolean
    30  	cgofunc                      // operand is a cgo function
    31  )
    32  
    33  var operandModeString = [...]string{
    34  	invalid:   "invalid operand",
    35  	novalue:   "no value",
    36  	builtin:   "built-in",
    37  	typexpr:   "type",
    38  	constant_: "constant",
    39  	variable:  "variable",
    40  	mapindex:  "map index expression",
    41  	value:     "value",
    42  	commaok:   "comma, ok expression",
    43  	commaerr:  "comma, error expression",
    44  	cgofunc:   "cgo function",
    45  }
    46  
    47  // An operand represents an intermediate value during type checking.
    48  // Operands have an (addressing) mode, the expression evaluating to
    49  // the operand, the operand's type, a value for constants, and an id
    50  // for built-in functions.
    51  // The zero value of operand is a ready to use invalid operand.
    52  type operand struct {
    53  	mode operandMode
    54  	expr ast.Expr
    55  	typ  Type
    56  	val  constant.Value
    57  	id   builtinId
    58  }
    59  
    60  // Pos returns the position of the expression corresponding to x.
    61  // If x is invalid the position is token.NoPos.
    62  func (x *operand) Pos() token.Pos {
    63  	// x.expr may not be set if x is invalid
    64  	if x.expr == nil {
    65  		return token.NoPos
    66  	}
    67  	return x.expr.Pos()
    68  }
    69  
    70  // Operand string formats
    71  // (not all "untyped" cases can appear due to the type system,
    72  // but they fall out naturally here)
    73  //
    74  // mode       format
    75  //
    76  // invalid    <expr> (               <mode>                    )
    77  // novalue    <expr> (               <mode>                    )
    78  // builtin    <expr> (               <mode>                    )
    79  // typexpr    <expr> (               <mode>                    )
    80  //
    81  // constant   <expr> (<untyped kind> <mode>                    )
    82  // constant   <expr> (               <mode>       of type <typ>)
    83  // constant   <expr> (<untyped kind> <mode> <val>              )
    84  // constant   <expr> (               <mode> <val> of type <typ>)
    85  //
    86  // variable   <expr> (<untyped kind> <mode>                    )
    87  // variable   <expr> (               <mode>       of type <typ>)
    88  //
    89  // mapindex   <expr> (<untyped kind> <mode>                    )
    90  // mapindex   <expr> (               <mode>       of type <typ>)
    91  //
    92  // value      <expr> (<untyped kind> <mode>                    )
    93  // value      <expr> (               <mode>       of type <typ>)
    94  //
    95  // commaok    <expr> (<untyped kind> <mode>                    )
    96  // commaok    <expr> (               <mode>       of type <typ>)
    97  //
    98  // commaerr   <expr> (<untyped kind> <mode>                    )
    99  // commaerr   <expr> (               <mode>       of type <typ>)
   100  //
   101  // cgofunc    <expr> (<untyped kind> <mode>                    )
   102  // cgofunc    <expr> (               <mode>       of type <typ>)
   103  func operandString(x *operand, qf Qualifier) string {
   104  	// special-case nil
   105  	if x.mode == value && x.typ == Typ[UntypedNil] {
   106  		return "nil"
   107  	}
   108  
   109  	var buf bytes.Buffer
   110  
   111  	var expr string
   112  	if x.expr != nil {
   113  		expr = ExprString(x.expr)
   114  	} else {
   115  		switch x.mode {
   116  		case builtin:
   117  			expr = predeclaredFuncs[x.id].name
   118  		case typexpr:
   119  			expr = TypeString(x.typ, qf)
   120  		case constant_:
   121  			expr = x.val.String()
   122  		}
   123  	}
   124  
   125  	// <expr> (
   126  	if expr != "" {
   127  		buf.WriteString(expr)
   128  		buf.WriteString(" (")
   129  	}
   130  
   131  	// <untyped kind>
   132  	hasType := false
   133  	switch x.mode {
   134  	case invalid, novalue, builtin, typexpr:
   135  		// no type
   136  	default:
   137  		// should have a type, but be cautious (don't crash during printing)
   138  		if x.typ != nil {
   139  			if isUntyped(x.typ) {
   140  				buf.WriteString(x.typ.(*Basic).name)
   141  				buf.WriteByte(' ')
   142  				break
   143  			}
   144  			hasType = true
   145  		}
   146  	}
   147  
   148  	// <mode>
   149  	buf.WriteString(operandModeString[x.mode])
   150  
   151  	// <val>
   152  	if x.mode == constant_ {
   153  		if s := x.val.String(); s != expr {
   154  			buf.WriteByte(' ')
   155  			buf.WriteString(s)
   156  		}
   157  	}
   158  
   159  	// <typ>
   160  	if hasType {
   161  		if x.typ != Typ[Invalid] {
   162  			var intro string
   163  			if isGeneric(x.typ) {
   164  				intro = " of parameterized type "
   165  			} else {
   166  				intro = " of type "
   167  			}
   168  			buf.WriteString(intro)
   169  			WriteType(&buf, x.typ, qf)
   170  			if tpar, _ := x.typ.(*TypeParam); tpar != nil {
   171  				buf.WriteString(" constrained by ")
   172  				WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
   173  			}
   174  		} else {
   175  			buf.WriteString(" with invalid type")
   176  		}
   177  	}
   178  
   179  	// )
   180  	if expr != "" {
   181  		buf.WriteByte(')')
   182  	}
   183  
   184  	return buf.String()
   185  }
   186  
   187  func (x *operand) String() string {
   188  	return operandString(x, nil)
   189  }
   190  
   191  // setConst sets x to the untyped constant for literal lit.
   192  func (x *operand) setConst(tok token.Token, lit string) {
   193  	var kind BasicKind
   194  	switch tok {
   195  	case token.INT:
   196  		kind = UntypedInt
   197  	case token.FLOAT:
   198  		kind = UntypedFloat
   199  	case token.IMAG:
   200  		kind = UntypedComplex
   201  	case token.CHAR:
   202  		kind = UntypedRune
   203  	case token.STRING:
   204  		kind = UntypedString
   205  	default:
   206  		unreachable()
   207  	}
   208  
   209  	val := constant.MakeFromLiteral(lit, tok, 0)
   210  	if val.Kind() == constant.Unknown {
   211  		x.mode = invalid
   212  		x.typ = Typ[Invalid]
   213  		return
   214  	}
   215  	x.mode = constant_
   216  	x.typ = Typ[kind]
   217  	x.val = val
   218  }
   219  
   220  // isNil reports whether x is the nil value.
   221  func (x *operand) isNil() bool {
   222  	return x.mode == value && x.typ == Typ[UntypedNil]
   223  }
   224  
   225  // assignableTo reports whether x is assignable to a variable of type T. If the
   226  // result is false and a non-nil reason is provided, it may be set to a more
   227  // detailed explanation of the failure (result != ""). The returned error code
   228  // is only valid if the (first) result is false. The check parameter may be nil
   229  // if assignableTo is invoked through an exported API call, i.e., when all
   230  // methods have been type-checked.
   231  func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
   232  	if x.mode == invalid || T == Typ[Invalid] {
   233  		return true, 0 // avoid spurious errors
   234  	}
   235  
   236  	V := x.typ
   237  
   238  	// x's type is identical to T
   239  	if Identical(V, T) {
   240  		return true, 0
   241  	}
   242  
   243  	Vu := under(V)
   244  	Tu := under(T)
   245  	Vp, _ := V.(*TypeParam)
   246  	Tp, _ := T.(*TypeParam)
   247  
   248  	// x is an untyped value representable by a value of type T.
   249  	if isUntyped(Vu) {
   250  		assert(Vp == nil)
   251  		if Tp != nil {
   252  			// T is a type parameter: x is assignable to T if it is
   253  			// representable by each specific type in the type set of T.
   254  			return Tp.is(func(t *term) bool {
   255  				if t == nil {
   256  					return false
   257  				}
   258  				// A term may be a tilde term but the underlying
   259  				// type of an untyped value doesn't change so we
   260  				// don't need to do anything special.
   261  				newType, _, _ := check.implicitTypeAndValue(x, t.typ)
   262  				return newType != nil
   263  			}), _IncompatibleAssign
   264  		}
   265  		newType, _, _ := check.implicitTypeAndValue(x, T)
   266  		return newType != nil, _IncompatibleAssign
   267  	}
   268  	// Vu is typed
   269  
   270  	// x's type V and T have identical underlying types
   271  	// and at least one of V or T is not a named type
   272  	// and neither V nor T is a type parameter.
   273  	if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) && Vp == nil && Tp == nil {
   274  		return true, 0
   275  	}
   276  
   277  	// T is an interface type and x implements T and T is not a type parameter.
   278  	// Also handle the case where T is a pointer to an interface.
   279  	if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
   280  		if err := check.implements(V, T); err != nil {
   281  			if reason != nil {
   282  				*reason = err.Error()
   283  			}
   284  			return false, _InvalidIfaceAssign
   285  		}
   286  		return true, 0
   287  	}
   288  
   289  	// If V is an interface, check if a missing type assertion is the problem.
   290  	if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
   291  		if check.implements(T, V) == nil {
   292  			// T implements V, so give hint about type assertion.
   293  			if reason != nil {
   294  				*reason = "need type assertion"
   295  			}
   296  			return false, _IncompatibleAssign
   297  		}
   298  	}
   299  
   300  	// x is a bidirectional channel value, T is a channel
   301  	// type, x's type V and T have identical element types,
   302  	// and at least one of V or T is not a named type.
   303  	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
   304  		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
   305  			return !hasName(V) || !hasName(T), _InvalidChanAssign
   306  		}
   307  	}
   308  
   309  	// optimization: if we don't have type parameters, we're done
   310  	if Vp == nil && Tp == nil {
   311  		return false, _IncompatibleAssign
   312  	}
   313  
   314  	errorf := func(format string, args ...any) {
   315  		if check != nil && reason != nil {
   316  			msg := check.sprintf(format, args...)
   317  			if *reason != "" {
   318  				msg += "\n\t" + *reason
   319  			}
   320  			*reason = msg
   321  		}
   322  	}
   323  
   324  	// x's type V is not a named type and T is a type parameter, and
   325  	// x is assignable to each specific type in T's type set.
   326  	if !hasName(V) && Tp != nil {
   327  		ok := false
   328  		code := _IncompatibleAssign
   329  		Tp.is(func(T *term) bool {
   330  			if T == nil {
   331  				return false // no specific types
   332  			}
   333  			ok, code = x.assignableTo(check, T.typ, reason)
   334  			if !ok {
   335  				errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
   336  				return false
   337  			}
   338  			return true
   339  		})
   340  		return ok, code
   341  	}
   342  
   343  	// x's type V is a type parameter and T is not a named type,
   344  	// and values x' of each specific type in V's type set are
   345  	// assignable to T.
   346  	if Vp != nil && !hasName(T) {
   347  		x := *x // don't clobber outer x
   348  		ok := false
   349  		code := _IncompatibleAssign
   350  		Vp.is(func(V *term) bool {
   351  			if V == nil {
   352  				return false // no specific types
   353  			}
   354  			x.typ = V.typ
   355  			ok, code = x.assignableTo(check, T, reason)
   356  			if !ok {
   357  				errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
   358  				return false
   359  			}
   360  			return true
   361  		})
   362  		return ok, code
   363  	}
   364  
   365  	return false, _IncompatibleAssign
   366  }
   367  

View as plain text