add peer type resolution for mixed-const []T and *[N]T

closes #4766

This commit also fixes the implementation of some utility functions for
adjusting properties of pointer types. Previously these functions would
incorrectly drop vector, sentinel, and inference metadata.
This commit is contained in:
Andrew Kelley 2020-03-30 13:01:53 -04:00
parent ef419dd72d
commit b980568c81
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 76 additions and 17 deletions

View File

@ -231,6 +231,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op);
static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc); static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc);
static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc); static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const);
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val); static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val);
static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val);
@ -11844,6 +11845,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull); bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull);
bool convert_to_const_slice = false; bool convert_to_const_slice = false;
bool make_the_slice_const = false;
for (; i < instruction_count; i += 1) { for (; i < instruction_count; i += 1) {
IrInstGen *cur_inst = instructions[i]; IrInstGen *cur_inst = instructions[i];
ZigType *cur_type = cur_inst->value->type; ZigType *cur_type = cur_inst->value->type;
@ -12357,12 +12359,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ? ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ?
prev_type->data.error_union.payload_type : prev_type; prev_type->data.error_union.payload_type : prev_type;
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
!cur_type->data.pointer.is_const) &&
types_match_const_cast_only(ira,
slice_ptr_type->data.pointer.child_type,
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
{ {
bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
!cur_type->data.pointer.is_const);
if (!const_ok) make_the_slice_const = true;
convert_to_const_slice = false; convert_to_const_slice = false;
continue; continue;
} }
@ -12391,12 +12393,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
break; break;
} }
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
!prev_type->data.pointer.is_const) &&
types_match_const_cast_only(ira,
slice_ptr_type->data.pointer.child_type,
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
{ {
bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
!prev_type->data.pointer.is_const);
if (!const_ok) make_the_slice_const = true;
prev_inst = cur_inst; prev_inst = cur_inst;
convert_to_const_slice = false; convert_to_const_slice = false;
continue; continue;
@ -12408,8 +12410,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
cur_type->data.pointer.child_type->id == ZigTypeIdArray && cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle &&
prev_type->data.pointer.child_type->id == ZigTypeIdArray && prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
(cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
prev_type->data.pointer.child_type->data.array.len == 0) &&
( (
prev_type->data.pointer.child_type->data.array.sentinel == nullptr || prev_type->data.pointer.child_type->data.array.sentinel == nullptr ||
(cur_type->data.pointer.child_type->data.array.sentinel != nullptr && (cur_type->data.pointer.child_type->data.array.sentinel != nullptr &&
@ -12421,6 +12421,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
prev_type->data.pointer.child_type->data.array.child_type, prev_type->data.pointer.child_type->data.array.child_type,
source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk)
{ {
bool const_ok = (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
prev_type->data.pointer.child_type->data.array.len == 0);
if (!const_ok) make_the_slice_const = true;
prev_inst = cur_inst; prev_inst = cur_inst;
convert_to_const_slice = true; convert_to_const_slice = true;
continue; continue;
@ -12429,8 +12432,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
prev_type->data.pointer.child_type->id == ZigTypeIdArray && prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle &&
cur_type->data.pointer.child_type->id == ZigTypeIdArray && cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
(prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
cur_type->data.pointer.child_type->data.array.len == 0) &&
( (
cur_type->data.pointer.child_type->data.array.sentinel == nullptr || cur_type->data.pointer.child_type->data.array.sentinel == nullptr ||
(prev_type->data.pointer.child_type->data.array.sentinel != nullptr && (prev_type->data.pointer.child_type->data.array.sentinel != nullptr &&
@ -12442,6 +12443,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
cur_type->data.pointer.child_type->data.array.child_type, cur_type->data.pointer.child_type->data.array.child_type,
source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk)
{ {
bool const_ok = (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
cur_type->data.pointer.child_type->data.array.len == 0);
if (!const_ok) make_the_slice_const = true;
convert_to_const_slice = true; convert_to_const_slice = true;
continue; continue;
} }
@ -12486,7 +12490,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
src_assert(array_type->id == ZigTypeIdArray, source_node); src_assert(array_type->id == ZigTypeIdArray, source_node);
ZigType *ptr_type = get_pointer_to_type_extra2( ZigType *ptr_type = get_pointer_to_type_extra2(
ira->codegen, array_type->data.array.child_type, ira->codegen, array_type->data.array.child_type,
prev_inst->value->type->data.pointer.is_const, false, prev_inst->value->type->data.pointer.is_const || make_the_slice_const, false,
PtrLenUnknown, PtrLenUnknown,
0, 0, 0, false, 0, 0, 0, false,
VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel); VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel);
@ -12537,6 +12541,26 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
return ira->codegen->builtin_types.entry_invalid; return ira->codegen->builtin_types.entry_invalid;
return get_optional_type(ira->codegen, prev_inst->value->type); return get_optional_type(ira->codegen, prev_inst->value->type);
} }
} else if (make_the_slice_const) {
ZigType *slice_type;
if (prev_inst->value->type->id == ZigTypeIdErrorUnion) {
slice_type = prev_inst->value->type->data.error_union.payload_type;
} else if (is_slice(prev_inst->value->type)) {
slice_type = prev_inst->value->type;
} else {
zig_unreachable();
}
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
ZigType *adjusted_ptr_type = adjust_ptr_const(ira->codegen, slice_ptr_type, make_the_slice_const);
ZigType *adjusted_slice_type = get_slice_type(ira->codegen, adjusted_ptr_type);
if (prev_inst->value->type->id == ZigTypeIdErrorUnion) {
return get_error_union_type(ira->codegen, prev_inst->value->type->data.error_union.err_set_type,
adjusted_slice_type);
} else if (is_slice(prev_inst->value->type)) {
return adjusted_slice_type;
} else {
zig_unreachable();
}
} else { } else {
return prev_inst->value->type; return prev_inst->value->type;
} }
@ -20708,24 +20732,44 @@ static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new
static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) { static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
assert(ptr_type->id == ZigTypeIdPointer); assert(ptr_type->id == ZigTypeIdPointer);
return get_pointer_to_type_extra(g, return get_pointer_to_type_extra2(g,
ptr_type->data.pointer.child_type, ptr_type->data.pointer.child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
ptr_len, ptr_len,
ptr_type->data.pointer.explicit_alignment, ptr_type->data.pointer.explicit_alignment,
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
ptr_type->data.pointer.allow_zero); ptr_type->data.pointer.allow_zero,
ptr_type->data.pointer.vector_index,
ptr_type->data.pointer.inferred_struct_field,
ptr_type->data.pointer.sentinel);
} }
static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) { static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) {
assert(ptr_type->id == ZigTypeIdPointer); assert(ptr_type->id == ZigTypeIdPointer);
return get_pointer_to_type_extra(g, return get_pointer_to_type_extra2(g,
ptr_type->data.pointer.child_type, ptr_type->data.pointer.child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
ptr_type->data.pointer.ptr_len, ptr_type->data.pointer.ptr_len,
ptr_type->data.pointer.explicit_alignment, ptr_type->data.pointer.explicit_alignment,
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
allow_zero); allow_zero,
ptr_type->data.pointer.vector_index,
ptr_type->data.pointer.inferred_struct_field,
ptr_type->data.pointer.sentinel);
}
static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const) {
assert(ptr_type->id == ZigTypeIdPointer);
return get_pointer_to_type_extra2(g,
ptr_type->data.pointer.child_type,
is_const, ptr_type->data.pointer.is_volatile,
ptr_type->data.pointer.ptr_len,
ptr_type->data.pointer.explicit_alignment,
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
ptr_type->data.pointer.allow_zero,
ptr_type->data.pointer.vector_index,
ptr_type->data.pointer.inferred_struct_field,
ptr_type->data.pointer.sentinel);
} }
static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align,

View File

@ -790,3 +790,18 @@ test "assignment to optional pointer result loc" {
var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct };
expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); expect(foo.ptr.? == @ptrCast(*c_void, &global_struct));
} }
test "peer type resolve string lit with sentinel-terminated mutable slice" {
var array: [4:0]u8 = undefined;
array[4] = 0; // TODO remove this when #4372 is solved
var slice: [:0]u8 = array[0..4 :0];
comptime expect(@TypeOf(slice, "hi") == [:0]const u8);
comptime expect(@TypeOf("hi", slice) == [:0]const u8);
}
test "peer type resolve array pointers, one of them const" {
var array1: [4]u8 = undefined;
const array2: [5]u8 = undefined;
comptime expect(@TypeOf(&array1, &array2) == []const u8);
comptime expect(@TypeOf(&array2, &array1) == []const u8);
}