Compare commits

...

1 Commits

Author SHA1 Message Date
Christoffer Lerno
c1b1ca4266 Merge @ and # 2025-08-24 23:38:17 +02:00
10 changed files with 157 additions and 113 deletions

View File

@@ -128,28 +128,28 @@ macro Type Atomic.clear(&self, AtomicOrdering ordering = SEQ_CONSISTENT) @if(typ
return @atomic_exec_no_arg(atomic::flag_clear, data, ordering); return @atomic_exec_no_arg(atomic::flag_clear, data, ordering);
} }
macro @atomic_exec(#func, data, value, ordering) @local macro @atomic_exec(@func, data, value, ordering) @local
{ {
switch(ordering) switch(ordering)
{ {
case RELAXED: return #func(data, value, RELAXED); case RELAXED: return @func(data, value, RELAXED);
case ACQUIRE: return #func(data, value, ACQUIRE); case ACQUIRE: return @func(data, value, ACQUIRE);
case RELEASE: return #func(data, value, RELEASE); case RELEASE: return @func(data, value, RELEASE);
case ACQUIRE_RELEASE: return #func(data, value, ACQUIRE_RELEASE); case ACQUIRE_RELEASE: return @func(data, value, ACQUIRE_RELEASE);
case SEQ_CONSISTENT: return #func(data, value, SEQ_CONSISTENT); case SEQ_CONSISTENT: return @func(data, value, SEQ_CONSISTENT);
default: unreachable("Ordering may not be non-atomic or unordered."); default: unreachable("Ordering may not be non-atomic or unordered.");
} }
} }
macro @atomic_exec_no_arg(#func, data, ordering) @local macro @atomic_exec_no_arg(@func, data, ordering) @local
{ {
switch(ordering) switch(ordering)
{ {
case RELAXED: return #func(data, RELAXED); case RELAXED: return @func(data, RELAXED);
case ACQUIRE: return #func(data, ACQUIRE); case ACQUIRE: return @func(data, ACQUIRE);
case RELEASE: return #func(data, RELEASE); case RELEASE: return @func(data, RELEASE);
case ACQUIRE_RELEASE: return #func(data, ACQUIRE_RELEASE); case ACQUIRE_RELEASE: return @func(data, ACQUIRE_RELEASE);
case SEQ_CONSISTENT: return #func(data, SEQ_CONSISTENT); case SEQ_CONSISTENT: return @func(data, SEQ_CONSISTENT);
default: unreachable("Ordering may not be non-atomic or unordered."); default: unreachable("Ordering may not be non-atomic or unordered.");
} }
} }
@@ -157,9 +157,9 @@ macro @atomic_exec_no_arg(#func, data, ordering) @local
module std::atomic; module std::atomic;
import std::math; import std::math;
macro bool @is_native_atomic_value(#value) @private macro bool @is_native_atomic_value(@value) @private
{ {
return is_native_atomic_type($typeof(#value)); return is_native_atomic_type($typeof(@value));
} }
macro bool is_native_atomic_type($Type) macro bool is_native_atomic_type($Type)

View File

@@ -405,6 +405,26 @@ bool decl_needs_prefix(Decl *decl)
switch (decl->decl_kind) switch (decl->decl_kind)
{ {
case DECL_VAR: case DECL_VAR:
switch (decl->var.kind)
{
case VARDECL_CONST:
case VARDECL_GLOBAL:
case VARDECL_UNWRAPPED:
case VARDECL_ERASE:
case VARDECL_REWRAPPED:
break;
case VARDECL_LOCAL:
case VARDECL_PARAM:
case VARDECL_MEMBER:
case VARDECL_BITMEMBER:
case VARDECL_PARAM_EXPR:
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_LOCAL_CT:
case VARDECL_LOCAL_CT_TYPE:
return false;
}
FALLTHROUGH;
case DECL_ALIAS: case DECL_ALIAS:
case DECL_FUNC: case DECL_FUNC:
case DECL_MACRO: case DECL_MACRO:

View File

@@ -948,11 +948,12 @@ typedef struct
TypeProperty property; TypeProperty property;
} ExprTypeCall; } ExprTypeCall;
typedef struct typedef struct
{ {
Path *path; Path *path;
const char *ident; const char *ident;
bool is_const; IdentType ident_type;
} ExprUnresolvedIdentifier; } ExprUnresolvedIdentifier;
typedef struct typedef struct
@@ -3733,7 +3734,6 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
case EXPR_OPTIONAL: case EXPR_OPTIONAL:
case EXPR_FORCE_UNWRAP: case EXPR_FORCE_UNWRAP:
case EXPR_GENERIC_IDENT: case EXPR_GENERIC_IDENT:
case EXPR_HASH_IDENT:
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
case EXPR_LAMBDA: case EXPR_LAMBDA:
case EXPR_LAST_FAULT: case EXPR_LAST_FAULT:

View File

@@ -432,7 +432,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
} }
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
case EXPR_HASH_IDENT:
ASSERT(expr->resolve_status != RESOLVE_DONE); ASSERT(expr->resolve_status != RESOLVE_DONE);
return expr; return expr;
case EXPR_BENCHMARK_HOOK: case EXPR_BENCHMARK_HOOK:

View File

@@ -772,7 +772,6 @@ typedef enum
EXPR_FORCE_UNWRAP, EXPR_FORCE_UNWRAP,
EXPR_FLOAT_TO_INT, EXPR_FLOAT_TO_INT,
EXPR_GENERIC_IDENT, EXPR_GENERIC_IDENT,
EXPR_HASH_IDENT,
EXPR_IDENTIFIER, EXPR_IDENTIFIER,
EXPR_INITIALIZER_LIST, EXPR_INITIALIZER_LIST,
EXPR_INT_TO_FLOAT, EXPR_INT_TO_FLOAT,
@@ -831,6 +830,14 @@ typedef enum
EXPR_LAST = EXPR_VASPLAT EXPR_LAST = EXPR_VASPLAT
} ExprKind; } ExprKind;
typedef enum
{
IDENT_NORMAL,
IDENT_AT,
IDENT_CONST,
IDENT_HASH
} IdentType;
typedef enum typedef enum
{ {
FLOAT_ABI_NONE, FLOAT_ABI_NONE,
@@ -1669,7 +1676,7 @@ typedef enum
#define NON_RUNTIME_EXPR EXPR_POISONED: \ #define NON_RUNTIME_EXPR EXPR_POISONED: \
case EXPR_CT_DEFINED: \ case EXPR_CT_DEFINED: \
case EXPR_CT_ASSIGNABLE: case EXPR_CT_IS_CONST: \ case EXPR_CT_ASSIGNABLE: case EXPR_CT_IS_CONST: \
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \ case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: \
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \ case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
case EXPR_SPLAT: case EXPR_STRINGIFY: case EXPR_TYPECALL: \ case EXPR_SPLAT: case EXPR_STRINGIFY: case EXPR_TYPECALL: \
case EXPR_CT_EVAL case EXPR_CT_EVAL

View File

@@ -50,7 +50,6 @@ const char *expr_kind_to_string(ExprKind kind)
case EXPR_FORCE_UNWRAP: return "force_unwrap"; case EXPR_FORCE_UNWRAP: return "force_unwrap";
case EXPR_FLOAT_TO_INT: return "float_to_int"; case EXPR_FLOAT_TO_INT: return "float_to_int";
case EXPR_GENERIC_IDENT: return "generic_ident"; case EXPR_GENERIC_IDENT: return "generic_ident";
case EXPR_HASH_IDENT: return "hash_ident";
case EXPR_IDENTIFIER: return "identifier"; case EXPR_IDENTIFIER: return "identifier";
case EXPR_UNRESOLVED_IDENTIFIER: return "unresolved_identifier"; case EXPR_UNRESOLVED_IDENTIFIER: return "unresolved_identifier";
case EXPR_INITIALIZER_LIST: return "initializer_list"; case EXPR_INITIALIZER_LIST: return "initializer_list";
@@ -480,7 +479,6 @@ bool expr_is_runtime_const(Expr *expr)
return false; return false;
case EXPR_CT_CALL: case EXPR_CT_CALL:
case EXPR_TYPEINFO: case EXPR_TYPEINFO:
case EXPR_HASH_IDENT:
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
case EXPR_POISONED: case EXPR_POISONED:
case EXPR_CT_ARG: case EXPR_CT_ARG:
@@ -876,7 +874,6 @@ bool expr_is_pure(Expr *expr)
case EXPR_DECL: case EXPR_DECL:
case EXPR_OPTIONAL: case EXPR_OPTIONAL:
case EXPR_RETHROW: case EXPR_RETHROW:
case EXPR_HASH_IDENT:
case EXPR_MACRO_BLOCK: case EXPR_MACRO_BLOCK:
case EXPR_NAMED_ARGUMENT: case EXPR_NAMED_ARGUMENT:
case EXPR_INITIALIZER_LIST: case EXPR_INITIALIZER_LIST:

View File

@@ -672,7 +672,7 @@ static Expr *parse_ct_stringify(ParseContext *c, Expr *left, SourceSpan lhs_star
ASSIGN_EXPR_OR_RET(Expr *inner, parse_expr(c), poisoned_expr); ASSIGN_EXPR_OR_RET(Expr *inner, parse_expr(c), poisoned_expr);
const char *end = c->lexer.lexing_start - 1; const char *end = c->lexer.lexing_start - 1;
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
if (inner->expr_kind == EXPR_HASH_IDENT || (inner->expr_kind == EXPR_CT_ARG && inner->ct_arg_expr.type == TOKEN_CT_VAEXPR)) if ((inner->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && (inner->unresolved_ident_expr.ident_type == IDENT_AT || inner->unresolved_ident_expr.ident_type == IDENT_HASH)) || (inner->expr_kind == EXPR_CT_ARG && inner->ct_arg_expr.type == TOKEN_CT_VAEXPR))
{ {
Expr *expr = expr_new(EXPR_STRINGIFY, start_span); Expr *expr = expr_new(EXPR_STRINGIFY, start_span);
expr->inner_expr = inner; expr->inner_expr = inner;
@@ -1123,17 +1123,6 @@ static Expr *parse_ct_ident(ParseContext *c, Expr *left, SourceSpan lhs_span UNU
return expr; return expr;
} }
static Expr *parse_hash_ident(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSED)
{
ASSERT(!left && "Unexpected left hand side");
Expr *expr = EXPR_NEW_TOKEN(EXPR_HASH_IDENT);
expr->ct_ident_expr.identifier = symstr(c);
advance_and_verify(c, TOKEN_HASH_IDENT);
return expr;
}
/** /**
* ct_eval ::= CT_EVAL '(' expr ')' * ct_eval ::= CT_EVAL '(' expr ')'
*/ */
@@ -1304,7 +1293,23 @@ static Expr *parse_identifier(ParseContext *c, Expr *left, SourceSpan lhs_start)
} }
Expr *expr = EXPR_NEW_TOKEN(EXPR_UNRESOLVED_IDENTIFIER); Expr *expr = EXPR_NEW_TOKEN(EXPR_UNRESOLVED_IDENTIFIER);
expr->unresolved_ident_expr.ident = symstr(c); expr->unresolved_ident_expr.ident = symstr(c);
expr->unresolved_ident_expr.is_const = tok_is(c, TOKEN_CONST_IDENT); switch (c->tok)
{
case TOKEN_CONST_IDENT:
expr->unresolved_ident_expr.ident_type = IDENT_CONST;
break;
case TOKEN_AT_IDENT:
expr->unresolved_ident_expr.ident_type = IDENT_AT;
break;
case TOKEN_HASH_IDENT:
expr->unresolved_ident_expr.ident_type = IDENT_HASH;
break;
case TOKEN_IDENT:
expr->unresolved_ident_expr.ident_type = IDENT_NORMAL;
break;
default:
UNREACHABLE;
}
advance(c); advance(c);
return expr; return expr;
} }
@@ -2158,7 +2163,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE }, [TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_CT_CONST_IDENT] = { parse_ct_ident, NULL, PREC_NONE }, [TOKEN_CT_CONST_IDENT] = { parse_ct_ident, NULL, PREC_NONE },
[TOKEN_CT_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE }, [TOKEN_CT_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
[TOKEN_HASH_IDENT] = { parse_hash_ident, NULL, PREC_NONE }, [TOKEN_HASH_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_AT_IDENT] = { parse_identifier, NULL, PREC_NONE }, [TOKEN_AT_IDENT] = { parse_identifier, NULL, PREC_NONE },
[TOKEN_ELLIPSIS] = { parse_splat, NULL, PREC_NONE }, [TOKEN_ELLIPSIS] = { parse_splat, NULL, PREC_NONE },
[TOKEN_FN] = { parse_lambda, NULL, PREC_NONE }, [TOKEN_FN] = { parse_lambda, NULL, PREC_NONE },

View File

@@ -1632,6 +1632,17 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
} }
param_kind = VARDECL_PARAM_EXPR; param_kind = VARDECL_PARAM_EXPR;
break; break;
case TOKEN_AT_IDENT:
// expression @foo
name = symstr(c);
advance_and_verify(c, TOKEN_AT_IDENT);
if (ellipsis || tok_is(c, TOKEN_ELLIPSIS))
{
PRINT_ERROR_LAST("Expression parameters may not be varargs, use untyped macro varargs '...' instead.");
return false;
}
param_kind = VARDECL_PARAM_EXPR;
break;
// Compile time type $Type // Compile time type $Type
case TOKEN_CT_TYPE_IDENT: case TOKEN_CT_TYPE_IDENT:
name = symstr(c); name = symstr(c);
@@ -2164,15 +2175,18 @@ static inline Decl *parse_alias_type(ParseContext *c)
type_info = expr->type_expr; type_info = expr->type_expr;
break; break;
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
if (expr->unresolved_ident_expr.is_const) switch (expr->unresolved_ident_expr.ident_type)
{ {
print_error_at(decl->span, "A constant may not have a type name alias, it must have an all caps name."); case IDENT_CONST:
print_error_at(decl->span, "A constant may not have a type name alias, it must have an all caps name.");
return poisoned_decl;
case IDENT_AT:
case IDENT_HASH:
case IDENT_NORMAL:
print_error_at(decl->span, "An identifier may not be aliased with type name, it must start with a lower case letter.");
return poisoned_decl;
} }
else UNREACHABLE;
{
print_error_at(decl->span, "An identifier may not be aliased with type name, it must start with a lower case letter.");
}
return poisoned_decl;
default: default:
PRINT_ERROR_HERE("Expected a type to alias here."); PRINT_ERROR_HERE("Expected a type to alias here.");
return poisoned_decl; return poisoned_decl;

