Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/types/index.go

Documentation: go/types

     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  // This file implements typechecking of index/slice expressions.
     6  
     7  package types
     8  
     9  import (
    10  	"go/ast"
    11  	"go/constant"
    12  	"go/internal/typeparams"
    13  )
    14  
    15  // If e is a valid function instantiation, indexExpr returns true.
    16  // In that case x represents the uninstantiated function value and
    17  // it is the caller's responsibility to instantiate the function.
    18  func (check *Checker) indexExpr(x *operand, e *ast.IndexExpr) (isFuncInst bool) {
    19  	check.exprOrType(x, e.X)
    20  
    21  	switch x.mode {
    22  	case invalid:
    23  		check.use(typeparams.UnpackExpr(e.Index)...)
    24  		return false
    25  
    26  	case typexpr:
    27  		// type instantiation
    28  		x.mode = invalid
    29  		x.typ = check.varType(e)
    30  		if x.typ != Typ[Invalid] {
    31  			x.mode = typexpr
    32  		}
    33  		return false
    34  
    35  	case value:
    36  		if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
    37  			// function instantiation
    38  			return true
    39  		}
    40  	}
    41  
    42  	valid := false
    43  	length := int64(-1) // valid if >= 0
    44  	switch typ := optype(x.typ).(type) {
    45  	case *Basic:
    46  		if isString(typ) {
    47  			valid = true
    48  			if x.mode == constant_ {
    49  				length = int64(len(constant.StringVal(x.val)))
    50  			}
    51  			// an indexed string always yields a byte value
    52  			// (not a constant) even if the string and the
    53  			// index are constant
    54  			x.mode = value
    55  			x.typ = universeByte // use 'byte' name
    56  		}
    57  
    58  	case *Array:
    59  		valid = true
    60  		length = typ.len
    61  		if x.mode != variable {
    62  			x.mode = value
    63  		}
    64  		x.typ = typ.elem
    65  
    66  	case *Pointer:
    67  		if typ := asArray(typ.base); typ != nil {
    68  			valid = true
    69  			length = typ.len
    70  			x.mode = variable
    71  			x.typ = typ.elem
    72  		}
    73  
    74  	case *Slice:
    75  		valid = true
    76  		x.mode = variable
    77  		x.typ = typ.elem
    78  
    79  	case *Map:
    80  		index := check.singleIndex(e)
    81  		if index == nil {
    82  			x.mode = invalid
    83  			return
    84  		}
    85  		var key operand
    86  		check.expr(&key, index)
    87  		check.assignment(&key, typ.key, "map index")
    88  		// ok to continue even if indexing failed - map element type is known
    89  		x.mode = mapindex
    90  		x.typ = typ.elem
    91  		x.expr = e
    92  		return
    93  
    94  	case *_Sum:
    95  		// A sum type can be indexed if all of the sum's types
    96  		// support indexing and have the same index and element
    97  		// type. Special rules apply for maps in the sum type.
    98  		var tkey, telem Type // key is for map types only
    99  		nmaps := 0           // number of map types in sum type
   100  		if typ.is(func(t Type) bool {
   101  			var e Type
   102  			switch t := under(t).(type) {
   103  			case *Basic:
   104  				if isString(t) {
   105  					e = universeByte
   106  				}
   107  			case *Array:
   108  				e = t.elem
   109  			case *Pointer:
   110  				if t := asArray(t.base); t != nil {
   111  					e = t.elem
   112  				}
   113  			case *Slice:
   114  				e = t.elem
   115  			case *Map:
   116  				// If there are multiple maps in the sum type,
   117  				// they must have identical key types.
   118  				// TODO(gri) We may be able to relax this rule
   119  				// but it becomes complicated very quickly.
   120  				if tkey != nil && !Identical(t.key, tkey) {
   121  					return false
   122  				}
   123  				tkey = t.key
   124  				e = t.elem
   125  				nmaps++
   126  			case *_TypeParam:
   127  				check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
   128  			case *instance:
   129  				panic("unimplemented")
   130  			}
   131  			if e == nil || telem != nil && !Identical(e, telem) {
   132  				return false
   133  			}
   134  			telem = e
   135  			return true
   136  		}) {
   137  			// If there are maps, the index expression must be assignable
   138  			// to the map key type (as for simple map index expressions).
   139  			if nmaps > 0 {
   140  				index := check.singleIndex(e)
   141  				if index == nil {
   142  					x.mode = invalid
   143  					return
   144  				}
   145  				var key operand
   146  				check.expr(&key, index)
   147  				check.assignment(&key, tkey, "map index")
   148  				// ok to continue even if indexing failed - map element type is known
   149  
   150  				// If there are only maps, we are done.
   151  				if nmaps == len(typ.types) {
   152  					x.mode = mapindex
   153  					x.typ = telem
   154  					x.expr = e
   155  					return
   156  				}
   157  
   158  				// Otherwise we have mix of maps and other types. For
   159  				// now we require that the map key be an integer type.
   160  				// TODO(gri) This is probably not good enough.
   161  				valid = isInteger(tkey)
   162  				// avoid 2nd indexing error if indexing failed above
   163  				if !valid && key.mode == invalid {
   164  					x.mode = invalid
   165  					return
   166  				}
   167  				x.mode = value // map index expressions are not addressable
   168  			} else {
   169  				// no maps
   170  				valid = true
   171  				x.mode = variable
   172  			}
   173  			x.typ = telem
   174  		}
   175  	}
   176  
   177  	if !valid {
   178  		check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x)
   179  		x.mode = invalid
   180  		return
   181  	}
   182  
   183  	index := check.singleIndex(e)
   184  	if index == nil {
   185  		x.mode = invalid
   186  		return
   187  	}
   188  
   189  	// In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0)
   190  	// the element type may be accessed before it's set. Make sure we have
   191  	// a valid type.
   192  	if x.typ == nil {
   193  		x.typ = Typ[Invalid]
   194  	}
   195  
   196  	check.index(index, length)
   197  	return false
   198  }
   199  
   200  func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
   201  	check.expr(x, e.X)
   202  	if x.mode == invalid {
   203  		check.use(e.Low, e.High, e.Max)
   204  		return
   205  	}
   206  
   207  	valid := false
   208  	length := int64(-1) // valid if >= 0
   209  	switch typ := optype(x.typ).(type) {
   210  	case *Basic:
   211  		if isString(typ) {
   212  			if e.Slice3 {
   213  				check.invalidOp(x, _InvalidSliceExpr, "3-index slice of string")
   214  				x.mode = invalid
   215  				return
   216  			}
   217  			valid = true
   218  			if x.mode == constant_ {
   219  				length = int64(len(constant.StringVal(x.val)))
   220  			}
   221  			// spec: "For untyped string operands the result
   222  			// is a non-constant value of type string."
   223  			if typ.kind == UntypedString {
   224  				x.typ = Typ[String]
   225  			}
   226  		}
   227  
   228  	case *Array:
   229  		valid = true
   230  		length = typ.len
   231  		if x.mode != variable {
   232  			check.invalidOp(x, _NonSliceableOperand, "cannot slice %s (value not addressable)", x)
   233  			x.mode = invalid
   234  			return
   235  		}
   236  		x.typ = &Slice{elem: typ.elem}
   237  
   238  	case *Pointer:
   239  		if typ := asArray(typ.base); typ != nil {
   240  			valid = true
   241  			length = typ.len
   242  			x.typ = &Slice{elem: typ.elem}
   243  		}
   244  
   245  	case *Slice:
   246  		valid = true
   247  		// x.typ doesn't change
   248  
   249  	case *_Sum, *_TypeParam:
   250  		check.errorf(x, 0, "generic slice expressions not yet implemented")
   251  		x.mode = invalid
   252  		return
   253  	}
   254  
   255  	if !valid {
   256  		check.invalidOp(x, _NonSliceableOperand, "cannot slice %s", x)
   257  		x.mode = invalid
   258  		return
   259  	}
   260  
   261  	x.mode = value
   262  
   263  	// spec: "Only the first index may be omitted; it defaults to 0."
   264  	if e.Slice3 && (e.High == nil || e.Max == nil) {
   265  		check.invalidAST(inNode(e, e.Rbrack), "2nd and 3rd index required in 3-index slice")
   266  		x.mode = invalid
   267  		return
   268  	}
   269  
   270  	// check indices
   271  	var ind [3]int64
   272  	for i, expr := range []ast.Expr{e.Low, e.High, e.Max} {
   273  		x := int64(-1)
   274  		switch {
   275  		case expr != nil:
   276  			// The "capacity" is only known statically for strings, arrays,
   277  			// and pointers to arrays, and it is the same as the length for
   278  			// those types.
   279  			max := int64(-1)
   280  			if length >= 0 {
   281  				max = length + 1
   282  			}
   283  			if _, v := check.index(expr, max); v >= 0 {
   284  				x = v
   285  			}
   286  		case i == 0:
   287  			// default is 0 for the first index
   288  			x = 0
   289  		case length >= 0:
   290  			// default is length (== capacity) otherwise
   291  			x = length
   292  		}
   293  		ind[i] = x
   294  	}
   295  
   296  	// constant indices must be in range
   297  	// (check.index already checks that existing indices >= 0)
   298  L:
   299  	for i, x := range ind[:len(ind)-1] {
   300  		if x > 0 {
   301  			for _, y := range ind[i+1:] {
   302  				if y >= 0 && x > y {
   303  					check.errorf(inNode(e, e.Rbrack), _SwappedSliceIndices, "swapped slice indices: %d > %d", x, y)
   304  					break L // only report one error, ok to continue
   305  				}
   306  			}
   307  		}
   308  	}
   309  }
   310  
   311  // singleIndex returns the (single) index from the index expression e.
   312  // If the index is missing, or if there are multiple indices, an error
   313  // is reported and the result is nil.
   314  func (check *Checker) singleIndex(e *ast.IndexExpr) ast.Expr {
   315  	index := e.Index
   316  	if index == nil {
   317  		check.invalidAST(e, "missing index for %s", e)
   318  		return nil
   319  	}
   320  
   321  	indexes := typeparams.UnpackExpr(index)
   322  	if len(indexes) == 0 {
   323  		check.invalidAST(index, "index expression %v with 0 indices", index)
   324  		return nil
   325  	}
   326  	if len(indexes) > 1 {
   327  		// TODO(rFindley) should this get a distinct error code?
   328  		check.invalidOp(indexes[1], _InvalidIndex, "more than one index")
   329  	}
   330  	return indexes[0]
   331  }
   332  
   333  // index checks an index expression for validity.
   334  // If max >= 0, it is the upper bound for index.
   335  // If the result typ is != Typ[Invalid], index is valid and typ is its (possibly named) integer type.
   336  // If the result val >= 0, index is valid and val is its constant int value.
   337  func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) {
   338  	typ = Typ[Invalid]
   339  	val = -1
   340  
   341  	var x operand
   342  	check.expr(&x, index)
   343  	if !check.isValidIndex(&x, _InvalidIndex, "index", false) {
   344  		return
   345  	}
   346  
   347  	if x.mode != constant_ {
   348  		return x.typ, -1
   349  	}
   350  
   351  	if x.val.Kind() == constant.Unknown {
   352  		return
   353  	}
   354  
   355  	v, ok := constant.Int64Val(x.val)
   356  	assert(ok)
   357  	if max >= 0 && v >= max {
   358  		check.invalidArg(&x, _InvalidIndex, "index %s is out of bounds", &x)
   359  		return
   360  	}
   361  
   362  	// 0 <= v [ && v < max ]
   363  	return x.typ, v
   364  }
   365  
   366  func (check *Checker) isValidIndex(x *operand, code errorCode, what string, allowNegative bool) bool {
   367  	if x.mode == invalid {
   368  		return false
   369  	}
   370  
   371  	// spec: "a constant index that is untyped is given type int"
   372  	check.convertUntyped(x, Typ[Int])
   373  	if x.mode == invalid {
   374  		return false
   375  	}
   376  
   377  	// spec: "the index x must be of integer type or an untyped constant"
   378  	if !isInteger(x.typ) {
   379  		check.invalidArg(x, code, "%s %s must be integer", what, x)
   380  		return false
   381  	}
   382  
   383  	if x.mode == constant_ {
   384  		// spec: "a constant index must be non-negative ..."
   385  		if !allowNegative && constant.Sign(x.val) < 0 {
   386  			check.invalidArg(x, code, "%s %s must not be negative", what, x)
   387  			return false
   388  		}
   389  
   390  		// spec: "... and representable by a value of type int"
   391  		if !representableConst(x.val, check, Typ[Int], &x.val) {
   392  			check.invalidArg(x, code, "%s %s overflows int", what, x)
   393  			return false
   394  		}
   395  	}
   396  
   397  	return true
   398  }
   399  
   400  // indexElts checks the elements (elts) of an array or slice composite literal
   401  // against the literal's element type (typ), and the element indices against
   402  // the literal length if known (length >= 0). It returns the length of the
   403  // literal (maximum index value + 1).
   404  //
   405  func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
   406  	visited := make(map[int64]bool, len(elts))
   407  	var index, max int64
   408  	for _, e := range elts {
   409  		// determine and check index
   410  		validIndex := false
   411  		eval := e
   412  		if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
   413  			if typ, i := check.index(kv.Key, length); typ != Typ[Invalid] {
   414  				if i >= 0 {
   415  					index = i
   416  					validIndex = true
   417  				} else {
   418  					check.errorf(e, _InvalidLitIndex, "index %s must be integer constant", kv.Key)
   419  				}
   420  			}
   421  			eval = kv.Value
   422  		} else if length >= 0 && index >= length {
   423  			check.errorf(e, _OversizeArrayLit, "index %d is out of bounds (>= %d)", index, length)
   424  		} else {
   425  			validIndex = true
   426  		}
   427  
   428  		// if we have a valid index, check for duplicate entries
   429  		if validIndex {
   430  			if visited[index] {
   431  				check.errorf(e, _DuplicateLitKey, "duplicate index %d in array or slice literal", index)
   432  			}
   433  			visited[index] = true
   434  		}
   435  		index++
   436  		if index > max {
   437  			max = index
   438  		}
   439  
   440  		// check element against composite literal element type
   441  		var x operand
   442  		check.exprWithHint(&x, eval, typ)
   443  		check.assignment(&x, typ, "array or slice literal")
   444  	}
   445  	return max
   446  }
   447  

View as plain text