- Implicitly convert from constant typeid to Type in $Type assignment, and $assignable.

- Make $Type parameters accept constant typeid values.
This commit is contained in:
Christoffer Lerno
2025-06-05 00:37:16 +02:00
parent ba1332dc2a
commit 7f85534414
16 changed files with 87 additions and 36 deletions

View File

@@ -175,7 +175,7 @@ macro bool is_native_atomic_type($Type)
$case BOOL:
return true;
$case DISTINCT:
return is_native_atomic_type($typefrom($Type.inner));
return is_native_atomic_type($Type.inner);
$default:
return false;
$endswitch
@@ -240,7 +240,7 @@ macro fetch_mul(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
$endif
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
var $StorageType = types::lower_to_atomic_compatible_type($typeof(*ptr));
$StorageType* storage_ptr = ($StorageType*)ptr;
@@ -280,7 +280,7 @@ macro fetch_div(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
$endif
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
var $StorageType = types::lower_to_atomic_compatible_type($typeof(*ptr));
$StorageType* storage_ptr = ($StorageType*)ptr;
@@ -372,7 +372,7 @@ macro fetch_shift_right(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
$endif
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
var $StorageType = types::lower_to_atomic_compatible_type($typeof(*ptr));
$StorageType* storage_ptr = ($StorageType*)ptr;
@@ -414,7 +414,7 @@ macro fetch_shift_left(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
$endif
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
var $StorageType = types::lower_to_atomic_compatible_type($typeof(*ptr));
$StorageType* storage_ptr = ($StorageType*)ptr;

View File

@@ -98,7 +98,7 @@ macro bool is_numerical($Type)
{
var $kind = $Type.kindof;
$if $kind == TypeKind.DISTINCT:
return is_numerical($typefrom($Type.inner));
return is_numerical($Type.inner);
$else
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|| $kind == TypeKind.VECTOR;
@@ -135,7 +135,7 @@ macro bool is_signed($Type) @const
$case FLOAT:
return true;
$case VECTOR:
return is_signed($typefrom($Type.inner));
return is_signed($Type.inner);
$default:
return false;
$endswitch
@@ -150,7 +150,7 @@ macro bool is_unsigned($Type) @const
$case UNSIGNED_INT:
return true;
$case VECTOR:
return is_unsigned($typefrom($Type.inner));
return is_unsigned($Type.inner);
$default:
return false;
$endswitch
@@ -159,7 +159,7 @@ macro bool is_unsigned($Type) @const
macro typeid flat_type($Type) @const
{
$if $Type.kindof == DISTINCT:
return flat_type($typefrom($Type.inner));
return flat_type($Type.inner);
$else
return $Type.typeid;
$endif
@@ -168,7 +168,7 @@ macro typeid flat_type($Type) @const
macro TypeKind flat_kind($Type) @const
{
$if $Type.kindof == DISTINCT:
return flat_type($typefrom($Type.inner));
return flat_type($Type.inner);
$else
return $Type.kindof;
$endif
@@ -204,7 +204,7 @@ macro bool is_underlying_int($Type) @const
$case UNSIGNED_INT:
return true;
$case DISTINCT:
return is_underlying_int($typefrom($Type.inner));
return is_underlying_int($Type.inner);
$default:
return false;
$endswitch
@@ -232,7 +232,7 @@ macro bool is_vector($Type) @const
macro typeid inner_type($Type) @const
{
$if $Type.kindof == TypeKind.DISTINCT:
return inner_type($typefrom($Type.inner));
return inner_type($Type.inner);
$else
return $Type.typeid;
$endif

View File

@@ -41,7 +41,7 @@ macro usz? struct_to_format(value, Formatter* f, bool $force_dump)
total += f.printf("%s: ", $member.nameof)!;
$endif
$if ($force_dump &&& $member.typeid.kindof == STRUCT) |||
is_struct_with_default_print($typefrom($member.typeid)):
is_struct_with_default_print($member.typeid):
total += struct_to_format($member.get(value), f, $force_dump)!;
$else
total += f.printf("%s", $member.get(value))!;

View File

@@ -191,7 +191,7 @@ const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
*>
macro usz? read_varint(stream, x_ptr)
{
var $Type = $typefrom($typeof(x_ptr).inner);
var $Type = $typeof(x_ptr).inner;
const MAX = MAX_VARS[$Type.sizeof];
$Type x;
uint shift;

View File

@@ -32,7 +32,7 @@ alias Indexs @private = char[256];
alias ElementType = $typeof((Type){}[0]);
const bool NO_KEY_FN @private = types::is_same(KeyFn, EmptySlot);
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable((Type){}[0], $typefrom(KeyFn.paramsof[0].type));
const bool KEY_BY_VALUE @private = NO_KEY_FN ||| $assignable((Type){}[0], KeyFn.paramsof[0].type);
const bool LIST_HAS_REF @private = $defined(&(Type){}[0]);
alias KeyFnReturnType @if(!NO_KEY_FN) = $typefrom(KeyFn.returns) ;

View File

@@ -25,7 +25,7 @@ fn void isort(Type list, usz low, usz high, CmpFn comp, Context context)
{
var $has_cmp = @is_valid_macro_slot(comp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
var $cmp_by_value = $has_cmp &&& $assignable(list[0], CmpFn.paramsof[0].type);
var $has_get_ref = $defined(&list[0]);
for (usz i = low; i < high; ++i)
{

View File

@@ -115,7 +115,7 @@ macro @partition(Type list, isz l, isz h, CmpFn cmp, Context context)
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(context);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom(CmpFn.paramsof[0].type));
var $cmp_by_value = $has_cmp &&& $assignable(list[0], CmpFn.paramsof[0].type);
ElementType pivot = list[l];
while (l < h)

View File

@@ -39,7 +39,7 @@ macro int @sort_cmp(list, pos, cmp, ctx) @local
{
var $has_cmp = @is_valid_macro_slot(cmp);
var $has_context = @is_valid_macro_slot(ctx);
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typefrom($typeof(cmp).paramsof[0].type));
var $cmp_by_value = $has_cmp &&& $assignable(list[0], $typeof(cmp).paramsof[0].type);
var a = list[pos];
var b = list[pos+1];

View File

@@ -6,6 +6,8 @@
- `$typefrom` now also accepts a constant string, and so works like `$evaltype`.
- `$evaltype` is deprecated in favour of `$typefrom`.
- `-0xFF` will now be a signed integer.
- Implicitly convert from constant typeid to Type in `$Type` assignment, and `$assignable`.
- Make $Type parameters accept constant typeid values.
### Fixes
- `-2147483648`, MIN literals work correctly.

View File

@@ -1089,7 +1089,7 @@ typedef struct
{
bool is_assign;
ExprId expr;
TypeInfoId type;
ExprId type;
} ExprCastable;
typedef struct
@@ -4077,6 +4077,12 @@ INLINE bool expr_is_const_float(Expr *expr)
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_FLOAT;
}
INLINE bool expr_is_const_typeid(Expr *expr)
{
ASSERT(expr->resolve_status == RESOLVE_DONE);
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_TYPEID;
}
INLINE bool expr_is_const_member(Expr *expr)
{
ASSERT(expr->resolve_status == RESOLVE_DONE);

View File

@@ -471,7 +471,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
UNREACHABLE
case EXPR_CT_CASTABLE:
MACRO_COPY_EXPRID(expr->castable_expr.expr);
MACRO_COPY_TYPEID(expr->castable_expr.type);
MACRO_COPY_EXPRID(expr->castable_expr.type);
return expr;
case EXPR_CT_EVAL:
case EXPR_CT_IS_CONST:

View File

@@ -1247,7 +1247,7 @@ static Expr *parse_ct_castable(ParseContext *c, Expr *left)
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
ASSIGN_EXPRID_OR_RET(expr->castable_expr.expr, parse_expr(c), poisoned_expr);
CONSUME_OR_RET(TOKEN_COMMA, poisoned_expr);
ASSIGN_TYPEID_OR_RET(expr->castable_expr.type, parse_type(c), poisoned_expr);
ASSIGN_EXPRID_OR_RET(expr->castable_expr.type, parse_expr(c), poisoned_expr);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
RANGE_EXTEND_PREV(expr);
return expr;

View File

@@ -4322,8 +4322,13 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl)
// Try to fold any constant into an lvalue.
if (!sema_analyse_expr_value(context, init)) goto FAIL;
if (init->expr_kind == EXPR_TYPEINFO)
{
Type *type = init->type_expr->type;
expr_rewrite_const_typeid(init, type);
}
// If this isn't a type, it's an error.
if (init->expr_kind != EXPR_TYPEINFO)
if (!expr_is_const_typeid(init))
{
SEMA_ERROR(decl->var.init_expr, "Expected a type assigned to %s.", decl->name);
goto FAIL;

View File

@@ -1364,7 +1364,13 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
case VARDECL_PARAM_CT_TYPE:
// $Foo
if (!sema_analyse_expr_value(context, arg)) return false;
if (arg->expr_kind != EXPR_TYPEINFO)
if (arg->expr_kind == EXPR_TYPEINFO)
{
assert(arg->type_expr->resolve_status == RESOLVE_DONE);
expr_rewrite_const_typeid(arg, arg->type_expr->type);
}
if (!sema_cast_const(arg) || !expr_is_const_typeid(arg))
{
RETURN_SEMA_FUNC_ERROR(definition, arg, "A type, like 'int' or 'double' was expected for the parameter '%s'.", param->name);
}
@@ -6158,7 +6164,11 @@ static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Ex
}
if (!sema_analyse_expr_value(context, right)) return false;
if (right->expr_kind != EXPR_TYPEINFO) RETURN_SEMA_ERROR(right, "Expected a type here.");
if (right->expr_kind == EXPR_TYPEINFO)
{
expr_rewrite_const_typeid(right, right->type_expr->type);
}
if (!expr_is_const_typeid(right)) RETURN_SEMA_ERROR(right, "Expected a type or constant typeid here.");
Decl *decl = sema_find_symbol(context, info->unresolved.name);
if (!decl) RETURN_SEMA_ERROR(info, "'%s' is not defined in this scope yet.", info->unresolved.name);
@@ -9313,8 +9323,8 @@ INLINE bool lambda_parameter_match(Decl **ct_lambda_params, Decl *candidate)
{
case VARDECL_LOCAL_CT_TYPE:
case VARDECL_PARAM_CT_TYPE:
if (ct_param->var.init_expr->type_expr->type->canonical !=
param->var.init_expr->type_expr->type->canonical)
if (ct_param->var.init_expr->const_expr.typeid->canonical !=
param->var.init_expr->const_expr.typeid->canonical)
return false;
break;
case VARDECL_LOCAL_CT:
@@ -9931,11 +9941,39 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty
static inline bool sema_expr_analyse_castable(SemaContext *context, Expr *expr)
{
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING);
TypeInfo *type_info = type_infoptr(expr->castable_expr.type);
Expr *type_expr = exprptr(expr->castable_expr.type);
bool in_no_eval = context->call_env.in_no_eval;
context->call_env.in_no_eval = true;
Type *type;
if (type_expr->expr_kind == EXPR_TYPEINFO)
{
TypeInfo *type_info = type_expr->type_expr;
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_INFER)) goto FAILED;
Type *type = type_info->type;
type = type_info->type;
}
else
{
if (!sema_analyse_expr_value(context, type_expr)) goto FAILED;
switch (type_expr->expr_kind)
{
case EXPR_TYPEINFO:
ASSERT_SPAN(expr, type_expr->type_expr->resolve_status == RESOLVE_DONE);
type = type_expr->type_expr->type;
break;
case EXPR_CONST:
if (type_expr->const_expr.const_kind == CONST_TYPEID)
{
type = type_expr->const_expr.typeid;
break;
}
type = NULL;
break;
default:
type = NULL;
break;
}
}
if (!type) RETURN_SEMA_ERROR(type_expr, "Expected a type or constant typeid here.");
Expr *inner = exprptr(expr->castable_expr.expr);
if (!sema_analyse_inferred_expr(context, type, inner)) goto FAILED;
bool ok = may_cast(context, inner, type, !expr->castable_expr.is_assign, true);

View File

@@ -255,14 +255,14 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
if (decl->var.kind == VARDECL_PARAM_CT_TYPE || decl->var.kind == VARDECL_LOCAL_CT_TYPE)
{
decl->var.is_read = true;
if (!decl->var.init_expr)
Expr *init_expr = decl->var.init_expr;
if (!init_expr)
{
SEMA_ERROR(type_info, "You need to assign a type to '%s' before using it.", decl->name);
return false;
RETURN_SEMA_ERROR(type_info, "You need to assign a type to '%s' before using it.", decl->name);
}
ASSERT(decl->var.init_expr->expr_kind == EXPR_TYPEINFO);
ASSERT(decl->var.init_expr->resolve_status == RESOLVE_DONE);
*type_info = *decl->var.init_expr->type_expr;
ASSERT_SPAN(init_expr, expr_is_const_typeid(init_expr));
ASSERT_SPAN(init_expr, init_expr->resolve_status == RESOLVE_DONE);
type_info->type = init_expr->const_expr.typeid;
return true;
}
FALLTHROUGH;

View File

@@ -4,7 +4,7 @@ fn void Bar.xyz(&self) @tag("footag", 123) {}
macro void Foo.tags(&self, other)
{
// inner to remove pointer
var $Type = $typefrom($typeof(other).inner);
var $Type = $typeof(other).inner;
var $methodcount = $Type.methodsof.len;
$for var $i = 0; $i < $methodcount; $i++:
var $MethodType1 = $typeof($Type.$eval($Type.methodsof[$i]));