enhance default hashing strategy for basic types (#1758)

* enhance default hashing strategy for basic types

* fix

* `$defined` in a global scope should accept testing normal macros.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
Francesco Alemanno
2025-01-02 20:44:33 +01:00
committed by GitHub
parent 14d8e93004
commit a16316d7b4
7 changed files with 99 additions and 29 deletions

View File

@@ -376,21 +376,39 @@ macro String @str_upper(String $str) @builtin => $$str_upper($str);
macro String @str_lower(String $str) @builtin => $$str_lower($str);
macro uint @str_hash(String $str) @builtin => $$str_hash($str);
macro uint int.hash(int i) => i;
macro uint uint.hash(uint i) => i;
macro uint short.hash(short s) => s;
macro uint ushort.hash(ushort s) => s;
macro uint char.hash(char c) => c;
macro uint ichar.hash(ichar c) => c;
macro uint long.hash(long i) => (uint)((i >> 32) ^ i);
macro uint ulong.hash(ulong i) => (uint)((i >> 32) ^ i);
macro uint int128.hash(int128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
macro uint uint128.hash(uint128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
macro uint bool.hash(bool b) => (uint)b;
macro uint typeid.hash(typeid t) => ((ulong)(uptr)t).hash();
macro @generic_hash_core(h, value)
{
h ^= (uint)value; // insert lowest 32 bits
h *= 0x96f59e5b; // diffuse them up
h ^= h >> 16; // diffuse them down
return h;
}
macro @generic_hash(value)
{
uint h = @generic_hash_core((uint)0x3efd4391, value);
$for (var $cnt = 4; $cnt < $sizeof(value); $cnt += 4)
value >>= 32; // reduce value
h = @generic_hash_core(h, value);
$endfor
return h;
}
macro uint int.hash(int i) => @generic_hash(i);
macro uint uint.hash(uint i) => @generic_hash(i);
macro uint short.hash(short s) => @generic_hash(s);
macro uint ushort.hash(ushort s) => @generic_hash(s);
macro uint char.hash(char c) => @generic_hash(c);
macro uint ichar.hash(ichar c) => @generic_hash(c);
macro uint long.hash(long i) => @generic_hash(i);
macro uint ulong.hash(ulong i) => @generic_hash(i);
macro uint int128.hash(int128 i) => @generic_hash(i);
macro uint uint128.hash(uint128 i) => @generic_hash(i);
macro uint bool.hash(bool b) => @generic_hash(b);
macro uint typeid.hash(typeid t) => @generic_hash(((ulong)(uptr)t));
macro uint String.hash(String c) => (uint)fnv32a::encode(c);
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
macro uint void*.hash(void* ptr) => ((ulong)(uptr)ptr).hash();
macro uint void*.hash(void* ptr) => @generic_hash(((ulong)(uptr)ptr));
distinct EmptySlot = void*;
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;

View File

@@ -44,6 +44,7 @@
- Macros with default arguments to `&`, `#` and type parameters didn't work as expected. #1754.
- `net::poll()` with negative timeout behaved incorrectly.
- Return type inference bugs with macros #1757
- `$defined` in a global scope should accept testing normal macros.
### Stdlib changes
- Increase BitWriter.write_bits limit up to 32 bits.
@@ -52,6 +53,7 @@
- Add "tokenizer" to String.
- Add "skip_empty" to split methods. Add split_to_buffer method.
- Add `@enum_from_value`.
- Updated hash function.
## 0.6.5 Change list

View File

@@ -1669,6 +1669,7 @@ typedef struct
CallEnvKind kind : 8;
bool ensures : 1;
bool pure : 1;
bool in_no_eval : 1;
SourceSpan in_if_resolution;
Decl **opt_returns;
union

View File

@@ -3962,7 +3962,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
}
else
{
if (context->call_env.kind == CALL_ENV_GLOBAL_INIT)
if (context->call_env.kind == CALL_ENV_GLOBAL_INIT && !context->call_env.in_no_eval)
{
if (context->current_macro)
{

View File

@@ -8795,24 +8795,29 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{
Expr *main_expr = list[i];
SemaContext *active_context = context;
bool in_no_eval = active_context->call_env.in_no_eval;
active_context->call_env.in_no_eval = true;
RETRY:
switch (main_expr->expr_kind)
{
case EXPR_OTHER_CONTEXT:
active_context->call_env.in_no_eval = in_no_eval;
active_context = expr->expr_other_context.context;
in_no_eval = active_context->call_env.in_no_eval;
active_context->call_env.in_no_eval = true;
main_expr = expr->expr_other_context.inner;
goto RETRY;
case EXPR_ACCESS:
if (!sema_expr_analyse_access(active_context, main_expr, &failed, CHECK_VALUE))
{
if (!failed) return false;
if (!failed) goto FAIL;
success = false;
}
break;
case EXPR_IDENTIFIER:
{
Decl *decl = sema_find_path_symbol(active_context, main_expr->identifier_expr.ident, main_expr->identifier_expr.path);
if (!decl_ok(decl)) return false;
if (!decl_ok(decl)) goto FAIL;
success = decl != NULL;
break;
}
@@ -8826,14 +8831,14 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
main_expr->resolve_status = RESOLVE_RUNNING;
if (!sema_expr_analyse_unary(active_context, main_expr, &failed, CHECK_VALUE))
{
if (!failed) return false;
if (!failed) goto FAIL;
success = false;
}
break;
case EXPR_TYPEINFO:
{
Type *type = sema_expr_check_type_exists(active_context, main_expr->type_expr);
if (!type_ok(type)) return false;
if (!type_ok(type)) goto FAIL;
success = type != NULL;
break;
}
@@ -8843,7 +8848,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_HASH_IDENT:
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->hash_ident_expr.identifier, NULL, main_expr->span);
if (!decl) return false;
if (!decl) goto FAIL;
main_expr = copy_expr_single(decl->var.init_expr);
goto RETRY;
}
@@ -8851,7 +8856,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{
if (!sema_expr_analyse_subscript(active_context, main_expr, CHECK_VALUE, true))
{
return false;
goto FAIL;
}
if (!expr_ok(main_expr))
{
@@ -8862,14 +8867,14 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_CAST:
if (!sema_expr_analyse_cast(active_context, main_expr, &failed))
{
if (!failed) return false;
if (!failed) goto FAIL;
success = false;
}
break;
case EXPR_CT_IDENT:
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->ct_ident_expr.identifier, NULL, main_expr->span);
if (!decl) return false;
if (!decl) goto FAIL;
break;
}
case EXPR_CALL:
@@ -8877,23 +8882,23 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
bool no_match;
if (!sema_expr_analyse_call(active_context, main_expr, &no_match))
{
if (!no_match) return false;
if (!no_match) goto FAIL;
success = false;
}
break;
}
case EXPR_FORCE_UNWRAP:
if (!sema_analyse_expr(active_context, main_expr->inner_expr)) return false;
if (!sema_analyse_expr(active_context, main_expr->inner_expr)) goto FAIL;
success = IS_OPTIONAL(main_expr->inner_expr);
break;
case EXPR_RETHROW:
if (!sema_analyse_expr(active_context, main_expr->rethrow_expr.inner)) return false;
if (!sema_analyse_expr(active_context, main_expr->rethrow_expr.inner)) goto FAIL;
success = IS_OPTIONAL(main_expr->rethrow_expr.inner);
break;
case EXPR_OPTIONAL:
if (!sema_expr_analyse_optional(active_context, main_expr, &failed))
{
if (!failed) return false;
if (!failed) goto FAIL;
success = false;
}
break;
@@ -8966,10 +8971,15 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_PTR_ACCESS:
case EXPR_RVALUE:
case EXPR_MAKE_ANY:
if (!sema_analyse_expr(active_context, main_expr)) return false;
if (!sema_analyse_expr(active_context, main_expr)) goto FAIL;
break;
}
if (!success) break;
active_context->call_env.in_no_eval = in_no_eval;
if (success) continue;
break;
FAIL:
active_context->call_env.in_no_eval = in_no_eval;
return false;
}
expr_rewrite_const_bool(expr, type_bool, success);
return true;

View File

@@ -312,7 +312,11 @@ INLINE bool sema_resolve_evaltype(SemaContext *context, TypeInfo *type_info, Res
INLINE bool sema_resolve_typeof(SemaContext *context, TypeInfo *type_info)
{
Expr *expr = type_info->unresolved_type_expr;
if (!sema_analyse_expr_value(context, expr)) return false;
bool in_no_eval = context->call_env.in_no_eval;
context->call_env.in_no_eval = true;
bool success = sema_analyse_expr_value(context, expr);
context->call_env.in_no_eval = in_no_eval;
if (!success) return false;
Type *expr_type = expr->type;
if (expr_type->type_kind == TYPE_FUNC_RAW) expr_type = type_get_func_ptr(expr_type);
switch (sema_resolve_storage_type(context, expr_type))

View File

@@ -0,0 +1,35 @@
// #target: macos-x64
module test;
import std;
macro foo(int a)
{
int h = a;
return a;
}
$typeof(baz(2)) y;
const ABC = $sizeof(baz(2));
macro baz(int x) => foo(x);
fn void main()
{
int x = ABC;
int a = baz(3);
}
/* #expect: test.ll
@test.y = local_unnamed_addr global i32 0, align 4
@test.ABC = local_unnamed_addr constant i64 4, align 8
entry:
%x = alloca i32, align 4
%a = alloca i32, align 4
%h = alloca i32, align 4
store i32 4, ptr %x, align 4
store i32 3, ptr %h, align 4
store i32 3, ptr %a, align 4
ret void
}