From 9e477056ed3567c50b3d70a46d9955e520975d1b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 23 Jul 2023 23:55:38 +0200 Subject: [PATCH] Fixes to $defined implementation. --- lib/std/collections/list.c3 | 10 +-- src/compiler/copying.c | 1 + src/compiler/enums.h | 3 +- src/compiler/expr.c | 17 ++--- src/compiler/parse_expr.c | 15 ++++- src/compiler/sema_expr.c | 66 ++++++++++--------- src/compiler/sema_liveness.c | 1 + src/compiler/types.c | 1 + src/version.h | 2 +- .../compile_time_introspection/defined_2.c3t | 41 ++++++++++++ 10 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 test/test_suite/compile_time_introspection/defined_2.c3t diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index 9eb16b582..4e69e0903 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -313,7 +313,7 @@ fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : self) { - if (v == type) return i; + if (equals(v, type)) return i; } return SearchResult.MISSING?; } @@ -322,7 +322,7 @@ fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE) { foreach_r (i, v : self) { - if (v == type) return i; + if (equals(v, type)) return i; } return SearchResult.MISSING?; } @@ -332,7 +332,7 @@ fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE) if (self.size != other_list.size) return false; foreach (i, v : self) { - if (v != other_list.entries[i]) return false; + if (!equals(v, other_list.entries[i])) return false; } return true; } @@ -348,7 +348,7 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { foreach (i, v : self) { - if (v == value) return true; + if (equals(v, value)) return true; } return false; } @@ -364,7 +364,7 @@ fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE) usz size = self.size; for (usz i = size; i > 0; i--) { - if (self.entries[i - 1] != value) continue; + if (!equals(self.entries[i - 1], value)) continue; for (usz j = i; j < size; j++) { self.entries[j - 1] = self.entries[j]; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 4e7ebf2f0..871f02675 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -426,6 +426,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_STRINGIFY: case EXPR_CT_EVAL: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: MACRO_COPY_EXPR(expr->inner_expr); return expr; case EXPR_TYPEID_INFO: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index fbeea6b80..f48d3652c 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -160,7 +160,7 @@ typedef enum case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS #define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \ - case EXPR_CT_CHECKS: \ + case EXPR_CT_CHECKS: case EXPR_CT_DEFINED: \ case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \ case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \ case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_CT_EVAL @@ -220,6 +220,7 @@ typedef enum EXPR_CT_ARG, EXPR_CT_CALL, EXPR_CT_CHECKS, + EXPR_CT_DEFINED, EXPR_CT_EVAL, EXPR_CT_IDENT, EXPR_DECL, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 6efbd6b42..d35a64890 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -82,6 +82,7 @@ bool expr_may_addr(Expr *expr) return true; case EXPR_TEST_HOOK: return false; + case NON_RUNTIME_EXPR: case EXPR_ASM: case EXPR_BINARY: case EXPR_BITASSIGN: @@ -90,36 +91,26 @@ bool expr_may_addr(Expr *expr) case EXPR_CALL: case EXPR_CAST: case EXPR_CATCH_UNWRAP: - case EXPR_COMPILER_CONST: case EXPR_COMPOUND_LITERAL: case EXPR_COND: case EXPR_CONST: - case EXPR_CT_ARG: - case EXPR_CT_CALL: - case EXPR_CT_CHECKS: - case EXPR_CT_EVAL: - case EXPR_CT_IDENT: case EXPR_DECL: case EXPR_DESIGNATED_INITIALIZER_LIST: - case EXPR_DESIGNATOR: case EXPR_EXPRESSION_LIST: + case EXPR_INITIALIZER_LIST: case EXPR_EXPR_BLOCK: case EXPR_OPTIONAL: case EXPR_FORCE_UNWRAP: - case EXPR_HASH_IDENT: - case EXPR_INITIALIZER_LIST: case EXPR_MACRO_BLOCK: case EXPR_MACRO_BODY_EXPANSION: case EXPR_NOP: case EXPR_OPERATOR_CHARS: case EXPR_POINTER_OFFSET: - case EXPR_POISONED: case EXPR_POST_UNARY: case EXPR_RETHROW: case EXPR_RETVAL: case EXPR_SLICE_ASSIGN: case EXPR_SLICE_COPY: - case EXPR_STRINGIFY: case EXPR_SUBSCRIPT_ADDR: case EXPR_SUBSCRIPT_ASSIGN: case EXPR_TERNARY: @@ -127,9 +118,7 @@ bool expr_may_addr(Expr *expr) case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TYPEID: case EXPR_TYPEID_INFO: - case EXPR_TYPEINFO: case EXPR_ANY: - case EXPR_ANYSWITCH: case EXPR_VASPLAT: case EXPR_SWIZZLE: case EXPR_LAMBDA: @@ -203,6 +192,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_OPERATOR_CHARS: case EXPR_STRINGIFY: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: case EXPR_LAMBDA: case EXPR_EMBED: return true; @@ -664,6 +654,7 @@ bool expr_is_pure(Expr *expr) case EXPR_CT_ARG: case EXPR_OPERATOR_CHARS: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: case EXPR_LAMBDA: case EXPR_EMBED: return true; diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 82eb4d0ba..8a72b2997 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -1032,6 +1032,17 @@ static Expr *parse_ct_eval(ParseContext *c, Expr *left) return expr; } +static Expr *parse_ct_defined(ParseContext *c, Expr *left) +{ + assert(!left && "Unexpected left hand side"); + Expr *defined = expr_new(EXPR_CT_DEFINED, c->span); + advance(c); + CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr); + ASSIGN_EXPR_OR_RET(defined->inner_expr, parse_expr(c), poisoned_expr); + CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr); + return defined; + +} /** * ct_sizeof ::= CT_SIZEOF '(' expr ')' * @@ -1093,7 +1104,7 @@ static Expr *parse_ct_embed(ParseContext *c, Expr *left) } /** - * ct_call ::= (ALIGNOF | DEFINED | EXTNAMEOF | OFFSETOF | NAMEOF | QNAMEOF) '(' flat_path ')' + * ct_call ::= (ALIGNOF | EXTNAMEOF | OFFSETOF | NAMEOF | QNAMEOF) '(' flat_path ')' * flat_path ::= expr ('.' primary) | '[' expr ']')* */ static Expr *parse_ct_call(ParseContext *c, Expr *left) @@ -1894,7 +1905,7 @@ ParseRule rules[TOKEN_EOF + 1] = { [TOKEN_FN] = { parse_lambda, NULL, PREC_NONE }, [TOKEN_CT_SIZEOF] = { parse_ct_sizeof, NULL, PREC_NONE }, [TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE }, - [TOKEN_CT_DEFINED] = { parse_ct_call, NULL, PREC_NONE }, + [TOKEN_CT_DEFINED] = { parse_ct_defined, NULL, PREC_NONE }, [TOKEN_CT_CHECKS] = { parse_ct_checks, NULL, PREC_NONE }, [TOKEN_CT_EMBED] = { parse_ct_embed, NULL, PREC_NONE }, [TOKEN_CT_EVAL] = { parse_ct_eval, NULL, PREC_NONE }, diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 1f8b6c687..f2b154b83 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -483,6 +483,7 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr) case EXPR_CT_ARG: case EXPR_CT_CALL: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: case EXPR_CT_EVAL: case EXPR_DECL: case EXPR_DESIGNATED_INITIALIZER_LIST: @@ -594,6 +595,7 @@ static bool expr_may_ref(Expr *expr) case EXPR_CT_ARG: case EXPR_CT_CALL: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: case EXPR_CT_EVAL: case EXPR_DECL: case EXPR_DESIGNATED_INITIALIZER_LIST: @@ -6788,7 +6790,7 @@ RETRY: case TYPE_INFO_POISON: return poisoned_type; case TYPE_INFO_GENERIC: - TODO + return poisoned_type; case TYPE_INFO_VECTOR: { ArraySize size; @@ -6820,6 +6822,7 @@ RETRY: Decl *decl = sema_find_path_symbol(context, type_info->unresolved.name, type_info->unresolved.path); if (!decl) return NULL; if (!decl_ok(decl)) return poisoned_type; + if (type_info->kind == TYPE_INFO_CT_IDENTIFIER) return decl->var.init_expr->type_expr->type->canonical; return decl->type->canonical; } case TYPE_INFO_VATYPE: @@ -7224,9 +7227,15 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr { if (expr->resolve_status == RESOLVE_DONE) return expr_ok(expr); - Expr *main_var = expr->ct_call_expr.main_var; - Type *type = NULL; - Decl *decl = NULL; + Expr *inner = expr->inner_expr; + + Expr *main_var = inner; + while (main_var->expr_kind == EXPR_ACCESS) + { + main_var = main_var->access_expr.parent; + } + + Decl *decl; RETRY: switch (main_var->expr_kind) { @@ -7237,51 +7246,46 @@ RETRY: if (!decl_ok(decl)) return false; // 2b. If it's missing, goto not defined if (!decl) goto NOT_DEFINED; - type = decl->type; break; case EXPR_COMPILER_CONST: if (!sema_expr_analyse_compiler_const(context, main_var, false)) goto NOT_DEFINED; break; case EXPR_TYPEINFO: { - type = sema_expr_check_type_exists(context, main_var->type_expr); + Type *type = sema_expr_check_type_exists(context, main_var->type_expr); if (!type) goto NOT_DEFINED; if (!type_ok(type)) return false; + main_var->type_expr = type_info_new_base(type, main_var->span); break; } case EXPR_BUILTIN: if (!sema_expr_analyse_builtin(context, main_var, false)) goto NOT_DEFINED; break; case EXPR_CT_EVAL: - main_var = sema_ct_eval_expr(context, "$eval", main_var->inner_expr, false); - if (!main_var) goto NOT_DEFINED; + { + Expr *eval = sema_ct_eval_expr(context, "$eval", main_var->inner_expr, false); + if (!eval) goto NOT_DEFINED; + expr_replace(main_var, eval); goto RETRY; + } default: SEMA_ERROR(main_var, "Expected an identifier here."); return false; } - - FOREACH_BEGIN_IDX(i, DesignatorElement *element, expr->ct_call_expr.flat_path) - Decl *member = NULL; - ArraySize index; - Type *ret_type; - bool missing = false; - if (!sema_expr_analyse_decl_element(context, - element, - type, - &member, - &index, - &ret_type, - i, - i == 0 ? main_var->span : expr->span, - &missing)) - { - if (missing) goto NOT_DEFINED; - return false; - } - type = ret_type; - FOREACH_END(); - + if (main_var != inner) + { + bool suppress_error = global_context.suppress_errors; + global_context.suppress_errors = true; + CallEnvKind eval_kind = context->call_env.kind; + context->call_env.kind = CALL_ENV_CHECKS; + bool success; + SCOPE_START_WITH_FLAGS(SCOPE_CHECKS); + success = sema_analyse_expr_lvalue(context, inner); + SCOPE_END; + context->call_env.kind = eval_kind; + global_context.suppress_errors = suppress_error; + if (!success) goto NOT_DEFINED; + } expr_rewrite_const_bool(expr, type_bool, true); return true; @@ -7588,6 +7592,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) return sema_expr_analyse_generic_ident(context, expr); case EXPR_LAMBDA: return sema_expr_analyse_lambda(context, NULL, expr); + case EXPR_CT_DEFINED: + return sema_expr_analyse_ct_defined(context, expr); case EXPR_CT_CHECKS: return sema_expr_analyse_ct_checks(context, expr); case EXPR_CT_ARG: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 84984d528..0d886a370 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -253,6 +253,7 @@ RETRY: case EXPR_CT_ARG: case EXPR_CT_CALL: case EXPR_CT_CHECKS: + case EXPR_CT_DEFINED: case EXPR_CT_EVAL: case EXPR_CT_IDENT: case EXPR_ANYSWITCH: diff --git a/src/compiler/types.c b/src/compiler/types.c index a68aadb6d..72fc9c9ad 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -991,6 +991,7 @@ bool type_is_user_defined(Type *type) case TYPE_UNION: case TYPE_FAULTTYPE: case TYPE_DISTINCT: + case TYPE_BITSTRUCT: return true; case TYPE_TYPEDEF: return type->decl != NULL; diff --git a/src/version.h b/src/version.h index d69cf501c..e9366a010 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.578" \ No newline at end of file +#define COMPILER_VERSION "0.4.579" \ No newline at end of file diff --git a/test/test_suite/compile_time_introspection/defined_2.c3t b/test/test_suite/compile_time_introspection/defined_2.c3t new file mode 100644 index 000000000..522118028 --- /dev/null +++ b/test/test_suite/compile_time_introspection/defined_2.c3t @@ -0,0 +1,41 @@ +module testing; +import std::io; + +fn void! main() +{ + Bits b1; + Bits b2; + bool x = equals(b1, b2); +} + +bitstruct Bits : char +{ + bool flag; +} + +fn bool Bits.equals(a, Bits b) +{ + return a.flag == b.flag; +} + +/* #expect: testing.ll + +define i64 @testing.main() #0 { +entry: + %b1 = alloca i8, align 1 + %b2 = alloca i8, align 1 + %x = alloca i8, align 1 + %a = alloca i8, align 1 + %b = alloca i8, align 1 + store i8 0, ptr %b1, align 1 + store i8 0, ptr %b2, align 1 + %0 = load i8, ptr %b1, align 1 + store i8 %0, ptr %a, align 1 + %1 = load i8, ptr %b2, align 1 + store i8 %1, ptr %b, align 1 + %2 = load i8, ptr %a, align 1 + %3 = load i8, ptr %b, align 1 + %4 = call i8 @testing.Bits.equals(i8 zeroext %2, i8 zeroext %3) + store i8 %4, ptr %x, align 1 + ret i64 0 +} \ No newline at end of file