Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ziglang/zig
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0e9fef78dd7e
Choose a base ref
...
head repository: ziglang/zig
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1cf7511dc9d4
Choose a head ref
  • 2 commits
  • 5 files changed
  • 1 contributor

Commits on Jul 6, 2018

  1. Copy the full SHA
    6d793c0 View commit details
  2. Copy the full SHA
    1cf7511 View commit details
Showing with 114 additions and 21 deletions.
  1. +4 −4 doc/langref.html.in
  2. +37 −0 src/analyze.cpp
  3. +1 −0 src/analyze.hpp
  4. +36 −11 src/ir.cpp
  5. +36 −6 test/compile_errors.zig
8 changes: 4 additions & 4 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
@@ -679,7 +679,7 @@ fn divide(a: i32, b: i32) i32 {
{#header_open|Float Literals#}
<p>
Float literals have type <code>comptime_float</code> which is guaranteed to hold at least all possible values
that the largest other floating point type can hold. Float literals implicitly cast to any other type.
that the largest other floating point type can hold. Float literals {#link|implicitly cast|Implicit Casts#} to any other type.
</p>
{#code_begin|syntax#}
const floating_point = 123.0E+77;
@@ -1604,7 +1604,7 @@ test "variable alignment" {
}
}
{#code_end#}
<p>In the same way that a <code>*i32</code> can be implicitly cast to a
<p>In the same way that a <code>*i32</code> can be {#link|implicitly cast|Implicit Casts#} to a
<code>*const i32</code>, a pointer with a larger alignment can be implicitly
cast to a pointer with a smaller alignment, but not vice versa.
</p>
@@ -2968,7 +2968,7 @@ test "fn reflection" {
However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/ziglang/zig/issues/786">#768</a>.
</p>
<p>
You can implicitly cast an error from a subset to its superset:
You can {#link|implicitly cast|Implicit Casts#} an error from a subset to its superset:
</p>
{#code_begin|test#}
const std = @import("std");
@@ -3101,7 +3101,7 @@ test "parse u64" {
<p>
Within the function definition, you can see some return statements that return
an error, and at the bottom a return statement that returns a <code>u64</code>.
Both types implicitly cast to <code>error!u64</code>.
Both types {#link|implicitly cast|Implicit Casts#} to <code>error!u64</code>.
</p>
<p>
What it looks like to use this function varies depending on what you're
37 changes: 37 additions & 0 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
@@ -212,6 +212,43 @@ static uint8_t bits_needed_for_unsigned(uint64_t x) {
return (upper >= x) ? base : (base + 1);
}

AstNode *type_decl_node(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
zig_unreachable();
case TypeTableEntryIdStruct:
return type_entry->data.structure.decl_node;
case TypeTableEntryIdEnum:
return type_entry->data.enumeration.decl_node;
case TypeTableEntryIdUnion:
return type_entry->data.unionation.decl_node;
case TypeTableEntryIdOpaque:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdComptimeFloat:
case TypeTableEntryIdComptimeInt:
case TypeTableEntryIdUndefined:
case TypeTableEntryIdNull:
case TypeTableEntryIdOptional:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdPromise:
return nullptr;
}
zig_unreachable();
}

bool type_is_complete(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
1 change: 1 addition & 0 deletions src/analyze.hpp
Original file line number Diff line number Diff line change
@@ -202,5 +202,6 @@ uint32_t get_coro_frame_align_bytes(CodeGen *g);
bool fn_type_can_fail(FnTypeId *fn_type_id);
bool type_can_fail(TypeTableEntry *type_entry);
bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type);
AstNode *type_decl_node(TypeTableEntry *type_entry);

#endif
47 changes: 36 additions & 11 deletions src/ir.cpp
Original file line number Diff line number Diff line change
@@ -82,6 +82,7 @@ struct ConstCastSliceMismatch;
struct ConstCastErrUnionErrSetMismatch;
struct ConstCastErrUnionPayloadMismatch;
struct ConstCastErrSetMismatch;
struct ConstCastTypeMismatch;

struct ConstCastOnly {
ConstCastResultId id;
@@ -92,6 +93,7 @@ struct ConstCastOnly {
ConstCastOptionalMismatch *optional;
ConstCastErrUnionPayloadMismatch *error_union_payload;
ConstCastErrUnionErrSetMismatch *error_union_error_set;
ConstCastTypeMismatch *type_mismatch;
ConstCastOnly *return_type;
ConstCastOnly *async_allocator_type;
ConstCastOnly *null_wrap_ptr_child;
@@ -100,6 +102,11 @@ struct ConstCastOnly {
} data;
};

struct ConstCastTypeMismatch {
TypeTableEntry *wanted_type;
TypeTableEntry *actual_type;
};

struct ConstCastOptionalMismatch {
ConstCastOnly child;
TypeTableEntry *wanted_child;
@@ -8128,15 +8135,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
}

// pointer const
if (wanted_type->id == TypeTableEntryIdPointer &&
actual_type->id == TypeTableEntryIdPointer &&
(actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment)
{
if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
if (child.id != ConstCastResultIdOk) {
@@ -8145,8 +8144,17 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
result.data.pointer_mismatch->child = child;
result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type;
result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type;
return result;
}
if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment)
{
return result;
}
return result;
}

// slice const
@@ -8341,6 +8349,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
}

result.id = ConstCastResultIdType;
result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1);
result.data.type_mismatch->wanted_type = wanted_type;
result.data.type_mismatch->actual_type = actual_type;
return result;
}

@@ -10154,6 +10165,21 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
report_recursive_error(ira, source_node, &cast_result->data.error_union_payload->child, msg);
break;
}
case ConstCastResultIdType: {
AstNode *wanted_decl_node = type_decl_node(cast_result->data.type_mismatch->wanted_type);
AstNode *actual_decl_node = type_decl_node(cast_result->data.type_mismatch->actual_type);
if (wanted_decl_node != nullptr) {
add_error_note(ira->codegen, parent_msg, wanted_decl_node,
buf_sprintf("%s declared here",
buf_ptr(&cast_result->data.type_mismatch->wanted_type->name)));
}
if (actual_decl_node != nullptr) {
add_error_note(ira->codegen, parent_msg, actual_decl_node,
buf_sprintf("%s declared here",
buf_ptr(&cast_result->data.type_mismatch->actual_type->name)));
}
break;
}
case ConstCastResultIdFnAlign: // TODO
case ConstCastResultIdFnCC: // TODO
case ConstCastResultIdFnVarArgs: // TODO
@@ -10163,7 +10189,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
case ConstCastResultIdFnGenericArgCount: // TODO
case ConstCastResultIdFnArg: // TODO
case ConstCastResultIdFnArgNoAlias: // TODO
case ConstCastResultIdType: // TODO
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
case ConstCastResultIdAsyncAllocatorType: // TODO
case ConstCastResultIdNullWrapPtr: // TODO
42 changes: 36 additions & 6 deletions test/compile_errors.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
const tests = @import("tests.zig");

pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addCase(x: {
const tc = cases.create(
"wrong same named struct",
\\const a = @import("a.zig");
\\const b = @import("b.zig");
\\
\\export fn entry() void {
\\ var a1: a.Foo = undefined;
\\ bar(&a1);
\\}
\\
\\fn bar(x: *b.Foo) void {}
,
".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'",
".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'",
"a.zig:1:17: note: Foo declared here",
"b.zig:1:17: note: Foo declared here",
);

tc.addSourceFile("a.zig",
\\pub const Foo = struct {
\\ x: i32,
\\};
);

tc.addSourceFile("b.zig",
\\pub const Foo = struct {
\\ z: f64,
\\};
);

break :x tc;
});

cases.add(
"enum field value references enum",
\\pub const Foo = extern enum {
@@ -358,9 +392,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
".tmp_source.zig:3:14: note: other value is here",
);


cases.add(
"invalid cast from integral type to enum",
cases.add("invalid cast from integral type to enum",
\\const E = enum(usize) { One, Two };
\\
\\export fn entry() void {
@@ -372,9 +404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ E.One => {},
\\ }
\\}
,
".tmp_source.zig:9:10: error: expected type 'usize', found 'E'"
);
, ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'");

cases.add(
"range operator in switch used on error set",