- $typefrom now also accepts a constant string, and so works like $evaltype.

- `$evaltype` is deprecated in favour of `$typefrom`.
This commit is contained in:
Christoffer Lerno
2025-06-03 14:51:56 +02:00
parent 8fc01d4e1a
commit 9645bd3289
10 changed files with 101 additions and 22 deletions

View File

@@ -3,6 +3,8 @@
## 0.7.3 Change list
### Changes / improvements
- `$typefrom` now also accepts a constant string, and so works like `$evaltype`.
- `$evaltype` is deprecated in favour of `$typefrom`.
### Fixes

View File

@@ -9975,7 +9975,7 @@ static inline bool sema_expr_resolve_ct_eval(SemaContext *context, Expr *expr)
if (!result) return false;
if (result->expr_kind == EXPR_TYPEINFO)
{
RETURN_SEMA_ERROR(result, "Evaluation to a type requires the use of '$evaltype' rather than '$eval'.");
RETURN_SEMA_ERROR(result, "Evaluation to a type requires the use of '$typefrom' rather than '$eval'.");
}
expr_replace(expr, result);
return true;

View File

@@ -11,7 +11,7 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info,
static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_type_kind);
INLINE bool sema_resolve_vatype(SemaContext *context, TypeInfo *type_info);
INLINE bool sema_resolve_evaltype(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_kind);
INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info);
INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_kind);
INLINE bool sema_resolve_typeof(SemaContext *context, TypeInfo *type_info);
static int compare_function(Signature *sig, FunctionPrototype *proto);
@@ -293,6 +293,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
// $evaltype("Foo")
INLINE bool sema_resolve_evaltype(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_kind)
{
SEMA_DEPRECATED(type_info, "$evaltype is deprecated, use $typefrom instead.");
Expr *expr = type_info->unresolved_type_expr;
Expr *inner = sema_ct_eval_expr(context, true, expr, true);
if (!inner) return type_info_poison(type_info);
@@ -353,16 +354,69 @@ INLINE bool sema_resolve_typeof(SemaContext *context, TypeInfo *type_info)
UNREACHABLE
}
INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info)
INLINE bool sema_resolve_typefrom(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_kind)
{
Expr *expr = type_info->unresolved_type_expr;
if (!sema_analyse_expr(context, expr)) return false;
if (!sema_cast_const(expr) || expr->const_expr.const_kind != CONST_TYPEID)
if (!sema_cast_const(expr))
{
RETURN_SEMA_ERROR(expr, "Expected a constant typeid value.");
RETURN_SEMA_ERROR(expr, "Expected a constant value.");
}
type_info->type = expr->const_expr.typeid;
return true;
switch (expr->const_expr.const_kind)
{
case CONST_TYPEID:
type_info->type = expr->const_expr.typeid;
return true;
case CONST_STRING:
break;
default:
RETURN_SEMA_ERROR(expr, "Expected a constant string or typeid value.");
}
Path *path = NULL;
const char *interned_version = NULL;
const char *bytes = expr->const_expr.bytes.ptr;
ArraySize bytes_len = expr->const_expr.bytes.len;
TokenType token = sema_splitpathref(bytes, bytes_len, &path, &interned_version);
TypeInfo *info;
switch (token)
{
case TOKEN_IDENT:
if (slice_is_type(bytes, bytes_len))
{
RETURN_SEMA_ERROR(expr, "'%.*s' could not be found, did you spell it right?", (int)bytes_len, bytes);
}
FALLTHROUGH;
case TOKEN_CONST_IDENT:
RETURN_SEMA_ERROR(expr, "Expected a type name, but the argument was \"%.*s\".", (int)bytes_len, bytes);
case TYPE_TOKENS:
type_info->type = type_from_token(token);
return true;
case TOKEN_TYPE_IDENT:
info = type_info_new(TYPE_INFO_IDENTIFIER, expr->span);
info->unresolved.name = interned_version;
info->unresolved.path = path;
info->resolve_status = RESOLVE_NOT_DONE;
break;
default:
RETURN_SEMA_ERROR(expr, "Only valid types can be resolved with $typefrom. You passed the string \"%.*s\", which cannot be resolved as a type.", (int)bytes_len, bytes);
}
if (!sema_resolve_type(context, info, resolve_kind)) return false;
switch (sema_resolve_storage_type(context, info->type))
{
case STORAGE_ERROR:
return false;
case STORAGE_VOID:
case STORAGE_UNKNOWN:
case STORAGE_NORMAL:
type_info->type = info->type;
return true;
case STORAGE_WILDCARD:
RETURN_SEMA_ERROR(expr, "$typefrom failed to resolve \"%.*s\" to a definite type.", (int)bytes_len, bytes);
case STORAGE_COMPILE_TIME:
RETURN_SEMA_ERROR(expr, "$typefrom does not support compile-time types.");
}
UNREACHABLE
}
// $vatype(...)
@@ -476,7 +530,7 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info,
if (!sema_resolve_typeof(context, type_info)) return type_info_poison(type_info);
goto APPEND_QUALIFIERS;
case TYPE_INFO_TYPEFROM:
if (!sema_resolve_typefrom(context, type_info)) return type_info_poison(type_info);
if (!sema_resolve_typefrom(context, type_info, resolve_kind)) return type_info_poison(type_info);
goto APPEND_QUALIFIERS;
case TYPE_INFO_INFERRED_VECTOR:
case TYPE_INFO_INFERRED_ARRAY:

