stage2: validate struct/array init ty

This commit is contained in:
Veikka Tuominen 2022-02-19 22:31:24 +02:00
parent 6f0601c793
commit a2533e6fca
4 changed files with 77 additions and 9 deletions

View File

@ -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) {

View File

@ -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),
}
}

View File

@ -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,

View File

@ -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,