diff --git a/releasenotes.md b/releasenotes.md index c0f62b31f..5dc191476 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Removed `@adhoc` attribute. - Disallow inline use of nested generics (e.g. `List{List{int}}`. - Remove `.allocator = allocator` syntax for functions. +- Remove `@operator(construct)`. ## 0.6.8 Change list diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 164fe2bd6..eefc8223b 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -1,13 +1,9 @@ + module test; import libc; import std::io; import std::collections::maybe; -def MaybeString = Maybe{String}; -def MaybeHead = Maybe{Head}; -def new_head_val = maybe::value{Head}; -def new_string_val = maybe::value{String}; - fault TitleResult { TITLE_MISSING @@ -18,16 +14,23 @@ fault ReadError BAD_READ, } -struct Doc { MaybeHead head; } -struct Head { MaybeString title; } +struct Doc +{ + Maybe { Head } head; +} + +struct Head +{ + Maybe { String } title; +} struct Summary { - MaybeString title; + Maybe { String } title; bool ok; } -fn void! Summary.print(Summary *s, OutStream out) +fn void! Summary.print(Summary* s, OutStream out) { io::fprintf(out, "Summary({ .title = %s, .ok = %s})", s.title.get() ?? "missing", s.ok)!; } @@ -36,22 +39,22 @@ fn Doc! read_doc(String url) { if (url.contains("fail")) return ReadError.BAD_READ?; if (url.contains("head-missing")) return { }; - if (url.contains("title-missing")) return { .head = new_head_val({}) }; - if (url.contains("title-empty")) return { .head = new_head_val({ .title = new_string_val("")}) }; - return { .head = new_head_val({ .title = new_string_val(string::new_format("Title of %s", url)) }) }; + if (url.contains("title-missing")) return { .head = maybe::value{Head}({}) }; + if (url.contains("title-empty")) return { .head = maybe::value{Head}({ .title = maybe::value{String}("")}) }; + return { .head = maybe::value{Head}({ .title = maybe::value{String}(string::format(mem, "Title of %s", url)) }) }; } fn Summary build_summary(Doc doc) { - return Summary { - .title = new_string_val(doc.head.get().title.get()) ?? MaybeString {}, + return { + .title = maybe::value{String}(doc.head.get().title.get()) ?? {}, .ok = true, }; } fn Summary read_and_build_summary(String url) { - return build_summary(read_doc(url)) ?? Summary {}; + return build_summary(read_doc(url)) ?? {}; } fn bool! is_title_non_empty(Doc doc) diff --git a/resources/examples/contextfree/boolerr7.c3 b/resources/examples/contextfree/boolerr7.c3 deleted file mode 100644 index eefc8223b..000000000 --- a/resources/examples/contextfree/boolerr7.c3 +++ /dev/null @@ -1,101 +0,0 @@ - -module test; -import libc; -import std::io; -import std::collections::maybe; - -fault TitleResult -{ - TITLE_MISSING -} - -fault ReadError -{ - BAD_READ, -} - -struct Doc -{ - Maybe { Head } head; -} - -struct Head -{ - Maybe { String } title; -} - -struct Summary -{ - Maybe { String } title; - bool ok; -} - -fn void! Summary.print(Summary* s, OutStream out) -{ - io::fprintf(out, "Summary({ .title = %s, .ok = %s})", s.title.get() ?? "missing", s.ok)!; -} - -fn Doc! read_doc(String url) -{ - if (url.contains("fail")) return ReadError.BAD_READ?; - if (url.contains("head-missing")) return { }; - if (url.contains("title-missing")) return { .head = maybe::value{Head}({}) }; - if (url.contains("title-empty")) return { .head = maybe::value{Head}({ .title = maybe::value{String}("")}) }; - return { .head = maybe::value{Head}({ .title = maybe::value{String}(string::format(mem, "Title of %s", url)) }) }; -} - -fn Summary build_summary(Doc doc) -{ - return { - .title = maybe::value{String}(doc.head.get().title.get()) ?? {}, - .ok = true, - }; -} - -fn Summary read_and_build_summary(String url) -{ - return build_summary(read_doc(url)) ?? {}; -} - -fn bool! is_title_non_empty(Doc doc) -{ - String! title = doc.head.get().title.get(); - if (catch title) return TitleResult.TITLE_MISSING?; - return title.len > 0; -} - -fn bool! read_whether_title_non_empty(String url) -{ - return is_title_non_empty(read_doc(url)); -} - -fn String bool_to_string(bool b) -{ - return b ? "true" : "false"; -} - -fn void main() -{ - const String[] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" }; - DynamicArenaAllocator dynamic_arena; - dynamic_arena.init(1024, allocator::heap()); - OutStream out = io::stdout(); - foreach (String url : URLS) - { - mem::@scoped(&dynamic_arena) - { - io::printf(`Checking "https://%s/":` "\n", url); - Summary summary = read_and_build_summary(url); - io::fprintf(out, " Summary: ")!!; - summary.print(out)!!; - io::fprintn(out, "")!!; - io::fprintf(out, " Title: %s\n", summary.title.get() ?? "")!!; - bool! has_title = read_whether_title_non_empty(url); - // This looks a bit less than elegant, but as you see it's mostly due to having to - // use printf here. - io::fprintf(out, " Has title: %s vs %s\n", bool_to_string(has_title) ?? (@catch(has_title)).nameof, has_title ?? false)!!; - }; - dynamic_arena.reset(); - } - dynamic_arena.free(); -} diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 178dac4b1..15e0fb59d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1916,7 +1916,6 @@ extern const char *kw_at_pure; extern const char *kw_at_require; extern const char *kw_at_return; extern const char *kw_at_jump; -extern const char *kw_construct; extern const char *kw_in; extern const char *kw_inout; extern const char *kw_len; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index ade557a4e..a82c20e67 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -902,7 +902,6 @@ typedef enum OVERLOAD_ELEMENT_REF, OVERLOAD_ELEMENT_SET, OVERLOAD_LEN, - OVERLOAD_CONSTRUCT, } OperatorOverload; typedef enum diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 8f4d68ec6..93624e188 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1180,7 +1180,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, } // Ensure it has at least one parameter if method. - if (method_parent && !vec_size(params) && decl->operator != OVERLOAD_CONSTRUCT) + if (method_parent && !vec_size(params)) { RETURN_SEMA_ERROR(decl, "A method must start with an argument of the type " "it is a method of, e.g. 'fn void %s.%s(%s* self)', " @@ -1702,33 +1702,6 @@ Decl *sema_find_operator(SemaContext *context, Type *type, OperatorOverload oper return NULL; } -static inline bool sema_analyse_operator_construct(SemaContext *context, Decl *method) -{ - Signature *signature = &method->func_decl.signature; - Decl **params = signature->params; - uint32_t param_count = vec_size(params); - if (param_count && params[0] && params[0]->var.is_self) - { - RETURN_SEMA_ERROR(method, "'construct' methods cannot have 'self' parameters."); - } - if (!signature->rtype) - { - RETURN_SEMA_ERROR(method, "A 'construct' macro method should always have an explicitly typed return value."); - } - Type *rtype = typeget(signature->rtype)->canonical; - Type *parent = typeget(method->func_decl.type_parent); - if (parent->canonical != rtype && type_get_ptr(parent->canonical) != rtype) - { - RETURN_SEMA_ERROR(type_infoptr(signature->rtype), - "The return type of a 'construct' method must be the method type, or a pointer to it." - " In this case %s or %s was expected.", - type_quoted_error_string(parent), type_quoted_error_string(type_get_ptr(parent))); - } - SEMA_DEPRECATED(method, "'operator(@construct)' is deprecated and will be removed in the next version, prefer using init methods and functions instead."); - return true; -} - - static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *method) { TypeInfo *rtype; @@ -1781,8 +1754,6 @@ static bool sema_check_operator_method_validity(SemaContext *context, Decl *meth { switch (method->operator) { - case OVERLOAD_CONSTRUCT: - return sema_analyse_operator_construct(context, method); case OVERLOAD_ELEMENT_SET: return sema_analyse_operator_element_set(context, method); case OVERLOAD_ELEMENT_AT: @@ -1889,7 +1860,6 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type // See if the operator has already been defined. OperatorOverload operator = method->operator; - if (operator == OVERLOAD_CONSTRUCT) return true; Decl *other = sema_find_operator(context, parent_type, operator); if (other != method) @@ -1956,7 +1926,6 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type break; } return true; - case OVERLOAD_CONSTRUCT: default: UNREACHABLE } @@ -2355,10 +2324,8 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) Decl **params = decl->func_decl.signature.params; bool is_dynamic = decl->func_decl.attr_dynamic; - bool is_constructor = decl->operator == OVERLOAD_CONSTRUCT; - // Ensure that the first parameter is valid. - if (!is_constructor && !sema_is_valid_method_param(context, params[0], par_type, is_dynamic)) return false; + if (!sema_is_valid_method_param(context, params[0], par_type, is_dynamic)) return false; // Make dynamic checks. if (is_dynamic) @@ -2371,10 +2338,6 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl) { RETURN_SEMA_ERROR(decl, "'any' may not implement '@dynamic' methods, only regular methods."); } - if (is_constructor) - { - RETURN_SEMA_ERROR(decl, "A 'construct' method may not be '@dynamic'."); - } // Retrieve the implemented method. Decl *implemented_method = sema_find_interface_for_method(context, par_type, decl); if (!decl_ok(implemented_method)) return false; @@ -2671,11 +2634,6 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_ { case EXPR_UNRESOLVED_IDENTIFIER: if (expr->unresolved_ident_expr.path) goto FAILED_OP_TYPE; - if (expr->unresolved_ident_expr.ident == kw_construct) - { - decl->operator = OVERLOAD_CONSTRUCT; - break; - } if (expr->unresolved_ident_expr.ident != kw_len) goto FAILED_OP_TYPE; decl->operator = OVERLOAD_LEN; break; @@ -3688,19 +3646,17 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl) ASSERT(parent_type_info->resolve_status == RESOLVE_DONE); Type *parent_type = parent_type_info->type->canonical; - bool is_constructor = decl->operator == OVERLOAD_CONSTRUCT; - // Check the first argument. - Decl *first_param = is_constructor ? NULL : decl->func_decl.signature.params[0]; - if (!is_constructor && !first_param) + Decl *first_param = decl->func_decl.signature.params[0]; + if (!first_param) { RETURN_SEMA_ERROR(decl, "The first parameter to this method must be of type %s or %s.", type_quoted_error_string(parent_type), type_quoted_error_string(type_get_ptr(parent_type))); } - if (!is_constructor && !sema_is_valid_method_param(context, first_param, parent_type, false)) return false; + if (!sema_is_valid_method_param(context, first_param, parent_type, false)) return false; - if (!is_constructor && first_param->var.kind != VARDECL_PARAM_EXPR && first_param->var.kind != VARDECL_PARAM_CT && first_param->var.kind != VARDECL_PARAM) + if (first_param->var.kind != VARDECL_PARAM_EXPR && first_param->var.kind != VARDECL_PARAM_CT && first_param->var.kind != VARDECL_PARAM) { RETURN_SEMA_ERROR(first_param, "The first parameter must be a compile time, regular or ref (&) type."); } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index db12af6ba..c68a13ec5 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -47,7 +47,6 @@ const char *kw_at_pure; const char *kw_at_require; const char *kw_at_return; const char *kw_at_jump; -const char *kw_construct; const char *kw_in; const char *kw_inout; const char *kw_len; @@ -134,7 +133,6 @@ void symtab_init(uint32_t capacity) kw_IoError = KW_DEF("IoError"); type = TOKEN_IDENT; - kw_construct = KW_DEF("construct"); kw_in = KW_DEF("in"); kw_inout = KW_DEF("inout"); kw_libc = KW_DEF("libc");