diff --git a/releasenotes.md b/releasenotes.md index 708f0c4ec..cab93b8a6 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,5 +1,13 @@ # C3C Release Notes +## 0.7.5 Change list + +### Changes / improvements +- Support `alias foo = module std::io` module aliasing. + +### Fixes +### Stdlib changes + ## 0.7.4 Change list ### Changes / improvements diff --git a/src/compiler/ast.c b/src/compiler/ast.c index f1c991300..c8b316574 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -52,9 +52,6 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type) TypeKind kind = TYPE_POISONED; switch (decl_type) { - case DECL_FNTYPE: - case DECL_FUNC: - UNREACHABLE case DECL_INTERFACE: kind = TYPE_INTERFACE; break; @@ -79,8 +76,10 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type) case DECL_BITSTRUCT: kind = TYPE_BITSTRUCT; break; - case NON_TYPE_DECLS: + case DECL_FNTYPE: + case DECL_FUNC: case DECL_ERASED: + case NON_TYPE_DECLS: UNREACHABLE } Type *type = type_new(kind, name ? name : "$anon"); @@ -115,7 +114,7 @@ const char *decl_to_a_name(Decl *decl) case DECL_CT_EXEC: return "compile time exec include"; case DECL_CT_INCLUDE: return "an include"; case DECL_DECLARRAY: return "a declarray"; - case DECL_ALIAS: case DECL_TYPEDEF: return "an alias"; + case DECL_ALIAS: case DECL_ALIAS_PATH: case DECL_TYPEDEF: return "an alias"; case DECL_DISTINCT: return "a distinct type"; case DECL_ENUM: return "an enum"; case DECL_CONST_ENUM: return "a raw enum"; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 9cc60c733..b6946b9b2 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -598,6 +598,11 @@ typedef struct }; } DefineDecl; +typedef union +{ + Path *alias_path; + Module *module; +} ModuleAliasDecl; typedef struct { @@ -690,6 +695,7 @@ typedef struct Decl_ Decl** ct_else_decl; Decl** decls; DefineDecl define_decl; + ModuleAliasDecl module_alias_decl; EnumConstantDecl enum_constant; ExecDecl exec_decl; Expr* expand_decl; @@ -1658,6 +1664,7 @@ struct CompilationUnit_ Module *module; File *file; Decl **imports; + Decl **module_aliases; Decl **public_imports; Decl **types; Decl **functions; @@ -2231,6 +2238,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl); void unit_register_external_symbol(SemaContext *context, Decl *decl); bool unit_add_import(CompilationUnit *unit, Path *path, bool private_import, bool is_non_recursive); +bool unit_add_alias(CompilationUnit *unit, Decl *decl); bool context_set_module_from_filename(ParseContext *context); bool context_set_module(ParseContext *context, Path *path, const char **generic_parameters); bool context_is_macro(SemaContext *context); diff --git a/src/compiler/context.c b/src/compiler/context.c index d6296369f..4942d27b7 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -156,17 +156,18 @@ void decl_register(Decl *decl) { case DECL_ERASED: return; - case DECL_POISONED: + case DECL_ALIAS_PATH: + case DECL_BODYPARAM: case DECL_CT_ASSERT: case DECL_CT_ECHO: case DECL_CT_EXEC: + case DECL_CT_INCLUDE: + case DECL_DECLARRAY: case DECL_ENUM_CONSTANT: + case DECL_GROUP: case DECL_IMPORT: case DECL_LABEL: - case DECL_DECLARRAY: - case DECL_BODYPARAM: - case DECL_CT_INCLUDE: - case DECL_GROUP: + case DECL_POISONED: UNREACHABLE case DECL_ATTRIBUTE: case DECL_BITSTRUCT: @@ -264,13 +265,14 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) vec_add(unit->attributes, decl); decl_register(decl); break; + case DECL_ALIAS_PATH: + case DECL_BODYPARAM: + case DECL_DECLARRAY: case DECL_ENUM_CONSTANT: + case DECL_FNTYPE: + case DECL_GROUP: case DECL_IMPORT: case DECL_LABEL: - case DECL_DECLARRAY: - case DECL_BODYPARAM: - case DECL_GROUP: - case DECL_FNTYPE: UNREACHABLE case DECL_CT_EXEC: case DECL_CT_INCLUDE: @@ -329,3 +331,12 @@ bool unit_add_import(CompilationUnit *unit, Path *path, bool private_import, boo return true; } +bool unit_add_alias(CompilationUnit *unit, Decl *alias) +{ + DEBUG_LOG("SEMA: Add module alias '%s'.", alias->name); + + if (!check_module_name(alias->module_alias_decl.alias_path)) return false; + vec_add(unit->module_aliases, alias); + return true; +} + diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 4b8760b1b..e23b8db76 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -1122,6 +1122,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) MACRO_COPY_AST(decl->ct_assert_decl); break; case DECL_IMPORT: + case DECL_ALIAS_PATH: break; case DECL_MACRO: MACRO_COPY_ASTID(copy->func_decl.docs); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 457b42526..6c64132fb 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -670,6 +670,7 @@ typedef enum DECL_CT_INCLUDE, DECL_DECLARRAY, DECL_ALIAS, + DECL_ALIAS_PATH, DECL_DISTINCT, DECL_ENUM, DECL_ENUM_CONSTANT, @@ -1660,7 +1661,7 @@ typedef enum case DECL_ALIAS: case DECL_CT_ASSERT: case DECL_CT_EXEC: case DECL_FAULT: \ case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GROUP: \ case DECL_BODYPARAM: case DECL_VAR: case DECL_ENUM_CONSTANT: \ - case DECL_POISONED + case DECL_POISONED: case DECL_ALIAS_PATH // -- Expr helper macros #define NON_RUNTIME_EXPR EXPR_POISONED: \ diff --git a/src/compiler/json_output.c b/src/compiler/json_output.c index c70857d34..a2675127e 100644 --- a/src/compiler/json_output.c +++ b/src/compiler/json_output.c @@ -96,6 +96,7 @@ static inline const char *decl_type_to_string(Decl *type) case DECL_FUNC: return "function"; case DECL_GROUP: return "globals"; case DECL_IMPORT: return "import"; + case DECL_ALIAS_PATH: return "module_alias"; case DECL_MACRO: return "macro"; case DECL_INTERFACE: return "interface"; case DECL_STRUCT: return "struct"; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 0b30707d3..32337a3c8 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1365,6 +1365,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl) case DECL_CONST_ENUM: case DECL_ENUM_CONSTANT: case DECL_IMPORT: + case DECL_ALIAS_PATH: case DECL_LABEL: case DECL_MACRO: case DECL_STRUCT: diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index a5b2be072..ff2ab04c3 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2149,7 +2149,37 @@ static inline Decl *parse_alias_type(ParseContext *c) } /** - * define_ident ::= 'define' (IDENT | CONST_IDENT | AT_IDENT) attributes? '=' identifier_alias generic_params? + * define_ident ::= 'alias' 'module' IDENT = path + */ +static inline Decl *parse_alias_module(ParseContext *c, Decl *decl, TokenType token_type) +{ + advance_and_verify(c, TOKEN_MODULE); + + if (token_type != TOKEN_IDENT) + { + PRINT_ERROR_AT(decl, "A (lower case) module name was expected here."); + return poisoned_decl; + } + + if (!str_is_valid_lowercase_name(decl->name)) + { + PRINT_ERROR_AT(decl, "The module name must be all lower case."); + return poisoned_decl; + } + + decl->decl_kind = DECL_ALIAS_PATH; + + Path *path = parse_module_path(c); + if (!path) return poisoned_decl; + + decl->module_alias_decl.alias_path = path; + + RANGE_EXTEND_PREV(decl); + CONSUME_EOS_OR_RET(poisoned_decl); + return decl; +} +/** + * define_ident ::= 'alias' (IDENT | CONST_IDENT | AT_IDENT) attributes? '=' (('module' path) | identifier_alias generic_params?) * * identifier_alias ::= path? (IDENT | CONST_IDENT | AT_IDENT) */ @@ -2158,7 +2188,6 @@ static inline Decl *parse_alias_ident(ParseContext *c) // 1. Store the beginning of the "alias". advance_and_verify(c, TOKEN_ALIAS); - // 2. At this point we expect an ident or a const token. // since the Type is handled. TokenType alias_type = c->tok; @@ -2182,10 +2211,6 @@ static inline Decl *parse_alias_ident(ParseContext *c) // 3. Set up the "define". Decl *decl = decl_new(DECL_ALIAS, symstr(c), c->span); - if (decl->name == kw_main) - { - RETURN_PRINT_ERROR_AT(poisoned_decl, decl, "'main' is reserved and cannot be used as an alias."); - } // 4. Advance and consume the '=' advance(c); @@ -2193,6 +2218,15 @@ static inline Decl *parse_alias_ident(ParseContext *c) CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); + if (tok_is(c, TOKEN_MODULE)) + { + return parse_alias_module(c, decl, alias_type); + } + if (decl->name == kw_main) + { + RETURN_PRINT_ERROR_AT(poisoned_decl, decl, "'main' is reserved and cannot be used as an alias."); + } + if (tok_is(c, TOKEN_FN)) { RETURN_PRINT_ERROR_AT(poisoned_decl, decl, "This looks like you're declaring a function type alias, and such an alias must have a valid type name, like 'Callback'."); @@ -3169,6 +3203,16 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out) case TOKEN_ALIAS: if (has_real_contracts) goto CONTRACT_NOT_ALLOWED; decl = parse_alias(c); + if (decl->decl_kind == DECL_ALIAS_PATH) + { + if (!context_out) + { + PRINT_ERROR_HERE("'alias module' may not appear inside a compile time statement."); + return poisoned_decl; + } + if (!unit_add_alias(c->unit, decl)) return poisoned_decl; + return NULL; + } break; case TOKEN_ATTRDEF: if (has_real_contracts) goto CONTRACT_NOT_ALLOWED; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 946173ffc..40f006668 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4849,6 +4849,7 @@ static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit) { CompilationUnit *copy = unit_create(unit->file); copy->imports = copy_decl_list_single(unit->imports); + copy->module_aliases = copy_decl_list_single(unit->module_aliases); copy->public_imports = NULL; if (unit->public_imports) { @@ -5420,17 +5421,18 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) case DECL_ALIAS: if (!sema_analyse_alias(context, decl, &erase_decl)) goto FAILED; break; - case DECL_POISONED: - case DECL_IMPORT: - case DECL_ENUM_CONSTANT: - case DECL_LABEL: + case DECL_ALIAS_PATH: + case DECL_BODYPARAM: case DECL_CT_ASSERT: case DECL_CT_ECHO: - case DECL_DECLARRAY: - case DECL_BODYPARAM: - case DECL_CT_INCLUDE: case DECL_CT_EXEC: + case DECL_CT_INCLUDE: + case DECL_DECLARRAY: + case DECL_ENUM_CONSTANT: case DECL_GROUP: + case DECL_IMPORT: + case DECL_LABEL: + case DECL_POISONED: UNREACHABLE } if (erase_decl) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f17649283..16b4244f9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -928,19 +928,20 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) case DECL_FAULT: expr_rewrite_const_fault(expr, decl); return true; - case DECL_DISTINCT: - case DECL_TYPEDEF: - case DECL_DECLARRAY: - case DECL_BODYPARAM: - case DECL_CT_INCLUDE: - case DECL_CT_EXEC: - case DECL_GROUP: - case DECL_ERASED: - case DECL_IMPORT: - case DECL_ATTRIBUTE: - case DECL_CT_ASSERT: case DECL_ALIAS: + case DECL_ALIAS_PATH: + case DECL_ATTRIBUTE: + case DECL_BODYPARAM: + case DECL_CT_ASSERT: case DECL_CT_ECHO: + case DECL_CT_EXEC: + case DECL_CT_INCLUDE: + case DECL_DECLARRAY: + case DECL_DISTINCT: + case DECL_ERASED: + case DECL_GROUP: + case DECL_IMPORT: + case DECL_TYPEDEF: UNREACHABLE case DECL_POISONED: return expr_poison(expr); @@ -9721,7 +9722,8 @@ static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr) break; } FALLTHROUGH; - case DECL_POISONED: + case DECL_ALIAS: + case DECL_ALIAS_PATH: case DECL_ATTRIBUTE: case DECL_BODYPARAM: case DECL_CT_ASSERT: @@ -9734,7 +9736,7 @@ static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr) case DECL_IMPORT: case DECL_LABEL: case DECL_MACRO: - case DECL_ALIAS: + case DECL_POISONED: RETURN_SEMA_ERROR(main_var, "'%s' does not have an external name.", decl->name); case DECL_FAULT: goto RETURN_CT; diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 37364320d..b461636b9 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -624,15 +624,16 @@ RETRY: case DECL_ATTRIBUTE: case DECL_FAULT: return; + case DECL_ALIAS_PATH: + case DECL_BODYPARAM: case DECL_CT_ASSERT: case DECL_CT_ECHO: case DECL_CT_EXEC: - case DECL_IMPORT: case DECL_CT_INCLUDE: + case DECL_GROUP: + case DECL_IMPORT: case DECL_LABEL: case DECL_MACRO: - case DECL_BODYPARAM: - case DECL_GROUP: UNREACHABLE case DECL_FNTYPE: sema_trace_func_liveness(&decl->fntype_decl); diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 8d93a5fc4..964d6fd2d 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -142,6 +142,7 @@ static bool sema_find_decl_in_imports(SemaContext *context, NameResolve *name_re // 1. Loop over imports. Path *path = name_resolve->path; const char *symbol = name_resolve->symbol; + FOREACH(Decl *, import, context->unit->imports) { if (import->import.module->is_generic != want_generic) continue; @@ -436,6 +437,19 @@ static bool sema_resolve_path_symbol(SemaContext *context, NameResolve *name_res name_resolve->found = NULL; ASSERT(name_resolve->path && "Expected path."); + if (path != NULL) + { + FOREACH(Decl *, decl_alias, context->unit->module_aliases) + { + if (path->module == decl_alias->name) + { + assert(decl_alias->resolve_status == RESOLVE_DONE); + name_resolve->path_found = decl_alias->module_alias_decl.module; + name_resolve->path = name_resolve->path_found->name; + break; + } + } + } const char *symbol = name_resolve->symbol; // 0. std module special handling. if (path->module == compiler.context.std_module_path.module) diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index caf8e8221..14150c287 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -116,6 +116,33 @@ void sema_analysis_pass_process_imports(Module *module) import->import.module = import_module; NEXT:; } + FOREACH_IDX(idx, Decl *, alias_module, unit->module_aliases) + { + Path *path = alias_module->module_alias_decl.alias_path; + Module *import_module = global_context_find_module(path->module); + + // 5. Do we find it? + if (!import_module) + { + PRINT_ERROR_AT(path, "No module named '%s' could be found, did you type the name right?", path->module); + continue; + } + alias_module->module_alias_decl.module = import_module; + alias_module->resolve_status = RESOLVE_DONE; + for (unsigned i = 0; i < idx; i++) + { + if (unit->module_aliases[i]->name == alias_module->name) + { + PRINT_ERROR_AT(alias_module, "The module alias must be unique."); + break; + } + } + if (alias_module->attributes) + { + PRINT_ERROR_AT(alias_module->attributes[0], "Module aliases cannot have attributes."); + break; + } + } total_import_count += import_count; } (void)total_import_count; // workaround for clang 13.0 diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 3df02f7c0..a2e9f1f1d 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -267,21 +267,22 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in } FALLTHROUGH; case DECL_ALIAS: - case DECL_FUNC: - case DECL_ENUM_CONSTANT: - case DECL_IMPORT: - case DECL_MACRO: - case DECL_LABEL: + case DECL_ALIAS_PATH: case DECL_ATTRIBUTE: + case DECL_ENUM_CONSTANT: case DECL_FAULT: + case DECL_FUNC: + case DECL_IMPORT: + case DECL_LABEL: + case DECL_MACRO: SEMA_ERROR(type_info, "This is not a type."); return type_info_poison(type_info); + case DECL_BODYPARAM: case DECL_CT_ASSERT: case DECL_CT_ECHO: - case DECL_DECLARRAY: - case DECL_BODYPARAM: - case DECL_CT_INCLUDE: case DECL_CT_EXEC: + case DECL_CT_INCLUDE: + case DECL_DECLARRAY: case DECL_GROUP: UNREACHABLE } diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 107b15fe9..318601d08 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -224,38 +224,37 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) decl->unit = unit; switch (decl->decl_kind) { - case DECL_ENUM_CONSTANT: - case DECL_DECLARRAY: - case DECL_ERASED: - case DECL_LABEL: - UNREACHABLE - case DECL_POISONED: - case DECL_IMPORT: + case DECL_ALIAS_PATH: case DECL_CT_ASSERT: case DECL_CT_ECHO: - case DECL_FNTYPE: - case DECL_CT_INCLUDE: case DECL_CT_EXEC: + case DECL_CT_INCLUDE: + case DECL_FNTYPE: + case DECL_IMPORT: + case DECL_POISONED: continue; - case DECL_ATTRIBUTE: - break; case DECL_FAULT: PRINT_ERROR_AT(decl, "Generic modules cannot use 'faultdef', place the declaration in a separate sub module or parent module instead."); decl_poison(decl); break; case DECL_BODYPARAM: + case DECL_DECLARRAY: + case DECL_ENUM_CONSTANT: + case DECL_ERASED: case DECL_GROUP: + case DECL_LABEL: UNREACHABLE case DECL_ALIAS: + case DECL_ATTRIBUTE: + case DECL_BITSTRUCT: + case DECL_CONST_ENUM: case DECL_DISTINCT: case DECL_ENUM: + case DECL_INTERFACE: case DECL_STRUCT: case DECL_TYPEDEF: case DECL_UNION: case DECL_VAR: - case DECL_BITSTRUCT: - case DECL_INTERFACE: - case DECL_CONST_ENUM: break; case DECL_MACRO: case DECL_FUNC: diff --git a/src/version.h b/src/version.h index b6afad39d..877a52b0b 100644 --- a/src/version.h +++ b/src/version.h @@ -1,2 +1,2 @@ -#define COMPILER_VERSION "0.7.4" +#define COMPILER_VERSION "0.7.5" #define PRERELEASE 0 diff --git a/test/test_suite/import/alias_attributes.c3 b/test/test_suite/import/alias_attributes.c3 new file mode 100644 index 000000000..c87816cd9 --- /dev/null +++ b/test/test_suite/import/alias_attributes.c3 @@ -0,0 +1,3 @@ +module abc; + +alias test @if(true) = module abc; // #error: Module aliases cannot \ No newline at end of file diff --git a/test/test_suite/import/alias_bad_name.c3 b/test/test_suite/import/alias_bad_name.c3 new file mode 100644 index 000000000..c7318a590 --- /dev/null +++ b/test/test_suite/import/alias_bad_name.c3 @@ -0,0 +1,5 @@ +module foo; + +alias FOO = module abc; // #error: A (lower case) module name was expected here +alias hellO = module abc; // #error: The module name must be all lower case +alias hllo = module aBC; // #error: A module name may not have any diff --git a/test/test_suite/import/alias_duplicate.c3 b/test/test_suite/import/alias_duplicate.c3 new file mode 100644 index 000000000..6cc8446dd --- /dev/null +++ b/test/test_suite/import/alias_duplicate.c3 @@ -0,0 +1,7 @@ +module abc; +import std; + +alias xyz1 = module std::io; +alias xyz2 = module std::io; +alias xyz3 = module std::io; +alias xyz2 = module std::io; // #error: The module alias must be unique \ No newline at end of file diff --git a/test/test_suite/import/alias_no_match.c3 b/test/test_suite/import/alias_no_match.c3 new file mode 100644 index 000000000..8cb65e2d3 --- /dev/null +++ b/test/test_suite/import/alias_no_match.c3 @@ -0,0 +1,3 @@ +module abc; + +alias test = module abg; // #error: No module named