- Incorrect type checking when &[] and [] return optional values.

- Failed to find subscript overloading on optional values.
- Added `&[]` overload to HashMap.
This commit is contained in:
Christoffer Lerno
2025-08-19 00:40:56 +02:00
parent ba55946c9a
commit de09a19a48
5 changed files with 39 additions and 5 deletions

View File

@@ -182,6 +182,24 @@ fn Value*? HashMap.get_ref(&map, Key key)
return NOT_FOUND?;
}
fn Value* HashMap.get_or_create_ref(&map, Key key) @operator(&[])
{
uint hash = rehash(key.hash());
if (map.count)
{
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return &e.value;
}
}
map.set(key, {});
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return &e.value;
}
unreachable();
}
fn Entry*? HashMap.get_entry(&map, Key key)
{
if (!map.count) return NOT_FOUND?;

View File

@@ -51,6 +51,8 @@
- Compiler assert when calling unassigned CT functions #2418.
- Fixed crash in header generation when exporting functions with const enums (#2384).
- Fix incorrect panic message when slicing with negative size.
- Incorrect type checking when &[] and [] return optional values.
- Failed to find subscript overloading on optional values.
### Stdlib changes
- Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`.
@@ -65,6 +67,7 @@
- Add Freestanding OS types to runtime `env::` booleans.
- Added libloaderapi to `std::os::win32`.
- Added `HashSet.values` and `String.contains_char` #2386
- Added `&[]` overload to HashMap.
## 0.7.4 Change list

View File

@@ -1851,7 +1851,7 @@ static bool sema_analyse_operator_common(SemaContext *context, Decl *method, Typ
Decl *sema_find_untyped_operator(Type *type, OperatorOverload operator_overload, Decl *skipped)
{
type = type->canonical;
type = type_no_optional(type)->canonical;
assert(operator_overload < OVERLOAD_TYPED_START);
if (!type_may_have_sub_elements(type)) return NULL;
Decl *def = type->decl;
@@ -2098,7 +2098,7 @@ static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *
RETURN_SEMA_ERROR(rtype, "%s has unknown size and cannot be used as a return type.",
type_quoted_error_string(rtype->type));
}
if (method->func_decl.operator == OVERLOAD_ELEMENT_REF && !type_is_pointer(rtype->type))
if (method->func_decl.operator == OVERLOAD_ELEMENT_REF && !type_is_pointer(type_no_optional(rtype->type)))
{
RETURN_SEMA_ERROR(rtype, "The return type must be a pointer, but it is returning %s, did you mean to overload [] instead?",
type_quoted_error_string(rtype->type));
@@ -2224,7 +2224,7 @@ static inline void sema_get_overload_arguments(Decl *method, Type **value_ref, T
*index_ref = method->func_decl.signature.params[1]->type->canonical;
return;
case OVERLOAD_ELEMENT_REF:
*value_ref = type_no_optional(typeget(method->func_decl.signature.rtype)->canonical->pointer);
*value_ref = type_no_optional(typeget(method->func_decl.signature.rtype))->canonical->pointer;
*index_ref = method->func_decl.signature.params[1]->type->canonical;
return;
case OVERLOAD_ELEMENT_SET:

View File

@@ -11781,7 +11781,7 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
.call_expr.is_func_ref = true,
.call_expr.is_type_method = true,
};
Type *type = parent->type->canonical;
Type *type = type_no_optional(parent->type)->canonical;
Decl *first_param = method_decl->func_decl.signature.params[0];
Type *first = first_param->type->canonical;
// Deref / addr as needed.
@@ -11796,7 +11796,7 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
if (!sema_expr_rewrite_insert_deref(context, parent)) return false;
}
}
ASSERT_SPAN(method_call, parent && parent->type && first == parent->type->canonical);
ASSERT_SPAN(method_call, first == type_no_optional(parent->type)->canonical);
unit_register_external_symbol(context, method_decl);
if (!sema_expr_analyse_general_call(context, method_call, method_decl, parent, false,
NULL)) return expr_poison(method_call);

View File

@@ -103,3 +103,16 @@ fn void map_copy()
assert(hash_map_copy.len() == hash_map.len());
}
alias Test = HashMap{String, HashMap {String, String}};
fn void test_ref()
{
Test t;
t.init(tmem);
(&t["a"]).init(tmem);
(*&t["a"])["b"] = "ab";
test::eq("ab", t["a"]["b"]!!);
}