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