diff --git a/releasenotes.md b/releasenotes.md index 33cb0c070..2df78ce73 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -55,6 +55,7 @@ - `$define` would occasionally not properly evaluate declarations it encountered. - Fixes with error handling recursive `@tag` #1583. - Sometimes generating introspection info would not be in the global scope causing a crash #1586. +- @tag on macros cannot be retrieved with tagof #1582 ### Stdlib changes - Remove unintended print of `char[]` as String diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index d7a0f2a4c..de9b97830 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -3608,6 +3608,32 @@ static inline bool sema_expr_replace_with_enum_name_array(SemaContext *context, return sema_analyse_expr(context, enum_array_expr); } +static inline bool sema_analyse_macro_func_access(SemaContext *context, Expr *expr, Decl *parent, Expr *identifier, const char *kw, bool *missing_ref) +{ + if (kw == type_property_list[TYPE_PROPERTY_HAS_TAGOF]) + { + expr->expr_kind = EXPR_TYPECALL; + expr->type_call_expr = (ExprTypeCall) { .type = parent, .property = TYPE_PROPERTY_HAS_TAGOF }; + return true; + } + if (kw == type_property_list[TYPE_PROPERTY_TAGOF]) + { + expr->expr_kind = EXPR_TYPECALL; + expr->type_call_expr = (ExprTypeCall) { .type = parent, .property = TYPE_PROPERTY_TAGOF }; + return true; + } + if (parent->decl_kind == DECL_MACRO) + { + if (missing_ref) + { + *missing_ref = true; + return false; + } + RETURN_SEMA_ERROR(identifier, "The property '%s' is not valid on the macro '%s'.", kw, parent->name); + } + return sema_expr_analyse_type_access(context, expr, parent->type, identifier, missing_ref); +} + static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, Expr *identifier, bool *missing_ref) { ASSERT_SPAN(expr, identifier->expr_kind == EXPR_IDENTIFIER); @@ -4749,15 +4775,28 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bo SourceSpan span; Expr *identifier = sema_expr_resolve_access_child(context, child, missing_ref); if (!identifier) return false; + const char *kw = identifier->identifier_expr.ident; // 2. If our left-hand side is a type, e.g. MyInt.abc, handle this here. if (parent->expr_kind == EXPR_TYPEINFO) { return sema_expr_analyse_type_access(context, expr, parent->type_expr->type, identifier, missing_ref); } - if (parent->expr_kind == EXPR_IDENTIFIER && parent->type->type_kind == TYPE_FUNC_RAW) + if (parent->expr_kind == EXPR_IDENTIFIER) { - return sema_expr_analyse_type_access(context, expr, parent->type, identifier, missing_ref); + Decl *decl = parent->identifier_expr.decl; + switch (decl->decl_kind) + { + case DECL_FUNC: + case DECL_MACRO: + return sema_analyse_macro_func_access(context, expr, decl, identifier, kw, missing_ref); + default: + break; + } + if (parent->type->type_kind == TYPE_FUNC_RAW) + { + return sema_expr_analyse_type_access(context, expr, parent->type, identifier, missing_ref); + } } if (expr_is_const_member(parent)) { @@ -4784,7 +4823,6 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bo Type *type = type_no_optional(parent->type)->canonical; Type *flat_type = type_flatten(type); - const char *kw = identifier->identifier_expr.ident; if (kw_type == kw) { if (type_is_any_raw(flat_type)) diff --git a/test/test_suite/macros/macro_tagof.c3t b/test/test_suite/macros/macro_tagof.c3t new file mode 100644 index 000000000..0227bba7b --- /dev/null +++ b/test/test_suite/macros/macro_tagof.c3t @@ -0,0 +1,11 @@ +import std::io; +macro int test() @tag("hello", 1) +{ + return 1; +} + +fn void main() +{ + var $v = test.tagof("hello"); + io::printn($v); +} \ No newline at end of file