diff options
Diffstat (limited to 'src/check_expr.cpp')
| -rw-r--r-- | src/check_expr.cpp | 266 |
1 files changed, 227 insertions, 39 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bc7ff1bbb..3a8cdf0b1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -100,7 +100,7 @@ gb_internal void check_union_type (CheckerContext *c, Type *un gb_internal Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name); -gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0); gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); @@ -1241,7 +1241,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T } case Type_Pointer: if (source->kind == Type_Pointer) { - isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->Pointer.elem); + isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->Pointer.elem, /*level*/0, /*src_is_ptr*/false, /*allow_polymorphic*/true); if (level > 0) { return true; } @@ -1413,7 +1413,9 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T return ok; } - // return check_is_assignable_to(c, &o, poly); + + // NOTE(bill): Check for subtypes of + // return check_is_assignable_to(c, &o, poly); // && is_type_subtype_of_and_allow_polymorphic(o.type, poly); } return false; case Type_Tuple: @@ -1884,33 +1886,55 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i BigInt i = v.value_integer; - i64 bit_size = type_size_of(type); + i64 byte_size = type_size_of(type); BigInt umax = {}; BigInt imin = {}; BigInt imax = {}; - if (bit_size < 16) { - big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]); - big_int_from_i64(&imin, signed_integer_mins[bit_size]); - big_int_from_i64(&imax, signed_integer_maxs[bit_size]); - } else { + if (c->bit_field_bit_size > 0) { + i64 bit_size = gb_min(cast(i64)(8*byte_size), cast(i64)c->bit_field_bit_size); + big_int_from_u64(&umax, 1); big_int_from_i64(&imin, 1); big_int_from_i64(&imax, 1); - BigInt bi128 = {}; - BigInt bi127 = {}; - big_int_from_i64(&bi128, 128); - big_int_from_i64(&bi127, 127); + BigInt bu = {}; + BigInt bi = {}; + big_int_from_i64(&bu, bit_size); + big_int_from_i64(&bi, bit_size-1); - big_int_shl_eq(&umax, &bi128); + big_int_shl_eq(&umax, &bu); mp_decr(&umax); - big_int_shl_eq(&imin, &bi127); + big_int_shl_eq(&imin, &bi); big_int_neg(&imin, &imin); - big_int_shl_eq(&imax, &bi127); + big_int_shl_eq(&imax, &bi); mp_decr(&imax); + } else { + if (byte_size < 16) { + big_int_from_u64(&umax, unsigned_integer_maxs[byte_size]); + big_int_from_i64(&imin, signed_integer_mins[byte_size]); + big_int_from_i64(&imax, signed_integer_maxs[byte_size]); + } else { + big_int_from_u64(&umax, 1); + big_int_from_i64(&imin, 1); + big_int_from_i64(&imax, 1); + + BigInt bi128 = {}; + BigInt bi127 = {}; + big_int_from_i64(&bi128, 128); + big_int_from_i64(&bi127, 127); + + big_int_shl_eq(&umax, &bi128); + mp_decr(&umax); + + big_int_shl_eq(&imin, &bi127); + big_int_neg(&imin, &imin); + + big_int_shl_eq(&imax, &bi127); + mp_decr(&imax); + } } switch (type->Basic.kind) { @@ -2069,11 +2093,17 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } -gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0) { if (is_type_integer(type) && o->value.kind == ExactValue_Integer) { gbString b = type_to_string(type); i64 sz = type_size_of(type); + i64 bit_size = 8*sz; + bool size_changed = false; + if (max_bit_size > 0) { + size_changed = (bit_size != max_bit_size); + bit_size = gb_min(bit_size, max_bit_size); + } BigInt *bi = &o->value.value_integer; if (is_type_unsigned(type)) { if (big_int_is_neg(bi)) { @@ -2081,25 +2111,36 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } else { BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz); + BigInt bits = big_int_make_i64(bit_size); big_int_shl_eq(&max_size, &bits); big_int_sub_eq(&max_size, &one); String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } } } else { BigInt zero = big_int_make_u64(0); BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz - 1); + BigInt bits = big_int_make_i64(bit_size - 1); big_int_shl_eq(&max_size, &bits); + + String max_size_str = {}; if (big_int_is_neg(bi)) { big_int_neg(&max_size, &max_size); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); } else { big_int_sub_eq(&max_size, &one); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); + } + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } } @@ -2110,7 +2151,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } return false; } -gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2141,7 +2182,7 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); - } else if (check_integer_exceed_suggestion(c, o, type)) { + } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } } @@ -2215,13 +2256,18 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { + i64 max_bit_size = 0; + if (ctx->bit_field_bit_size) { + max_bit_size = ctx->bit_field_bit_size; + } + if (are_types_identical(o->type, type)) { error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); } else { error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); } - check_assignment_error_suggestion(ctx, o, type); + check_assignment_error_suggestion(ctx, o, type, max_bit_size); } } else { error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); @@ -2232,6 +2278,11 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ } gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { + if (o->expr && o->expr->kind == Ast_SelectorExpr) { + if (o->expr->SelectorExpr.is_bit_field) { + return true; + } + } if (o->mode == Addressing_OptionalOk) { Ast *expr = unselector_expr(o->expr); if (expr->kind != Ast_TypeAssertion) { @@ -2304,6 +2355,8 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * Entity *e = entity_of_node(ue->expr); if (e != nullptr && (e->flags & EntityFlag_Param) != 0) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); + } else if (e != nullptr && (e->flags & EntityFlag_BitFieldField) != 0) { + error(op, "Cannot take the pointer address of '%s' which is a bit_field's field", str); } else { switch (o->mode) { case Addressing_Constant: @@ -2877,6 +2930,13 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } } + if (is_type_bit_field(src)) { + return are_types_identical(core_type(src->BitField.backing_type), dst); + } + if (is_type_bit_field(dst)) { + return are_types_identical(src, core_type(dst->BitField.backing_type)); + } + if (is_type_integer(src) && is_type_rune(dst)) { return true; } @@ -2988,6 +3048,13 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { + if (is_type_polymorphic(dst)) { + if (is_type_polymorphic(src) && + operand->mode == Addressing_Variable) { + return true; + } + return false; + } return true; } @@ -3067,7 +3134,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; bool can_convert = check_cast_internal(c, x, type); - if (!can_convert) { TEMPORARY_ALLOCATOR_GUARD(); gbString expr_str = expr_to_string(x->expr, temporary_allocator()); @@ -3108,6 +3174,26 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { final_type = default_type(x->type); } update_untyped_expr_type(c, x->expr, final_type, true); + } else { + Type *src = core_type(x->type); + Type *dst = core_type(type); + if (src != dst) { + bool const REQUIRE = true; + if (is_type_integer_128bit(src) && is_type_float(dst)) { + add_package_dependency(c, "runtime", "floattidf_unsigned", REQUIRE); + add_package_dependency(c, "runtime", "floattidf", REQUIRE); + } else if (is_type_integer_128bit(dst) && is_type_float(src)) { + add_package_dependency(c, "runtime", "fixunsdfti", REQUIRE); + add_package_dependency(c, "runtime", "fixunsdfdi", REQUIRE); + } else if (src == t_f16 && is_type_float(dst)) { + add_package_dependency(c, "runtime", "gnu_h2f_ieee", REQUIRE); + add_package_dependency(c, "runtime", "extendhfsf2", REQUIRE); + } else if (is_type_float(dst) && dst == t_f16) { + add_package_dependency(c, "runtime", "truncsfhf2", REQUIRE); + add_package_dependency(c, "runtime", "truncdfhf2", REQUIRE); + add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE); + } + } } x->type = type; @@ -3729,8 +3815,16 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ return; } - if (op.kind == Token_Quo || op.kind == Token_QuoEq) { - Type *bt = base_type(x->type); + bool REQUIRE = true; + + Type *bt = base_type(x->type); + if (op.kind == Token_Mod || op.kind == Token_ModEq || + op.kind == Token_ModMod || op.kind == Token_ModModEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; + } + } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { if (bt->kind == Type_Basic) switch (bt->Basic.kind) { case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; @@ -3738,13 +3832,32 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; + + case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; } } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { - Type *bt = base_type(x->type); if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; + case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; + + + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__multi3", REQUIRE); + } + break; + } + } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); + } + break; } } @@ -4575,7 +4688,8 @@ gb_internal bool is_entity_declared_for_selector(Entity *entity, Scope *import_s if (entity->kind == Entity_Builtin) { // NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy // This means that we should just ignore the found result through it - *allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope; + *allow_builtin = entity->scope == import_scope || + (entity->scope != builtin_pkg->scope && entity->scope != intrinsics_pkg->scope); } else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) { is_declared = false; } @@ -5011,6 +5125,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->type = entity->type; operand->expr = node; + if (entity->flags & EntityFlag_BitFieldField) { + add_package_dependency(c, "runtime", "__write_bits"); + add_package_dependency(c, "runtime", "__read_bits"); + } + switch (entity->kind) { case Entity_Constant: operand->value = entity->Constant.value; @@ -5024,6 +5143,9 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } break; case Entity_Variable: + if (sel.is_bit_field) { + se->is_bit_field = true; + } if (sel.indirect) { operand->mode = Addressing_Variable; } else if (operand->mode == Addressing_Context) { @@ -7053,8 +7175,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c name == "defined" || name == "config" || name == "load" || - name == "load_hash" || - name == "load_or" + name == "load_directory" || + name == "load_hash" ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; @@ -7904,6 +8026,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A name == "config" || name == "load" || name == "load_hash" || + name == "load_directory" || name == "load_or" ) { error(node, "'#%.*s' must be used as a call", LIT(name)); @@ -8339,6 +8462,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As StringMap<String> fields_visited_through_raw_union = {}; defer (string_map_destroy(&fields_visited_through_raw_union)); + String assignment_str = str_lit("structure literal"); + if (bt->kind == Type_BitField) { + assignment_str = str_lit("bit_field literal"); + } + for (Ast *elem : elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); @@ -8360,17 +8488,26 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As continue; } - Entity *field = bt->Struct.fields[sel.index[0]]; + Entity *field = nullptr; + if (bt->kind == Type_Struct) { + field = bt->Struct.fields[sel.index[0]]; + } else if (bt->kind == Type_BitField) { + field = bt->BitField.fields[sel.index[0]]; + } else { + GB_PANIC("Unknown type"); + } + + add_entity_use(c, fv->field, field); if (string_set_update(&fields_visited, name)) { if (sel.index.count > 1) { if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); } else { - error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string)); + error(fv->field, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str)); } } else { - error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string)); + error(fv->field, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str)); } continue; } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { @@ -8378,11 +8515,13 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As continue; } if (sel.indirect) { - error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name)); + error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str)); continue; } if (sel.index.count > 1) { + GB_ASSERT(bt->kind == Type_Struct); + if (is_constant) { Type *ft = type; for (i32 index : sel.index) { @@ -8443,7 +8582,15 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As is_constant = check_is_operand_compound_lit_constant(c, &o); } - check_assignment(c, &o, field->type, str_lit("structure literal")); + u8 prev_bit_field_bit_size = c->bit_field_bit_size; + if (field->kind == Entity_Variable && field->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + c->bit_field_bit_size = field->Variable.bit_field_bit_size; + } + + check_assignment(c, &o, field->type, assignment_str); + + c->bit_field_bit_size = prev_bit_field_bit_size; } } @@ -9245,6 +9392,21 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } break; } + case Type_BitField: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + is_constant = false; + if (cl->elems[0]->kind != Ast_FieldValue) { + gbString type_str = type_to_string(type); + error(node, "%s ('bit_field') compound literals are only allowed to contain 'field = value' elements", type_str); + gb_string_free(type_str); + } else { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } + break; + } + default: { if (cl->elems.count == 0) { @@ -11058,6 +11220,32 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; + case_ast_node(f, BitFieldField, node); + str = write_expr_to_string(str, f->name, shorthand); + str = gb_string_appendc(str, ": "); + str = write_expr_to_string(str, f->type, shorthand); + str = gb_string_appendc(str, " | "); + str = write_expr_to_string(str, f->bit_size, shorthand); + case_end; + case_ast_node(bf, BitFieldType, node); + str = gb_string_appendc(str, "bit_field "); + if (!shorthand) { + str = write_expr_to_string(str, bf->backing_type, shorthand); + } + str = gb_string_appendc(str, " {"); + if (shorthand) { + str = gb_string_appendc(str, "..."); + } else { + for_array(i, bf->fields) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, bf->fields[i], false); + } + } + str = gb_string_appendc(str, "}"); + case_end; + case_ast_node(ia, InlineAsmExpr, node); str = gb_string_appendc(str, "asm("); for_array(i, ia->param_types) { |