From da475885023f66115de514b2777a444a4e15c453 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 25 Sep 2024 14:26:49 +0200 Subject: [PATCH] Make methods be available in earlier stages of analysis. Add `@adhoc` attribute to allow types with ad hoc generic declarations. --- lib/std/collections/maybe.c3 | 2 +- lib/std/collections/tuple.c3 | 4 +- releasenotes.md | 3 +- src/compiler/compiler_internal.h | 3 + src/compiler/context.c | 5 +- src/compiler/enums.h | 14 ++- src/compiler/sema_decls.c | 111 ++++++++++++------- src/compiler/sema_expr.c | 7 +- src/compiler/sema_internal.h | 1 + src/compiler/sema_passes.c | 28 ++++- src/compiler/sema_types.c | 18 ++- src/compiler/semantic_analyser.c | 11 ++ src/compiler/symtab.c | 1 + test/test_suite/methods/operator_mismatch.c3 | 8 +- 14 files changed, 150 insertions(+), 66 deletions(-) diff --git a/lib/std/collections/maybe.c3 b/lib/std/collections/maybe.c3 index 9e51c3e70..a6a3067f3 100644 --- a/lib/std/collections/maybe.c3 +++ b/lib/std/collections/maybe.c3 @@ -1,6 +1,6 @@ module std::collections::maybe(); -struct Maybe +struct Maybe @adhoc { Type value; bool has_value; diff --git a/lib/std/collections/tuple.c3 b/lib/std/collections/tuple.c3 index efe59854d..a35eb3a41 100644 --- a/lib/std/collections/tuple.c3 +++ b/lib/std/collections/tuple.c3 @@ -1,6 +1,6 @@ module std::collections::tuple(); -struct Tuple @deprecated +struct Tuple @adhoc { Type1 first; Type2 second; @@ -8,7 +8,7 @@ struct Tuple @deprecated module std::collections::triple(); -struct Triple @deprecated +struct Triple @adhoc { Type1 first; Type2 second; diff --git a/releasenotes.md b/releasenotes.md index 57ff42192..2668bad3a 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -23,11 +23,12 @@ - Allow the "self" parameter to be $/# for macro methods. - Support compile time slicing of untyped lists. - Allow specifying an import module using `@wasm` #1305. +- Deprecated inline generic types outside of struct definitions and macros unless marked `@adhoc`. +- Improved method detection in earlier stages of checking. ### Fixes - Issue where a lambda wasn't correctly registered as external. #1408 - Generic methods were incorrectly registered as functions, leading to naming collisions. #1402 -- Deprecated inline generic types outside of struct definitions and macros. - Deprecated tuple / triple types. - Converting a slice to a vector/array would copy too little data. - Crash when reading an empty 'manifest.json'. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index fd1c5bd4c..46d123eeb 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -600,6 +600,7 @@ typedef struct Decl_ bool no_strip : 1; bool is_cond : 1; bool is_if : 1; + bool is_adhoc : 1; bool attr_nopadding : 1; bool attr_compact : 1; bool resolved_attributes : 1; @@ -1604,6 +1605,7 @@ struct CompilationUnit_ Decl **ct_includes; Decl **vars; Decl **macros; + Decl **methods_to_register; Decl **methods; Decl **macro_methods; Decl **global_decls; @@ -2273,6 +2275,7 @@ bool sema_cast_const(Expr *expr); bool sema_expr_check_discard(SemaContext *context, Expr *expr); bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr); bool sema_analyse_decl(SemaContext *context, Decl *decl); +bool sema_analyse_method_register(SemaContext *context, Decl *method); bool sema_resolve_type_structure(SemaContext *context, Type *type, SourceSpan span); bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl); bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local); diff --git a/src/compiler/context.c b/src/compiler/context.c index 8d01b5300..8c39765b7 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -181,7 +181,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) assert(decl->name); if (decl->func_decl.type_parent) { - vec_add(unit->macro_methods, decl); + vec_add(unit->methods_to_register, decl); return; } else @@ -194,7 +194,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) assert(decl->name); if (decl->func_decl.type_parent) { - vec_add(unit->methods, decl); + vec_add(unit->methods_to_register, decl); return; } else @@ -233,7 +233,6 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) vec_add(unit->attributes, decl); decl_register(decl); break; - case DECL_FAULTVALUE: case DECL_ENUM_CONSTANT: case DECL_IMPORT: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 2b1d2e96b..9df1c836d 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -46,9 +46,13 @@ typedef enum ANALYSIS_MODULE_TOP, ANALYSIS_IMPORTS, ANALYSIS_REGISTER_GLOBAL_DECLARATIONS, + ANALYSIS_METHODS_REGISTER, ANALYSIS_INCLUDES, + ANALYSIS_METHODS_INCLUDES, ANALYSIS_REGISTER_CONDITIONAL_UNITS, ANALYSIS_REGISTER_CONDITIONAL_DECLARATIONS, + ANALYSIS_METHODS_CONDITIONAL, + ANALYSIS_POST_REGISTER, ANALYSIS_DECLS, ANALYSIS_CT_ECHO, ANALYSIS_CT_ASSERT, @@ -250,6 +254,7 @@ typedef enum FLAG_ATTR typedef enum { + ATTRIBUTE_ADHOC, ATTRIBUTE_ALIGN, ATTRIBUTE_BENCHMARK, ATTRIBUTE_BIGENDIAN, @@ -988,10 +993,11 @@ typedef enum typedef enum { RESOLVE_TYPE_DEFAULT, - RESOLVE_TYPE_ALLOW_INFER = 0x01, - RESOLVE_TYPE_ALLOW_FLEXIBLE = 0x02, - RESOLVE_TYPE_MACRO_METHOD = RESOLVE_TYPE_ALLOW_INFER, - RESOLVE_TYPE_FUNC_METHOD = RESOLVE_TYPE_DEFAULT + RESOLVE_TYPE_ALLOW_INFER = 0x01, + RESOLVE_TYPE_ALLOW_FLEXIBLE = 0x02, + RESOLVE_TYPE_NO_CHECK_DISTINCT = 0x04, + RESOLVE_TYPE_MACRO_METHOD = RESOLVE_TYPE_ALLOW_INFER | RESOLVE_TYPE_NO_CHECK_DISTINCT, + RESOLVE_TYPE_FUNC_METHOD = RESOLVE_TYPE_NO_CHECK_DISTINCT, } ResolveTypeKind; typedef enum FLAG_ATTR diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index b83f13890..86ad0f155 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1780,15 +1780,6 @@ INLINE SourceSpan method_find_overload_span(Decl *method) static inline bool unit_add_base_extension_method(SemaContext *context, CompilationUnit *unit, Type *parent_type, Decl *method) { - // We don't support operator overloading on base types, because - // there seems little use for it frankly. - if (method->operator) - { - sema_error_at(context, method_find_overload_span(method), - "Only user-defined types support operator oveloading."); - return false; - } - // Add it to the right list of extensions. switch (method->visibility) { @@ -1841,10 +1832,20 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type // Check it's valid for the operator type. if (!sema_check_operator_method_validity(context, method)) return false; + // We don't support operator overloading on base types, because + // there seems little use for it frankly. + if (!type_is_user_defined(parent_type)) + { + sema_error_at(context, method_find_overload_span(method), + "Only user-defined types support operator oveloading."); + return false; + } + // See if the operator has already been defined. OperatorOverload operator = method->operator; + Decl *other = sema_find_operator(context, parent_type, operator); - if (other) + if (other != method) { SourceSpan span = method_find_overload_span(method); sema_error_at(context, span, "This operator is already defined for '%s'.", parent_type->name); @@ -1920,6 +1921,11 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type // So compare the value if (this_value != value) { + if (operator == OVERLOAD_ELEMENT_REF) + { + value = type_get_ptr(value); + this_value = type_get_ptr(this_value); + } SEMA_ERROR(method, "There is a mismatch of the 'value' type compared to that of another operator: expected %s but got %s.", type_quoted_error_string(value), type_quoted_error_string(this_value)); SEMA_NOTE(other, "The other definition is here."); @@ -1966,6 +1972,7 @@ static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl return false; } + // Is it a base extension? if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(context, unit, parent_type, method); @@ -1984,12 +1991,6 @@ static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl return false; } - // Is it an operator? - if (method->operator) - { - if (!sema_analyse_operator_method(context, parent_type, method)) return false; - } - DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method->name); // Add it to the correct place: type methods, private extensions, local method extensions @@ -2178,13 +2179,12 @@ static inline bool sema_compare_method_with_interface(SemaContext *context, Decl * * 1. Check that it has no init/finalizer attributes. * 2. Check that it has no test/benchmark attributes. - * 3. Resolve the parent type. - * 4. Resolve the declaration of the parent (as needed). - * 5. Check that it has at least one parameter. - * 6. Check that this parameter is correct. - * 7. If it is dynamic, the type may not be an interface or any - * 8. If it is dynamic, make sure that it implements an interface correctly if available - * 9. Try adding the method + * 3. Resolve the declaration of the parent (as needed). + * 4. Check that it has at least one parameter. + * 5. Check that this parameter is correct. + * 6. If it is dynamic, the type may not be an interface or any + * 7. If it is dynamic, make sure that it implements an interface correctly if available + * 8. Try adding the method */ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) { @@ -2202,7 +2202,7 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) // Resolve the parent type. TypeInfo *parent_type = type_infoptr(decl->func_decl.type_parent); - if (!sema_resolve_type_info(context, parent_type, RESOLVE_TYPE_FUNC_METHOD)) return false; + assert(parent_type->resolve_status == RESOLVE_DONE); Type *par_type = parent_type->type->canonical; // Resolve declaration of parent as needed. @@ -2245,7 +2245,13 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) decl->func_decl.interface_method = 0; } } - return unit_add_method(context, par_type, decl); + // Is it an operator? + if (decl->operator) + { + if (!sema_analyse_operator_method(context, par_type, decl)) return false; + } + + return true; } static const char *attribute_domain_to_string(AttributeDomain domain) @@ -2363,6 +2369,7 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_ assert(type >= 0 && type < NUMBER_OF_ATTRIBUTES); // NOLINTBEGIN(*.EnumCastOutOfRange) static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = { + [ATTRIBUTE_ADHOC] = USER_DEFINED_TYPES, [ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_BITSTRUCT | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER, // NOLINT [ATTRIBUTE_BENCHMARK] = ATTR_FUNC, [ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT, @@ -2526,6 +2533,9 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_ FAILED_OP_TYPE: RETURN_SEMA_ERROR(attr, "'operator' requires an operator type argument: '[]', '[]=', '&[]' or 'len'."); } + case ATTRIBUTE_ADHOC: + decl->is_adhoc = true; + return true; case ATTRIBUTE_ALIGN: if (!expr) { @@ -3462,20 +3472,8 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl) { // Resolve the type of the method. TypeInfo *parent_type_info = type_infoptr(decl->func_decl.type_parent); - if (!sema_resolve_type_info(context, parent_type_info, RESOLVE_TYPE_MACRO_METHOD)) return false; - - // Can the type have methods? - Type *parent_type = parent_type_info->type; - if (!type_may_have_method(parent_type)) - { - RETURN_SEMA_ERROR(parent_type_info, "Methods can not be associated with '%s'", type_to_error_string(parent_type)); - } - - // We need at least one argument (the parent type) - if (!vec_size(decl->func_decl.signature.params)) - { - RETURN_SEMA_ERROR(decl, "Expected at least one parameter - of type '%s'.", type_to_error_string(parent_type)); - } + assert(parent_type_info->resolve_status == RESOLVE_DONE); + Type *parent_type = parent_type_info->type->canonical; // Check the first argument. Decl *first_param = decl->func_decl.signature.params[0]; @@ -3484,13 +3482,19 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl) RETURN_SEMA_ERROR(decl, "The first parameter to this method must be of type '%s'.", type_to_error_string(parent_type)); return false; } - if (!sema_is_valid_method_param(context, first_param, parent_type->canonical, false)) return false; + if (!sema_is_valid_method_param(context, first_param, parent_type, false)) return false; if (first_param->var.kind != VARDECL_PARAM_EXPR && first_param->var.kind != VARDECL_PARAM_CT && first_param->var.kind != VARDECL_PARAM_REF && first_param->var.kind != VARDECL_PARAM) { RETURN_SEMA_ERROR(first_param, "The first parameter must be a compile time, regular or ref (&) type."); } - return unit_add_method(context, parent_type->canonical, decl); + // Is it an operator? + if (decl->operator) + { + if (!sema_analyse_operator_method(context, parent_type, decl)) return false; + } + + return true; } INLINE bool sema_analyse_macro_body(SemaContext *context, Decl **body_parameters) @@ -4408,6 +4412,31 @@ bool sema_resolve_type_structure(SemaContext *context, Type *type, SourceSpan sp UNREACHABLE } +bool sema_analyse_method_register(SemaContext *context, Decl *method) +{ + TypeInfo *parent_type_info = type_infoptr(method->func_decl.type_parent); + if (!sema_resolve_type_info(context, parent_type_info, method->decl_kind == DECL_MACRO ? RESOLVE_TYPE_MACRO_METHOD : RESOLVE_TYPE_FUNC_METHOD)) return false; + + // Can the type have methods? + Type *parent_type = parent_type_info->type; + if (!type_may_have_method(parent_type)) + { + RETURN_SEMA_ERROR(parent_type_info, "Methods can not be associated with '%s'", type_to_error_string(parent_type)); + } + + // We need at least one argument (the parent type) + if (!vec_size(method->func_decl.signature.params)) + { + RETURN_SEMA_ERROR(method, "Expected at least one parameter - of type '%s'.", type_to_error_string(parent_type)); + } + + // Check the first argument. + Decl *first_param = method->func_decl.signature.params[0]; + if (!first_param) RETURN_SEMA_ERROR(method, "The first parameter to this method must be of type '%s'.", type_to_error_string(parent_type)); + + return unit_add_method(context, parent_type->canonical, method); +} + bool sema_analyse_decl(SemaContext *context, Decl *decl) { if (decl->resolve_status == RESOLVE_DONE) return decl_ok(decl); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 6f87d0494..bf9249d1e 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2129,7 +2129,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s type_quoted_error_string(type_get_ptr(type_info->type))); } body_arg->type = type; - if (type_info && type_storage_type(type_info->type)) + if (type_info && type_storage_type(type_info->type) == STORAGE_NORMAL) { if (!sema_set_alloca_alignment(context, body_arg->type, &body_arg->alignment)) return false; } @@ -3547,6 +3547,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp UNREACHABLE } + Decl *member = sema_decl_stack_find_decl_member(context, decl, name); if (!decl_ok(member)) return false; if (!member) @@ -4507,10 +4508,6 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, return true; } case TYPE_PROPERTY_METHODSOF: - if (context->compilation_unit->module->stage <= ANALYSIS_DECLS) - { - RETURN_SEMA_ERROR(expr, "'methodsof' is not available until after declaration analysis is complete."); - } sema_create_const_methodsof(context, expr, flat); return true; case TYPE_PROPERTY_PARAMSOF: diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index a47d01d54..4263d759a 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -76,6 +76,7 @@ void sema_analysis_pass_register_global_declarations(Module *module); void sema_analysis_pass_process_includes(Module *module); void sema_analysis_pass_register_conditional_units(Module *module); void sema_analysis_pass_register_conditional_declarations(Module *module); +void sema_analysis_pass_process_methods(Module *module); void sema_analysis_pass_decls(Module *module); void sema_analysis_pass_ct_assert(Module *module); void sema_analysis_pass_ct_echo(Module *module); diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 1242f40ce..fce96ec4c 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -367,7 +367,6 @@ void sema_analysis_pass_register_global_declarations(Module *module) DEBUG_LOG("Processing %s.", unit->file->name); register_global_decls(unit, unit->global_decls); } - DEBUG_LOG("Pass finished with %d error(s).", compiler.context.errors_found); } @@ -385,6 +384,33 @@ void sema_analysis_pass_process_includes(Module *module) DEBUG_LOG("Pass finished with %d error(s).", compiler.context.errors_found); } + +void sema_analysis_pass_process_methods(Module *module) +{ + DEBUG_LOG("Pass: Process methods register for module '%s'.", module->name->module); + FOREACH(CompilationUnit *, unit, module->units) + { + SemaContext context; + sema_context_init(&context, unit); + FOREACH(Decl *, method, unit->methods_to_register) + { + sema_analyse_method_register(&context, method); + if (method->decl_kind == DECL_MACRO) + { + vec_add(unit->macro_methods, method); + } + else + { + vec_add(unit->methods, method); + } + } + sema_context_destroy(&context); + vec_resize(unit->methods_to_register, 0); + } + + DEBUG_LOG("Pass finished with %d error(s).", compiler.context.errors_found); +} + void sema_analysis_pass_register_conditional_units(Module *module) { DEBUG_LOG("Pass: Register conditional units for %s", module->name->module); diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 211b49ee3..988ce5764 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -192,7 +192,7 @@ static inline bool sema_resolve_array_type(SemaContext *context, TypeInfo *type, } -static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_info) +static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_info, ResolveTypeKind resolve_type_kind) { if (type_info->unresolved.name == type_string->name && !type_info->unresolved.path) { @@ -224,8 +224,15 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; return true; - case DECL_TYPEDEF: case DECL_DISTINCT: + if (resolve_type_kind & RESOLVE_TYPE_NO_CHECK_DISTINCT) + { + type_info->type = decl->type; + type_info->resolve_status = RESOLVE_DONE; + return true; + } + FALLTHROUGH; + case DECL_TYPEDEF: if (!sema_analyse_decl(context, decl)) return type_info_poison(type_info); type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; @@ -361,10 +368,11 @@ INLINE bool sema_resolve_generic_type(SemaContext *context, TypeInfo *type_info) Decl *type = sema_analyse_parameterized_identifier(context, inner->unresolved.path, inner->unresolved.name, inner->span, type_info->generic.params); if (!decl_ok(type)) return false; type_info->type = type->type; - if (!context->current_macro && (context->call_env.kind == CALL_ENV_FUNCTION || context->call_env.kind == CALL_ENV_FUNCTION_STATIC) + if (!type->is_adhoc && !context->current_macro && (context->call_env.kind == CALL_ENV_FUNCTION || context->call_env.kind == CALL_ENV_FUNCTION_STATIC) && !context->call_env.current_function->func_decl.in_macro) { - SEMA_DEPRECATED(type_info, "Direct generic type declarations outside of macros and type declarations is a deprecated feature, please use 'def' to create an alias."); + + SEMA_DEPRECATED(type_info, "Direct generic type declarations not marked '@adhoc' outside of macros and type declarations is a deprecated feature, please use 'def' to create an alias."); // TODO, completely disallow // RETURN_SEMA_ERROR(type_info, "Direct generic type declarations are only allowed inside of macros. Use `def` to define an alias for the type instead."); } @@ -411,7 +419,7 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info, case TYPE_INFO_CT_IDENTIFIER: case TYPE_INFO_IDENTIFIER: // $Type or Foo - if (!sema_resolve_type_identifier(context, type_info)) return type_info_poison(type_info); + if (!sema_resolve_type_identifier(context, type_info, resolve_type_kind)) return type_info_poison(type_info); goto APPEND_QUALIFIERS; case TYPE_INFO_EVALTYPE: if (!sema_resolve_evaltype(context, type_info, resolve_type_kind)) return type_info_poison(type_info); diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index a91b66df2..ccc0b7a26 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -158,15 +158,26 @@ void sema_analyze_stage(Module *module, AnalysisStage stage) case ANALYSIS_REGISTER_GLOBAL_DECLARATIONS: sema_analysis_pass_register_global_declarations(module); break; + case ANALYSIS_METHODS_REGISTER: + sema_analysis_pass_process_methods(module); + break; case ANALYSIS_INCLUDES: sema_analysis_pass_process_includes(module); break; + case ANALYSIS_METHODS_INCLUDES: + sema_analysis_pass_process_methods(module); + break; case ANALYSIS_REGISTER_CONDITIONAL_UNITS: sema_analysis_pass_register_conditional_units(module); break; case ANALYSIS_REGISTER_CONDITIONAL_DECLARATIONS: sema_analysis_pass_register_conditional_declarations(module); break; + case ANALYSIS_METHODS_CONDITIONAL: + sema_analysis_pass_process_methods(module); + break; + case ANALYSIS_POST_REGISTER: + break; case ANALYSIS_DECLS: sema_analysis_pass_decls(module); break; diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index d94c833ef..54cf6ea75 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -312,6 +312,7 @@ void symtab_init(uint32_t capacity) kw_at_require = KW_DEF("@require"); kw_at_return = KW_DEF("@return"); kw_at_jump = KW_DEF("@jump"); + attribute_list[ATTRIBUTE_ADHOC] = KW_DEF("@adhoc"); attribute_list[ATTRIBUTE_ALIGN] = KW_DEF("@align"); attribute_list[ATTRIBUTE_BENCHMARK] = KW_DEF("@benchmark"); attribute_list[ATTRIBUTE_BIGENDIAN] = KW_DEF("@bigendian"); diff --git a/test/test_suite/methods/operator_mismatch.c3 b/test/test_suite/methods/operator_mismatch.c3 index a73b9a308..d0f96160b 100644 --- a/test/test_suite/methods/operator_mismatch.c3 +++ b/test/test_suite/methods/operator_mismatch.c3 @@ -1,10 +1,12 @@ struct Foo { int a; } +struct Foo2 { int a; } struct Bar { int a; } fn int Foo.x(&self, int x) @operator([]) => 1; -fn int Foo.y(&self, int x) @operator(&[]) => 1; // #error: The return type must be a pointer -fn int** Foo.y2(&self, int x) @operator(&[]) => null; // #error: There is a mismatch of the 'value' type -fn void Foo.z(&self, uint x, int a) @operator([]=) {} // #error: There is a mismatch of the 'index' +fn int Foo.y(&self, int x) @operator(&[]) => 1; // #error: The return type must be a pointer +fn int Foo2.y(&self, int x) @operator([]) => null; +fn int** Foo2.y2(&self, int x) @operator(&[]) => null; // #error: There is a mismatch of the 'value' type +fn void Foo.z(&self, uint x, int a) @operator([]=) {} // #error: There is a mismatch of the 'index' fn double Bar.x(&self, int x) @operator([]) => 0.1; fn void Bar.y(&self, int x, float y) @operator([]=) {} // #error: There is a mismatch of the 'value'