diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-02-19 22:31:24 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-02-20 02:11:06 +0200 |
| commit | a2533e6fca0f28aa64717d8e4c13fe6a780b8b15 (patch) | |
| tree | 3509a8742dcf45ff99d6d370347bbc4ac08643d7 | |
| parent | 6f0601c79336d688c80a3b8592cf758f3c94a636 (diff) | |
| download | zig-a2533e6fca0f28aa64717d8e4c13fe6a780b8b15.tar.gz zig-a2533e6fca0f28aa64717d8e4c13fe6a780b8b15.zip | |
stage2: validate struct/array init ty
| -rw-r--r-- | src/AstGen.zig | 13 | ||||
| -rw-r--r-- | src/Sema.zig | 61 | ||||
| -rw-r--r-- | src/Zir.zig | 10 | ||||
| -rw-r--r-- | src/print_zir.zig | 2 |
4 files changed, 77 insertions, 9 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 8f34a58ed4..f2217f9cc3 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1282,6 +1282,7 @@ fn arrayInitExpr( } } const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); + _ = try gz.addUnNode(.validate_array_init_ty, array_type_inst, node); const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr); break :inst .{ .array = array_type_inst, @@ -1495,8 +1496,10 @@ fn structInitExpr( switch (rl) { .discard => { // TODO if a type expr is given the fields should be validated for that type - if (struct_init.ast.type_expr != 0) - _ = try typeExpr(gz, scope, struct_init.ast.type_expr); + if (struct_init.ast.type_expr != 0) { + const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); + } for (struct_init.ast.fields) |field_init| { _ = try expr(gz, scope, .discard, field_init); } @@ -1505,6 +1508,7 @@ fn structInitExpr( .ref => { if (struct_init.ast.type_expr != 0) { const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); } else { return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); @@ -1513,6 +1517,7 @@ fn structInitExpr( .none => { if (struct_init.ast.type_expr != 0) { const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); } else { return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); @@ -1523,6 +1528,7 @@ fn structInitExpr( return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); } const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); return rvalue(gz, rl, result, node); }, @@ -1573,6 +1579,7 @@ fn structInitExprRlPtr( return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); } const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); + _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr); defer as_scope.unstack(); @@ -2334,6 +2341,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .closure_capture, .memcpy, .memset, + .validate_array_init_ty, + .validate_struct_init_ty, => break :b true, } } else switch (maybe_unused_result) { diff --git a/src/Sema.zig b/src/Sema.zig index 5dadb94922..e7220640a0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -872,6 +872,16 @@ fn analyzeBodyInner( i += 1; continue; }, + .validate_array_init_ty => { + try sema.validateArrayInitTy(block, inst); + i += 1; + continue; + }, + .validate_struct_init_ty => { + try sema.validateStructInitTy(block, inst); + i += 1; + continue; + }, .validate_struct_init => { try sema.zirValidateStructInit(block, inst, false); i += 1; @@ -1341,6 +1351,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt return sema.fail(block, src, "expected optional type, found {}", .{optional_ty}); } +fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { + return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ty}); +} + +fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { + return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ty}); +} + fn failWithErrorSetCodeMissing( sema: *Sema, block: *Block, @@ -2614,9 +2632,7 @@ fn zirArrayBasePtr( .Struct => if (elem_ty.isTuple()) return base_ptr, else => {}, } - return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{ - sema.typeOf(start_ptr).childType(), - }); + return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); } fn zirFieldBasePtr( @@ -2640,9 +2656,40 @@ fn zirFieldBasePtr( .Struct, .Union => return base_ptr, else => {}, } - return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ - sema.typeOf(start_ptr).childType(), - }); + return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); +} + +fn validateArrayInitTy( + sema: *Sema, + block: *Block, + inst: Zir.Inst.Index, +) CompileError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + const ty = try sema.resolveType(block, src, inst_data.operand); + + switch (ty.zigTypeTag()) { + .Array, .Vector => return, + .Struct => if (ty.isTuple()) return, + else => {}, + } + return sema.failWithArrayInitNotSupported(block, src, ty); +} + +fn validateStructInitTy( + sema: *Sema, + block: *Block, + inst: Zir.Inst.Index, +) CompileError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + const ty = try sema.resolveType(block, src, inst_data.operand); + + switch (ty.zigTypeTag()) { + .Struct, .Union => return, + else => {}, + } + return sema.failWithStructInitNotSupported(block, src, ty); } fn zirValidateStructInit( @@ -10815,7 +10862,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE .Struct => return structInitEmpty(sema, block, obj_ty, src, src), .Array => return arrayInitEmpty(sema, obj_ty), .Void => return sema.addConstant(obj_ty, Value.void), - else => unreachable, + else => return sema.failWithArrayInitNotSupported(block, src, obj_ty), } } diff --git a/src/Zir.zig b/src/Zir.zig index 339a141c15..750caad4a0 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -655,6 +655,12 @@ pub const Inst = struct { /// *?S returns *S /// Uses the `un_node` field. field_base_ptr, + /// Checks that the type supports array init syntax. + /// Uses the `un_node` field. + validate_array_init_ty, + /// Checks that the type supports struct init syntax. + /// Uses the `un_node` field. + validate_struct_init_ty, /// Given a set of `field_ptr` instructions, assumes they are all part of a struct /// initialization expression, and emits compile errors for duplicate fields /// as well as missing fields, if applicable. @@ -1101,6 +1107,8 @@ pub const Inst = struct { .switch_cond_ref, .array_base_ptr, .field_base_ptr, + .validate_array_init_ty, + .validate_struct_init_ty, .validate_struct_init, .validate_struct_init_comptime, .validate_array_init, @@ -1356,6 +1364,8 @@ pub const Inst = struct { .switch_capture_multi_ref = .switch_capture, .array_base_ptr = .un_node, .field_base_ptr = .un_node, + .validate_array_init_ty = .un_node, + .validate_struct_init_ty = .un_node, .validate_struct_init = .pl_node, .validate_struct_init_comptime = .pl_node, .validate_array_init = .pl_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 5349d515aa..7aa315b114 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -237,6 +237,8 @@ const Writer = struct { .switch_cond_ref, .array_base_ptr, .field_base_ptr, + .validate_array_init_ty, + .validate_struct_init_ty, => try self.writeUnNode(stream, inst), .ref, |
