more compile errors for non-const variables of things

closes #456
This commit is contained in:
Andrew Kelley 2017-09-09 22:46:08 -04:00
parent 5fdf3fa195
commit bc0a60c7a6
3 changed files with 108 additions and 66 deletions

View File

@ -2510,6 +2510,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
IrInstruction *init_value = nullptr;
// TODO more validation for types that can't be used for export/extern variables
TypeTableEntry *implicit_type = nullptr;
if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) {
implicit_type = explicit_type;

View File

@ -9794,6 +9794,58 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
zig_unreachable();
}
enum VarClassRequired {
VarClassRequiredAny,
VarClassRequiredConst,
VarClassRequiredIllegal,
};
static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
zig_unreachable();
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVar:
return VarClassRequiredIllegal;
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdVoid:
case TypeTableEntryIdPureError:
case TypeTableEntryIdFn:
case TypeTableEntryIdEnumTag:
return VarClassRequiredAny;
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdBlock:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdOpaque:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
return VarClassRequiredConst;
case TypeTableEntryIdPointer:
return get_var_class_required(type_entry->data.pointer.child_type);
case TypeTableEntryIdArray:
return get_var_class_required(type_entry->data.array.child_type);
case TypeTableEntryIdMaybe:
return get_var_class_required(type_entry->data.maybe.child_type);
case TypeTableEntryIdErrorUnion:
return get_var_class_required(type_entry->data.error.child_type);
case TypeTableEntryIdStruct:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
// TODO check the fields of these things and make sure that they don't recursively
// contain any of the other variable classes
return VarClassRequiredAny;
}
zig_unreachable();
}
static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
VariableTableEntry *var = decl_var_instruction->var;
@ -9803,10 +9855,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
return var->value->type;
}
AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration;
bool is_export = (variable_declaration->visib_mod == VisibModExport);
bool is_extern = variable_declaration->is_extern;
var->ref_count = 0;
TypeTableEntry *explicit_type = nullptr;
@ -9824,59 +9872,30 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
AstNode *source_node = decl_var_instruction->base.source_node;
IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
bool is_comptime_var = ir_get_var_is_comptime(var);
TypeTableEntry *result_type = casted_init_value->value.type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
}
bool is_comptime_var = ir_get_var_is_comptime(var);
switch (result_type->id) {
case TypeTableEntryIdInvalid:
break; // handled above
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
if (is_export || is_extern || (!var->src_is_const && !is_comptime_var)) {
ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type"));
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVar:
case TypeTableEntryIdBlock:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdOpaque:
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
break;
case TypeTableEntryIdMetaType:
case TypeTableEntryIdNamespace:
if (casted_init_value->value.special == ConstValSpecialRuntime) {
} else {
switch (get_var_class_required(result_type)) {
case VarClassRequiredIllegal:
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name)));
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
// OK
break;
break;
case VarClassRequiredConst:
if (!var->src_is_const && !is_comptime_var) {
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' must be const or comptime",
buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
case VarClassRequiredAny:
// OK
break;
}
}
var->value->type = result_type;

View File

@ -1435,20 +1435,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\fn bar() -> %i32 { 0 }
, ".tmp_source.zig:2:14: error: expression value is ignored");
cases.add("integer literal on a non-comptime var",
\\export fn foo() {
\\ var i = 0;
\\ while (i < 10) : (i += 1) { }
\\}
, ".tmp_source.zig:2:5: error: unable to infer variable type");
cases.add("undefined literal on a non-comptime var",
\\export fn foo() {
\\ var i = undefined;
\\ i = i32(1);
\\}
, ".tmp_source.zig:2:5: error: unable to infer variable type");
cases.add("dereference an array",
\\var s_buffer: [10]u8 = undefined;
\\pub fn pass(in: []u8) -> []u8 {
@ -2090,4 +2076,40 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'");
cases.add("non-const variables of things that require const variables",
\\const Opaque = @OpaqueType();
\\
\\export fn entry(opaque: &Opaque) {
\\ var m2 = &2;
\\ const y: u32 = *m2;
\\
\\ var a = undefined;
\\ var b = 1;
\\ var c = 1.0;
\\ var d = this;
\\ var e = null;
\\ var f = *opaque;
\\ var g = i32;
\\ var h = @import("std");
\\ var i = (Foo {}).bar;
\\
\\ var z: noreturn = return;
\\}
\\
\\const Foo = struct {
\\ fn bar(self: &const Foo) {}
\\};
,
".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime",
".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
".tmp_source.zig:8:4: error: variable of type '(integer literal)' must be const or comptime",
".tmp_source.zig:9:4: error: variable of type '(float literal)' must be const or comptime",
".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime",
".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime",
".tmp_source.zig:12:4: error: variable of type 'Opaque' must be const or comptime",
".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime",
".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime",
".tmp_source.zig:15:4: error: variable of type '(bound fn(&const Foo))' must be const or comptime",
".tmp_source.zig:17:4: error: unreachable code");
}