fix(types): type force-unwrap so opt!.field chains resolve [0101]
ExprTyper.inferType had no `.force_unwrap` arm, so `mk()!` typed as `.unresolved`. The bind-first form (`v := mk()!; v.field`) worked because lowerForceUnwrap produces a correctly typed value stored in a slot, but the chained `mk()!.field` re-derives the receiver type via inferExprType and got `.unresolved` — the struct-field lookup failed, the field read emitted as `undef` (garbage), and `mk()!.method()` failed to resolve the method. Add a `.force_unwrap` arm resolving the operand's optional child type. One arm fixes every chained form — field, nested `opt!.a.b`, `opt!.method()` (pointer + value receiver), and `opt![i]` all route receiver typing through inferExprType. Regression: examples/0905-optionals-unwrap-field-chain.sx — garbage / compile error pre-fix, all correct after.
This commit is contained in:
@@ -84,6 +84,19 @@ pub const ExprTyper = struct {
|
||||
if (op_ty == channel) break :blk .void;
|
||||
break :blk self.l.failableSuccessType(op_ty);
|
||||
},
|
||||
// `opt!` force-unwraps an optional to its child type. Without this
|
||||
// arm a chained `opt!.field` / `opt![i]` / `opt!.method()` would
|
||||
// type its receiver as `.unresolved` (the `else` below) and fail to
|
||||
// resolve — even though `lowerForceUnwrap` produces a correctly
|
||||
// typed value. Mirrors lowerForceUnwrap's resolveOptionalInner.
|
||||
.force_unwrap => |fu| blk: {
|
||||
const opt_ty = self.l.inferExprType(fu.operand);
|
||||
if (!opt_ty.isBuiltin()) {
|
||||
const info = self.l.module.types.get(opt_ty);
|
||||
if (info == .optional) break :blk info.optional.child;
|
||||
}
|
||||
break :blk .unresolved;
|
||||
},
|
||||
.caller_location => self.l.module.types.findByName(self.l.module.types.internString("Source_Location")) orelse .unresolved,
|
||||
.if_expr => |ie| {
|
||||
// If-else types as its branches' unified type. A `noreturn`
|
||||
|
||||
Reference in New Issue
Block a user