View File

@@ -323,35 +323,39 @@ Expr *sema_resolve_string_ident(SemaContext *context, Expr *inner, bool report_m
ASSERT_SPAN(inner, expr_is_const_string(inner)); ASSERT_SPAN(inner, expr_is_const_string(inner));
Path *path = NULL; Path *path = NULL;
const char *interned_version = NULL; const char *interned_version = NULL;
TokenType token = sema_splitpathref(inner->const_expr.bytes.ptr, inner->const_expr.bytes.len, &path, &interned_version); const char *bytes = inner->const_expr.bytes.ptr;
size_t len = inner->const_expr.bytes.len;
TokenType token = sema_splitpathref(bytes, len, &path, &interned_version);
switch (token) switch (token)
{ {
case TOKEN_CONST_IDENT: case TOKEN_CONST_IDENT:
inner->unresolved_ident_expr.is_const = true; inner->unresolved_ident_expr.ident_type = IDENT_CONST;
goto IDENT_CHECK;
break; break;
case TOKEN_HASH_IDENT:
if (path) goto NO_PATH;
inner->expr_kind = EXPR_HASH_IDENT;
inner->ct_ident_expr.identifier = interned_version;
inner->resolve_status = RESOLVE_NOT_DONE;
return inner;
case TOKEN_CT_IDENT: case TOKEN_CT_IDENT:
if (path) goto NO_PATH; if (path) goto NO_PATH;
inner->expr_kind = EXPR_CT_IDENT; inner->expr_kind = EXPR_CT_IDENT;
inner->ct_ident_expr.identifier = interned_version; inner->ct_ident_expr.identifier = interned_version;
inner->resolve_status = RESOLVE_NOT_DONE; inner->resolve_status = RESOLVE_NOT_DONE;
return inner; return inner;
case TOKEN_HASH_IDENT:
if (path) goto NO_PATH;
inner->unresolved_ident_expr.ident_type = IDENT_HASH;
goto IDENT_CHECK;
case TOKEN_AT_IDENT: case TOKEN_AT_IDENT:
inner->unresolved_ident_expr.ident_type = IDENT_AT;
goto IDENT_CHECK;
case TOKEN_IDENT: case TOKEN_IDENT:
inner->unresolved_ident_expr.ident_type = IDENT_NORMAL;
IDENT_CHECK:
if (!interned_version) if (!interned_version)
{ {
if (report_missing) if (report_missing)
{ {
SEMA_ERROR(inner, "'%.*s' could not be found, did you spell it right?", (int)inner->const_expr.bytes.len, inner->const_expr.bytes.ptr); SEMA_ERROR(inner, "'%.*s' could not be found, did you spell it right?", (int)len, bytes);
} }
return NULL; return NULL;
} }
inner->unresolved_ident_expr.is_const = false;
break; break;
case TYPE_TOKENS: case TYPE_TOKENS:
{ {
@@ -670,7 +674,6 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
if (failed_ref) goto FAILED_REF; if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant expression."); RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant expression.");
case EXPR_CT_ARG: case EXPR_CT_ARG:
case EXPR_HASH_IDENT:
case EXPR_POISONED: case EXPR_POISONED:
case EXPR_ADDR_CONVERSION: case EXPR_ADDR_CONVERSION:
case EXPR_ASM: case EXPR_ASM:
@@ -825,8 +828,6 @@ static bool expr_may_ref(Expr *expr)
case EXPR_SLICE: case EXPR_SLICE:
case EXPR_SUBSCRIPT_ADDR: case EXPR_SUBSCRIPT_ADDR:
return true; return true;
case EXPR_HASH_IDENT:
return false;
case EXPR_TWO: case EXPR_TWO:
return expr_may_ref(expr->two_expr.last); return expr_may_ref(expr->two_expr.last);
case EXPR_EXPRESSION_LIST: case EXPR_EXPRESSION_LIST:
@@ -1181,7 +1182,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
// Rerun if we can't do inference. // Rerun if we can't do inference.
if (!decl) if (!decl)
{ {
if (!expr->unresolved_ident_expr.path && expr->unresolved_ident_expr.is_const && (!to || to->canonical->type_kind != TYPE_ENUM)) if (!expr->unresolved_ident_expr.path && expr->unresolved_ident_expr.ident_type == IDENT_CONST && (!to || to->canonical->type_kind != TYPE_ENUM))
{ {
CompilationUnit **units = context->unit->module->units; CompilationUnit **units = context->unit->module->units;
FOREACH (CompilationUnit *, unit, units) FOREACH (CompilationUnit *, unit, units)
@@ -1369,7 +1370,7 @@ EVAL_BOTH:
static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, Expr *right) static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, Expr *right)
{ {
// Special handling of f = FOO_BAR // Special handling of f = FOO_BAR
if (right->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && right->unresolved_ident_expr.is_const) if (right->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && right->unresolved_ident_expr.ident_type == IDENT_CONST)
{ {
if (!sema_analyse_expr(context, left)) return false; if (!sema_analyse_expr(context, left)) return false;
switch (type_flatten(left->type)->type_kind) switch (type_flatten(left->type)->type_kind)
@@ -1382,7 +1383,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left,
} }
} }
// Special handling of f = FOO_BAR // Special handling of f = FOO_BAR
if (left->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && left->unresolved_ident_expr.is_const) if (left->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && left->unresolved_ident_expr.ident_type == IDENT_CONST)
{ {
if (!sema_analyse_expr(context, right)) return false; if (!sema_analyse_expr(context, right)) return false;
switch (type_flatten(right->type)->type_kind) switch (type_flatten(right->type)->type_kind)
@@ -4482,11 +4483,6 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, Che
RETRY: RETRY:
switch (child->expr_kind) switch (child->expr_kind)
{ {
case EXPR_HASH_IDENT:
SEMA_DEPRECATED(child, "Using 'abc.#foo' access style is deprecated. Use 'abc.eval($foo)' instead.");
if (!sema_expr_fold_hash(context, child)) return NULL;
in_hash = true;
goto RETRY;
case EXPR_OTHER_CONTEXT: case EXPR_OTHER_CONTEXT:
{ {
Expr *inner = child->expr_other_context.inner; Expr *inner = child->expr_other_context.inner;
@@ -4499,6 +4495,13 @@ RETRY:
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
// A path is not allowed. // A path is not allowed.
if (child->unresolved_ident_expr.path) break; if (child->unresolved_ident_expr.path) break;
if (child->unresolved_ident_expr.ident_type == IDENT_HASH)
{
SEMA_DEPRECATED(child, "Using 'abc.#foo' access style is deprecated. Use 'abc.eval($foo)' instead.");
if (!sema_expr_fold_hash(context, child)) return child;
in_hash = true;
goto RETRY;
}
return child; return child;
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
if (child->resolve_status == RESOLVE_DONE) goto ALREADY_RESOLVED; if (child->resolve_status == RESOLVE_DONE) goto ALREADY_RESOLVED;
@@ -4645,9 +4648,9 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
ASSERT_SPAN(expr, identifier->expr_kind == EXPR_UNRESOLVED_IDENTIFIER); ASSERT_SPAN(expr, identifier->expr_kind == EXPR_UNRESOLVED_IDENTIFIER);
Type *canonical = parent_type->canonical; Type *canonical = parent_type->canonical;
const char *name = identifier->unresolved_ident_expr.ident; const char *name = identifier->unresolved_ident_expr.ident;
bool is_const = identifier->unresolved_ident_expr.is_const; IdentType ident_type = identifier->unresolved_ident_expr.ident_type;
if (!is_const) if (ident_type != IDENT_CONST)
{ {
TypeProperty property = type_property_by_name(name); TypeProperty property = type_property_by_name(name);
if (sema_type_property_is_valid_for_type(canonical, property)) if (sema_type_property_is_valid_for_type(canonical, property))
@@ -4674,7 +4677,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
{ {
case DECL_ENUM: case DECL_ENUM:
case DECL_CONST_ENUM: case DECL_CONST_ENUM:
if (is_const) if (ident_type == IDENT_CONST)
{ {
if (!sema_expr_analyse_enum_constant(context, expr, name, decl)) if (!sema_expr_analyse_enum_constant(context, expr, name, decl))
{ {
@@ -4740,9 +4743,9 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
Decl *decl = parent->const_expr.member.decl; Decl *decl = parent->const_expr.member.decl;
const char *name = identifier->unresolved_ident_expr.ident; const char *name = identifier->unresolved_ident_expr.ident;
bool is_const = identifier->unresolved_ident_expr.is_const; IdentType ident_type = identifier->unresolved_ident_expr.ident_type;
if (is_const) if (ident_type == IDENT_CONST)
{ {
if (missing_ref) goto MISSING_REF; if (missing_ref) goto MISSING_REF;
RETURN_SEMA_ERROR(expr, "There is no member '%s' for %s.", name, type_to_error_string(decl->type)); RETURN_SEMA_ERROR(expr, "There is no member '%s' for %s.", name, type_to_error_string(decl->type));
@@ -6682,22 +6685,31 @@ static bool sema_expr_analyse_ct_subscript_assign(SemaContext *context, Expr *ex
static bool sema_expr_fold_hash(SemaContext *context, Expr *expr) static bool sema_expr_fold_hash(SemaContext *context, Expr *expr)
{ {
assert(expr->expr_kind == EXPR_HASH_IDENT); bool did_fold = false;
while (expr->expr_kind == EXPR_HASH_IDENT) while (expr->expr_kind == EXPR_UNRESOLVED_IDENTIFIER && (expr->unresolved_ident_expr.ident_type == IDENT_HASH || expr->unresolved_ident_expr.ident_type == IDENT_AT))
{ {
ASSERT(expr && expr->hash_ident_expr.identifier); ASSERT(expr && expr->unresolved_ident_expr.ident);
DEBUG_LOG("Resolving identifier '%s'", expr->hash_ident_expr.identifier); DEBUG_LOG("Resolving identifier '%s'", expr->unresolved_ident_expr.ident);
Decl *decl = sema_resolve_symbol(context, expr->hash_ident_expr.identifier, NULL, expr->span); Decl *decl = sema_find_path_symbol(context, expr->unresolved_ident_expr.ident, NULL);
// Already handled // Already handled
if (!decl) return expr_poison(expr); if (!decl)
{
return BOOL_FALSE;
}
if (decl->decl_kind != DECL_VAR) break;
ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR); ASSERT_SPAN(expr, decl->decl_kind == DECL_VAR);
DEBUG_LOG("Replacing expr (%p) with '%s' (%p) expression resolve: %d", expr, expr_kind_to_string(decl->var.init_expr->expr_kind), decl->var.init_expr, decl->var.init_expr->resolve_status); if (decl->var.kind == VARDECL_PARAM_EXPR)
expr_replace(expr, copy_expr_single(decl->var.init_expr)); {
REMINDER("Handle inlining at"); DEBUG_LOG("Replacing expr (%p) with '%s' (%p) expression resolve: %d", expr, expr_kind_to_string(decl->var.init_expr->expr_kind), decl->var.init_expr, decl->var.init_expr->resolve_status);
expr_replace(expr, copy_expr_single(decl->var.init_expr));
did_fold = true;
continue;
}
break;
} }
return expr_ok(expr); return expr_ok(expr) ? (did_fold ? BOOL_TRUE : BOOL_FALSE) : BOOL_ERR;
} }
/** /**
* Analyse a = b * Analyse a = b
@@ -8412,6 +8424,10 @@ RETRY:;
{ {
case EXPR_POISONED: case EXPR_POISONED:
return false; return false;
case EXPR_UNRESOLVED_IDENTIFIER:
if (inner->unresolved_ident_expr.ident_type != IDENT_AT && inner->unresolved_ident_expr.ident_type != IDENT_HASH) break;
if (sema_expr_fold_hash(context, inner)) goto RETRY;
break;
case EXPR_OTHER_CONTEXT: case EXPR_OTHER_CONTEXT:
{ {
Expr *inner_c = inner->expr_other_context.inner; Expr *inner_c = inner->expr_other_context.inner;
@@ -8419,9 +8435,6 @@ RETRY:;
expr_replace(inner, inner_c); expr_replace(inner, inner_c);
return sema_expr_analyse_addr(c2, expr, failed_ref, check); return sema_expr_analyse_addr(c2, expr, failed_ref, check);
} }
case EXPR_HASH_IDENT:
if (!sema_expr_fold_hash(context, inner)) return false;
goto RETRY;
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
inner->expr_kind = EXPR_SUBSCRIPT_ADDR; inner->expr_kind = EXPR_SUBSCRIPT_ADDR;
if (failed_ref) if (failed_ref)
@@ -10254,7 +10267,7 @@ static inline bool sema_expr_analyse_ct_feature(SemaContext *context, Expr *expr
Expr *inner = expr->ct_call_expr.main_var; Expr *inner = expr->ct_call_expr.main_var;
if (expr->ct_call_expr.flat_path) goto ERROR; if (expr->ct_call_expr.flat_path) goto ERROR;
if (inner->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) goto ERROR; if (inner->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) goto ERROR;
if (!inner->unresolved_ident_expr.is_const) goto ERROR; if (inner->unresolved_ident_expr.ident_type != IDENT_CONST) goto ERROR;
const char *name = inner->unresolved_ident_expr.ident; const char *name = inner->unresolved_ident_expr.ident;
void *value = htable_get(&compiler.context.features, (void *)name); void *value = htable_get(&compiler.context.features, (void *)name);
@@ -10311,6 +10324,11 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
{ {
Decl *decl = sema_find_path_symbol(active_context, main_expr->unresolved_ident_expr.ident, main_expr->unresolved_ident_expr.path); Decl *decl = sema_find_path_symbol(active_context, main_expr->unresolved_ident_expr.ident, main_expr->unresolved_ident_expr.path);
if (!decl_ok(decl)) goto FAIL; if (!decl_ok(decl)) goto FAIL;
if (decl && decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM_EXPR)
{
main_expr = copy_expr_single(decl->var.init_expr);
goto RETRY;
}
success = decl != NULL; success = decl != NULL;
break; break;
} }
@@ -10342,13 +10360,6 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
success = eval != NULL; success = eval != NULL;
break; break;
} }
case EXPR_HASH_IDENT:
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->hash_ident_expr.identifier, NULL, main_expr->span);
if (!decl) goto FAIL;
main_expr = copy_expr_single(decl->var.init_expr);
goto RETRY;
}
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
{ {
if (!sema_expr_analyse_subscript(active_context, main_expr, CHECK_VALUE, true)) if (!sema_expr_analyse_subscript(active_context, main_expr, CHECK_VALUE, true))
@@ -10682,13 +10693,9 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex
context = inner->expr_other_context.context; context = inner->expr_other_context.context;
inner = inner->expr_other_context.inner; inner = inner->expr_other_context.inner;
continue; continue;
case EXPR_HASH_IDENT: case EXPR_UNRESOLVED_IDENTIFIER:
{ if (sema_expr_fold_hash(context, inner)) continue;
Decl *decl = sema_resolve_symbol(context, inner->ct_ident_expr.identifier, NULL, inner->span); break;
if (!decl) return false;
inner = decl->var.init_expr;
continue;
}
default: default:
break; break;
} }
@@ -10697,7 +10704,7 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex
const char *desc = span_to_string(inner->span); const char *desc = span_to_string(inner->span);
if (!desc) if (!desc)
{ {
RETURN_SEMA_ERROR(expr, "Failed to stringify hash variable contents - they must be a single line and not exceed 255 characters."); RETURN_SEMA_ERROR(expr, "Failed to stringify expr variable contents - they must be a single line and not exceed 255 characters.");
} }
expr_rewrite_const_string(expr, desc); expr_rewrite_const_string(expr, desc);
return true; return true;
@@ -10976,9 +10983,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
return sema_expr_analyse_builtin(context, expr, true); return sema_expr_analyse_builtin(context, expr, true);
case EXPR_CT_CALL: case EXPR_CT_CALL:
return sema_expr_analyse_ct_call(context, expr); return sema_expr_analyse_ct_call(context, expr);
case EXPR_HASH_IDENT:
if (!sema_expr_fold_hash(context, expr)) return false;
return sema_analyse_expr_check(context, expr, check);
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
return sema_expr_analyse_ct_identifier(context, expr); return sema_expr_analyse_ct_identifier(context, expr);
case EXPR_OPTIONAL: case EXPR_OPTIONAL:
@@ -11025,6 +11029,10 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
UNREACHABLE UNREACHABLE
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
if (sema_expr_fold_hash(context, expr))
{
return sema_analyse_expr_check(context, expr, check);
}
return sema_expr_analyse_identifier(context, NULL, expr); return sema_expr_analyse_identifier(context, NULL, expr);
case EXPR_CALL: case EXPR_CALL:
return sema_expr_analyse_call(context, expr, NULL); return sema_expr_analyse_call(context, expr, NULL);
@@ -11280,10 +11288,6 @@ static inline bool sema_analyse_expr_lvalue_dispatch(SemaContext *context, Expr
RETRY: RETRY:
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_HASH_IDENT:
DEBUG_LOG("Expand hash ident");
if (!sema_expr_fold_hash(context, expr)) return false;
goto RETRY;
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
return sema_expr_resolve_ct_identifier(context, expr); return sema_expr_resolve_ct_identifier(context, expr);
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
@@ -11313,6 +11317,7 @@ RETRY:
if (!sema_analyse_expr_dispatch(context, expr, CHECK_VALUE)) return false; if (!sema_analyse_expr_dispatch(context, expr, CHECK_VALUE)) return false;
goto IDENT_CHECK; goto IDENT_CHECK;
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
if (sema_expr_fold_hash(context, expr)) goto RETRY;
if (!sema_analyse_expr_dispatch(context, expr, CHECK_VALUE)) return false; if (!sema_analyse_expr_dispatch(context, expr, CHECK_VALUE)) return false;
FALLTHROUGH; FALLTHROUGH;
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
@@ -11638,9 +11643,6 @@ RETRY:
expr->resolve_status = RESOLVE_RUNNING; expr->resolve_status = RESOLVE_RUNNING;
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_HASH_IDENT:
if (!sema_expr_fold_hash(context, expr)) return false;
goto RETRY;
case EXPR_OTHER_CONTEXT: case EXPR_OTHER_CONTEXT:
{ {
InliningSpan *new_span = context->inlined_at; InliningSpan *new_span = context->inlined_at;
@@ -11657,6 +11659,7 @@ RETRY:
if (!sema_expr_analyse_initializer_list(context, to, expr)) return expr_poison(expr); if (!sema_expr_analyse_initializer_list(context, to, expr)) return expr_poison(expr);
break; break;
case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_UNRESOLVED_IDENTIFIER:
if (sema_expr_fold_hash(context, expr)) goto RETRY;
if (!sema_expr_analyse_identifier(context, to, expr)) return expr_poison(expr); if (!sema_expr_analyse_identifier(context, to, expr)) return expr_poison(expr);
break; break;
case EXPR_LAMBDA: case EXPR_LAMBDA:

View File

@@ -798,7 +798,6 @@ static inline bool sema_expr_valid_try_expression(Expr *expr)
case EXPR_MACRO_BLOCK: case EXPR_MACRO_BLOCK:
case EXPR_OPTIONAL: case EXPR_OPTIONAL:
case EXPR_FORCE_UNWRAP: case EXPR_FORCE_UNWRAP:
case EXPR_HASH_IDENT:
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
case EXPR_INITIALIZER_LIST: case EXPR_INITIALIZER_LIST:
case EXPR_LAMBDA: case EXPR_LAMBDA:
@@ -911,7 +910,7 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
if (ident->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) RETURN_SEMA_ERROR(ident, "A variable name was expected here."); if (ident->expr_kind != EXPR_UNRESOLVED_IDENTIFIER) RETURN_SEMA_ERROR(ident, "A variable name was expected here.");
ASSERT(ident->resolve_status != RESOLVE_DONE); ASSERT(ident->resolve_status != RESOLVE_DONE);
if (ident->unresolved_ident_expr.path) RETURN_SEMA_ERROR(ident->unresolved_ident_expr.path, "The variable may not have a path."); if (ident->unresolved_ident_expr.path) RETURN_SEMA_ERROR(ident->unresolved_ident_expr.path, "The variable may not have a path.");
if (ident->unresolved_ident_expr.is_const) RETURN_SEMA_ERROR(ident, "Expected a variable starting with a lower case letter."); if (ident->unresolved_ident_expr.ident_type != IDENT_NORMAL) RETURN_SEMA_ERROR(ident, "Expected a variable starting with a lower case letter.");
const char *ident_name = ident->unresolved_ident_expr.ident; const char *ident_name = ident->unresolved_ident_expr.ident;
// Special check for `if (try a = a)` // Special check for `if (try a = a)`
@@ -996,7 +995,7 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr)
} }
if (ident->unresolved_ident_expr.path) RETURN_SEMA_ERROR(ident->unresolved_ident_expr.path, "The variable may not have a path."); if (ident->unresolved_ident_expr.path) RETURN_SEMA_ERROR(ident->unresolved_ident_expr.path, "The variable may not have a path.");
if (ident->unresolved_ident_expr.is_const) RETURN_SEMA_ERROR(ident, "Expected a variable starting with a lower case letter."); if (ident->unresolved_ident_expr.ident_type != IDENT_NORMAL) RETURN_SEMA_ERROR(ident, "Expected a variable starting with a lower case letter.");
// 4d. A new declaration is created. // 4d. A new declaration is created.
decl = decl_new_var(ident->unresolved_ident_expr.ident, ident->span, type, VARDECL_LOCAL); decl = decl_new_var(ident->unresolved_ident_expr.ident, ident->span, type, VARDECL_LOCAL);
@@ -3247,7 +3246,7 @@ static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive)
{ {
if (ret->contract_fault.resolved) continue; if (ret->contract_fault.resolved) continue;
Expr *expr = ret->contract_fault.expr; Expr *expr = ret->contract_fault.expr;
if (expr->expr_kind != EXPR_UNRESOLVED_IDENTIFIER && !expr->unresolved_ident_expr.is_const) if (expr->expr_kind != EXPR_UNRESOLVED_IDENTIFIER || expr->unresolved_ident_expr.ident_type != IDENT_CONST)
{ {
RETURN_SEMA_ERROR(expr, "Expected a fault name here."); RETURN_SEMA_ERROR(expr, "Expected a fault name here.");
} }