View File

@@ -151,6 +151,7 @@ const char *str_unescape(char *string);
bool str_is_identifier(const char *string);
bool str_eq(const char *str1, const char *str2);
bool str_is_type(const char *string);
bool slice_is_type(const char *string, size_t);
bool str_is_integer(const char *string);
bool str_has_no_uppercase(const char *string);
bool str_is_valid_module_name(const char *name);

View File

@@ -103,6 +103,28 @@ bool str_is_type(const char *string)
return found_lower;
}
bool slice_is_type(const char *string, size_t len)
{
const char *begin = scan_past_underscore(string);
if (!begin) return false;
const char *end = string + len;
if (begin == end) return false;
char c = begin++[0];
if (!char_is_upper(c)) return false;
bool found_lower = false;
while (begin != end)
{
c = begin++[0];
if (char_is_lower(c))
{
found_lower = true;
continue;
}
if (!char_is_alphanum_(c)) return false;
}
return found_lower;
}
bool str_is_identifier(const char *string)
{
string = scan_past_underscore(string);

View File

@@ -38,11 +38,11 @@ fn void main()
x++;
$counter++;
$endif
$if $defined($evaltype("Foo").$eval("ab")):
$if $defined($typefrom("Foo").$eval("ab")):
x++;
$counter++;
$endif
$if $defined($evaltype("mymodule::Foo").$eval("bob")):
$if $defined($typefrom("mymodule::Foo").$eval("bob")):
x++;
$counter++;
$endif

View File

@@ -10,11 +10,11 @@ int b;
fn void main()
{
printf("%s\n", Foo.qnameof);
printf("%s\n", $evaltype("Foo").qnameof);
printf("%s\n", $typefrom("Foo").qnameof);
printf("%s\n", Foo.nameof);
printf("%s\n", $evaltype("mymodule::Foo").nameof);
printf("%s\n", $typefrom("mymodule::Foo").nameof);
printf("%s\n", Foo.extnameof);
printf("%s\n", $evaltype("Foo").extnameof);
printf("%s\n", $typefrom("Foo").extnameof);
printf("%s\n", $qnameof(b));
printf("%s\n", $qnameof($eval("b")));

View File

@@ -11,10 +11,10 @@ fn void main2()
fn void main3()
{
$evaltype("int").extnameof; // #error: 'int' does not have a property or method 'extnameof'
$typefrom("int").extnameof; // #error: 'int' does not have a property or method 'extnameof'
}
fn void main4()
{
$evaltype("foo::int").extnameof; // #error: Only valid types may be resolved with $evaltype.
$typefrom("foo::int").extnameof; // #error: Only valid types can be resolved with $typefrom
}

View File

@@ -3,17 +3,17 @@ import bar;
import bar::abc;
long x = Baz.sizeof;
short y = $evaltype("Baz").sizeof;
short y = $typefrom("Baz").sizeof;
int z = bar::Baz.sizeof;
int w = bar::Baz.sizeof;
int v = bar::abc::Foo.sizeof;
int x1 = $sizeof(x);
int y1 = $sizeof($eval("y"));
int a = Baz.y.sizeof;
int b = $evaltype("Deep").a.$eval("b").sizeof;
int b = $typefrom("Deep").a.$eval("b").sizeof;
int c = Deep.a.b.c.sizeof;
int d = Deep[][100].sizeof;
int e = $evaltype("Deep")[][100]**[100][]*.sizeof;
int e = $typefrom("Deep")[][100]**[100][]*.sizeof;
int a2 = Baz.y.sizeof;
int a3 = Baz.y.sizeof;
int a4 = Baz.y.sizeof;

View File

@@ -8,7 +8,7 @@ fn void a()
fn void b()
{
int x = $evaltype("Bazz").sizeof; // #error: 'Bazz' could not be found, did you spell it rig
int x = $typefrom("Bazz").sizeof; // #error: 'Bazz' could not be found, did you spell it rig
}
@@ -19,17 +19,17 @@ fn void e()
fn void f()
{
int x = $evaltype("bar::Bazy").sizeof; // #error: 'bar::Bazy' could not be found
int x = $typefrom("bar::Bazy").sizeof; // #error: 'bar::Bazy' could not be found
}
fn void g()
{
int x = $evaltype("bar::").sizeof; // #error: Only valid types may be resolved with $evaltype
int x = $typefrom("bar::").sizeof; // #error: Only valid types can be resolved with $typefrom
}
fn void k()
{
int v = $evaltype("int").x.sizeof; // #error: 'x'.
int v = $typefrom("int").x.sizeof; // #error: 'x'.
}
fn void l()