| 248 | }; |
| 249 | |
| 250 | DimResult getDim(EvalContext& context, const Args& args) const { |
| 251 | if (!noHierarchical(context, *args[0])) |
| 252 | return {}; |
| 253 | |
| 254 | // If an index expression is provided, evaluate it. Otherwise default to 1. |
| 255 | ConstantValue iv; |
| 256 | int32_t index = 1; |
| 257 | if (args.size() > 1) { |
| 258 | iv = args[1]->eval(context); |
| 259 | if (!iv) |
| 260 | return {}; |
| 261 | |
| 262 | std::optional<int32_t> oi = iv.integer().as<int32_t>(); |
| 263 | if (!oi || *oi <= 0) |
| 264 | return DimResult::OutOfRange(); |
| 265 | |
| 266 | index = *oi; |
| 267 | } |
| 268 | |
| 269 | // Unwrap each dimension until we reach the right index. |
| 270 | const Type* type = args[0]->type; |
| 271 | for (int32_t i = 0; i < index - 1; i++) { |
| 272 | // If this is not an array, we have nothing to index into |
| 273 | // and the index we were provided is invalid. |
| 274 | if (!type->isArray()) |
| 275 | return DimResult::OutOfRange(); |
| 276 | |
| 277 | type = type->getArrayElementType(); |
| 278 | } |
| 279 | |
| 280 | // We're pointing at the right dimension, so figure out its range. |
| 281 | // If fixed size, just return that range. |
| 282 | if (type->hasFixedRange() && !type->isScalar()) |
| 283 | return type->getFixedRange(); |
| 284 | |
| 285 | // Otherwise, this had better be a dynamic array or string. |
| 286 | if (!type->isString() && !type->isUnpackedArray()) |
| 287 | return DimResult::OutOfRange(); |
| 288 | |
| 289 | // This is a dynamically sized thing, so we need to evaluate the expression |
| 290 | // in order to know its current size. We can only do that if the index is 1 |
| 291 | // because otherwise we won't know which subelement this refers to. |
| 292 | if (index != 1) { |
| 293 | context.addDiag(diag::DynamicDimensionIndex, args[0]->sourceRange) |
| 294 | << iv << args[1]->sourceRange; |
| 295 | return {}; |
| 296 | } |
| 297 | |
| 298 | // This only works on associative arrays if they have an integral index type. |
| 299 | const Type* indexType = nullptr; |
| 300 | if (type->isAssociativeArray()) { |
| 301 | indexType = type->getAssociativeIndexType(); |
| 302 | if (!indexType || !indexType->isIntegral()) { |
| 303 | context.addDiag(diag::QueryOnAssociativeWildcard, args[0]->sourceRange) << name; |
| 304 | return {}; |
| 305 | } |
| 306 | } |
| 307 |
nothing calls this directly
no test coverage detected