fix: diagnose indexing a non-indexable type instead of panicking (issue 0183)
lowerIndexExpr fell through to an index_get with an .unresolved element
type for any non-indexable object (*T, *[]T, struct, scalar), reaching
codegen -> 'unresolved type reached LLVM emission' panic. Add a guard
after all indexable arms: if getElementType(obj_ty) is .unresolved and
obj_ty is itself resolved (genuinely non-indexable, not a prior-error
placeholder), emit a located 'cannot index a value of type <T>'
diagnostic + placeholder (hasErrors aborts before codegen). A single
pointer hints by pointee: ptr-to-scalar -> many-pointer/dereference;
ptr-to-array/slice -> dereference first. No false-positives (generics,
aliases, late-resolved, every indexable shape verified).
Regression: examples/diagnostics/1203-diagnostics-index-non-indexable.sx.
Verified by 3 adversarial reviews, suite 799/0. Filed adjacent pre-existing
panic 0184 (untyped positional .{ } literal with no target type).
This commit is contained in:
@@ -1840,6 +1840,37 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
|
||||
return self.builder.load(gep, elem);
|
||||
}
|
||||
const elem_ty = self.getElementType(obj_ty);
|
||||
// Final guard: the object is not an indexable shape. `getElementType`
|
||||
// recognizes every indexable type (`[N]T` array, `[]T` slice, `[*]T`
|
||||
// many-pointer, `Vector`, `string`) and `ptrToArrayElem` handled `*[N]T`
|
||||
// above; an `.unresolved` element here means the base is a single pointer
|
||||
// `*T`, a pointer-to-slice `*[]T`, a struct, or another non-indexable type.
|
||||
// Emitting an `index_get` with `.unresolved` would slip past lowering and
|
||||
// panic in emit_llvm ("unresolved type reached LLVM emission", issue 0183).
|
||||
// Diagnose here and return a placeholder so hasErrors() aborts before
|
||||
// codegen. Skip an already-`.unresolved` object type: it comes from a PRIOR
|
||||
// error (e.g. an undefined name) already diagnosed — re-reporting would
|
||||
// duplicate the message (mirrors the issue-0172 `??` guard).
|
||||
if (elem_ty == .unresolved and obj_ty != .unresolved) {
|
||||
if (self.diagnostics) |d| {
|
||||
const is_single_ptr = !obj_ty.isBuiltin() and self.module.types.get(obj_ty) == .pointer;
|
||||
if (is_single_ptr) {
|
||||
// If the pointee is itself indexable (slice/array), the right
|
||||
// advice is to dereference (`(*p)[i]`); the many-pointer hint
|
||||
// only applies to a pointer-to-scalar.
|
||||
const pointee = self.module.types.get(obj_ty).pointer.pointee;
|
||||
const pointee_indexable = (self.ptrToArrayElem(obj_ty) orelse self.getElementType(pointee)) != .unresolved;
|
||||
if (pointee_indexable) {
|
||||
d.addFmt(.err, ie.object.span, "cannot index a value of type '{s}' — dereference first (e.g. `(*p)[i]`)", .{self.formatTypeName(obj_ty)});
|
||||
} else {
|
||||
d.addFmt(.err, ie.object.span, "cannot index a value of type '{s}' — use a many-pointer '[*]T', or dereference first", .{self.formatTypeName(obj_ty)});
|
||||
}
|
||||
} else {
|
||||
d.addFmt(.err, ie.object.span, "cannot index a value of type '{s}'", .{self.formatTypeName(obj_ty)});
|
||||
}
|
||||
}
|
||||
return self.builder.constInt(0, .i64); // placeholder — hasErrors() aborts before codegen
|
||||
}
|
||||
return self.builder.emit(.{ .index_get = .{ .lhs = obj, .rhs = idx } }, elem_ty);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user