From f13472a8c355856bc8a0f4e9298096529e4971e0 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 27 Nov 2024 00:02:43 +0100 Subject: [PATCH] Contracts on generic modules would evaluate too late, sometimes not catching the error until it already occurred elsewhere. Add `file::save`. --- lib/std/collections/ringbuffer.c3 | 3 +++ lib/std/io/file.c3 | 11 +++++++++++ releasenotes.md | 2 ++ src/compiler/sema_decls.c | 31 +++++++++++++++++-------------- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/std/collections/ringbuffer.c3 b/lib/std/collections/ringbuffer.c3 index 895cfcf5f..38ae9e723 100644 --- a/lib/std/collections/ringbuffer.c3 +++ b/lib/std/collections/ringbuffer.c3 @@ -1,3 +1,6 @@ +<* + @require values::@is_int(SIZE) &&& SIZE > 0 "The size must be positive integer" +*> module std::collections::ringbuffer(); struct RingBuffer diff --git a/lib/std/io/file.c3 b/lib/std/io/file.c3 index 113502825..e0fa77975 100644 --- a/lib/std/io/file.c3 +++ b/lib/std/io/file.c3 @@ -182,6 +182,17 @@ fn char[]! load_temp(String filename) return load_new(filename, allocator::temp()); } +fn void! save(String filename, char[] data) +{ + File file = open(filename, "wb")!; + defer (void)file.close(); + while (data.len) + { + usz written = file.write(data)!; + data = data[written..]; + } +} + <* @require self.file `File must be initialized` *> diff --git a/releasenotes.md b/releasenotes.md index 9db3e0435..08f3becc8 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -24,10 +24,12 @@ - Not possible to alias or take reference for extension methods on non-user defined types. #1637 - Prevent methods from using names of properties or fields. #1638 - b64 / hex data strings can now be used with \` as well. +- Contracts on generic modules would evaluate too late, sometimes not catching the error until it already occurred elsewhere. ### Stdlib changes - Add `io::MultiReader`, `io::MultiWriter`, and `io::TeeReader` structs. - Updated Base32 API. +- Add `file::save`. ## 0.6.4 Change list diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index fe28a0738..43992b159 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4375,10 +4375,13 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con const char *path_string = scratch_buffer_interned(); Module *instantiated_module = global_context_find_module(path_string); - bool was_initiated = false; + AnalysisStage stage = c->unit->module->generic_module + ? c->unit->module->stage + : c->unit->module->stage - 1; + bool instatiation = false; if (!instantiated_module) { - was_initiated = true; + instatiation = true; Path *path = CALLOCS(Path); path->module = path_string; path->span = module->name->span; @@ -4387,14 +4390,7 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con if (!sema_generate_parameterized_name_to_scratch(c, module, params, false, NULL)) return poisoned_decl; if (!instantiated_module) return poisoned_decl; instantiated_module->generic_suffix = scratch_buffer_copy(); - if (c->unit->module->generic_module) - { - sema_analyze_stage(instantiated_module, c->unit->module->stage); - } - else - { - sema_analyze_stage(instantiated_module, c->unit->module->stage - 1); - } + sema_analyze_stage(instantiated_module, stage > ANALYSIS_POST_REGISTER ? ANALYSIS_POST_REGISTER : stage); } if (compiler.context.errors_found) return poisoned_decl; Decl *symbol = module_find_symbol(instantiated_module, name); @@ -4403,12 +4399,19 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con sema_error_at(c, span, "The generic module '%s' does not have '%s' for this parameterization.", module->name->module, name); return poisoned_decl; } - if (was_initiated && instantiated_module->contracts) + if (instatiation) { - SourceSpan error_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span); - if (!sema_analyse_generic_module_contracts(c, instantiated_module, error_span)) + if (instantiated_module->contracts) { - return poisoned_decl; + SourceSpan error_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span); + if (!sema_analyse_generic_module_contracts(c, instantiated_module, error_span)) + { + return poisoned_decl; + } + } + if (stage > ANALYSIS_POST_REGISTER) + { + sema_analyze_stage(instantiated_module, stage); } }