aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-02-19 22:31:24 +0200
committerVeikka Tuominen <git@vexu.eu>2022-02-20 02:11:06 +0200
commita2533e6fca0f28aa64717d8e4c13fe6a780b8b15 (patch)
tree3509a8742dcf45ff99d6d370347bbc4ac08643d7
parent6f0601c79336d688c80a3b8592cf758f3c94a636 (diff)
downloadzig-a2533e6fca0f28aa64717d8e4c13fe6a780b8b15.tar.gz
zig-a2533e6fca0f28aa64717d8e4c13fe6a780b8b15.zip
stage2: validate struct/array init ty
-rw-r--r--src/AstGen.zig13
-rw-r--r--src/Sema.zig61
-rw-r--r--src/Zir.zig10
-rw-r--r--src/print_zir.zig2
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,