Added "weak" type aliases def Foo = my_foo::Foo @weak;

This commit is contained in:
Christoffer Lerno
2024-07-25 22:55:45 +02:00
parent 379637f214
commit 623dd9f3b3
13 changed files with 318 additions and 210 deletions

View File

@@ -7,6 +7,7 @@
- Added `is_substruct` type property.
- Scalar -> vector not implicit in call or assign.
- Added `--vector-conv` to enable the old scalar->vector conversion behaviour.
- Added "weak" type aliases `def Foo = my_foo::Foo @weak;`
### Fixes
None

View File

@@ -56,6 +56,13 @@ extern const int manifest_default_keys_count;
extern const char *manifest_target_keys[][2];
extern const int manifest_target_keys_count;
typedef enum BoolErr__
{
BOOL_ERR = -1,
BOOL_FALSE = 0,
BOOL_TRUE = 1,
} BoolErr;
typedef struct Ast_ Ast;
typedef struct Decl_ Decl;
typedef struct TypeInfo_ TypeInfo;
@@ -601,6 +608,7 @@ typedef struct
typedef struct
{
bool is_func : 1;
bool is_redef : 1;
union
{
Decl *decl;
@@ -1887,6 +1895,7 @@ typedef struct
Decl *ambiguous_other_decl;
Decl *private_decl;
Decl *maybe_decl;
Decl *found;
Path *path;
SourceSpan span;
const char *symbol;
@@ -2373,7 +2382,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
Decl *unit_resolve_parameterized_symbol(SemaContext *context, CompilationUnit *unit, NameResolve *name_resolve);
bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve);
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name);
@@ -2384,7 +2393,7 @@ Decl *sema_find_path_symbol(SemaContext *context, const char *symbol, Path *path
Decl *sema_find_label_symbol(SemaContext *context, const char *symbol);
Decl *sema_find_label_symbol_anywhere(SemaContext *context, const char *symbol);
Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span);
bool sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol);
BoolErr sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol);
bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, ArraySize *len_ref);
@@ -2489,7 +2498,6 @@ Type *type_find_parent_type(Type *type);
bool type_is_subtype(Type *type, Type *possible_subtype);
bool type_is_abi_aggregate(Type *type);
bool type_is_int128(Type *type);
Decl * type_no_export(Type *type);
Type *type_from_token(TokenType type);
bool type_is_user_defined(Type *type);

View File

@@ -1819,6 +1819,11 @@ static inline Decl *parse_def_type(ParseContext *c)
decl->typedef_decl.is_func = false;
decl->decl_kind = DECL_TYPEDEF;
decl_add_type(decl, TYPE_TYPEDEF);
if (type_info->kind == TYPE_INFO_IDENTIFIER && type_info->resolve_status == RESOLVE_NOT_DONE
&& type_info->unresolved.name == decl->name)
{
decl->typedef_decl.is_redef = true;
}
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
RANGE_EXTEND_PREV(decl);

View File

@@ -285,6 +285,7 @@ static inline bool sema_check_asm_var(SemaContext *context, AsmInlineBlock *bloc
const char *name = arg->ident.name;
Decl *decl = sema_resolve_symbol(context, name, NULL, expr->span);
if (!decl) return false;
assert(arg->kind == ASM_ARG_REGVAR);
arg->ident.ident_decl = decl;
if (decl->decl_kind != DECL_VAR)
@@ -382,13 +383,11 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
arg->ident.ident_decl = decl;
if (decl->decl_kind != DECL_VAR)
{
SEMA_ERROR(expr, "Expected a global or local variable.");
return false;
RETURN_SEMA_ERROR(expr, "Expected a global or local variable.");
}
if (IS_OPTIONAL(decl))
{
SEMA_ERROR(expr, "Optional variables are not allowed in asm.");
return false;
RETURN_SEMA_ERROR(expr, "Optional variables are not allowed in asm.");
}
bool is_write = arg_type.is_write;
bool is_read = !arg_type.is_write || arg_type.is_readwrite;
@@ -398,8 +397,7 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
decl->var.is_read = true;
if (decl->var.out_param)
{
SEMA_ERROR(expr, "An 'out' variable may not be read from.");
return false;
RETURN_SEMA_ERROR(expr, "An 'out' variable may not be read from.");
}
asm_reg_add_input(block, arg);
}
@@ -408,15 +406,13 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
decl->var.is_written = true;
if (decl->var.in_param)
{
SEMA_ERROR(expr, "An 'in' variable may not be written to.");
return false;
RETURN_SEMA_ERROR(expr, "An 'in' variable may not be written to.");
}
asm_reg_add_output(block, arg);
}
if (!arg_type.is_address)
{
SEMA_ERROR(expr, "This slot does not accept an address.");
return false;
RETURN_SEMA_ERROR(expr, "This slot does not accept an address.");
}
return true;
}

View File

@@ -2380,7 +2380,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_UNUSED] = (AttributeDomain)~(ATTR_CALL),
[ATTRIBUTE_USED] = (AttributeDomain)~(ATTR_CALL),
[ATTRIBUTE_WASM] = ATTR_FUNC,
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL | ATTR_DEF,
[ATTRIBUTE_WINMAIN] = ATTR_FUNC,
};
// NOLINTEND(*.EnumCastOutOfRange)
@@ -2628,6 +2628,14 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
decl->func_decl.signature.attrs.noreturn = true;
break;
case ATTRIBUTE_WEAK:
if (domain == ATTR_DEF)
{
if (decl->decl_kind != DECL_TYPEDEF) RETURN_SEMA_ERROR(attr, "'@weak' can only be used on type aliases.");
if (!decl->typedef_decl.is_redef)
{
RETURN_SEMA_ERROR(attr, "'@weak' is only allowed on type aliases with the same name, eg 'def Foo = bar::def::Foo @weak'.");
}
}
decl->is_weak = true;
break;
case ATTRIBUTE_WASM:
@@ -4032,9 +4040,9 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con
.symbol = name
};
Decl *alias = unit_resolve_parameterized_symbol(NULL, c->unit, &name_resolve);
if (!decl_ok(alias)) return poisoned_decl;
if (!unit_resolve_parameterized_symbol(c, &name_resolve)) return poisoned_decl;
Decl *alias = name_resolve.found;
assert(alias);
Module *module = decl_module(alias);
unsigned parameter_count = vec_size(module->parameters);
assert(parameter_count > 0);
@@ -4127,6 +4135,7 @@ static inline bool sema_analyse_define(SemaContext *c, Decl *decl, bool *erase_d
if (decl->define_decl.define_kind == DEFINE_IDENT_ALIAS)
{
Decl *symbol = sema_resolve_symbol(c, decl->define_decl.ident, decl->define_decl.path, decl->define_decl.span);
if (!symbol) return false;
if (!sema_analyse_decl(c, symbol)) return false;
decl->type = symbol->type;
decl->define_decl.alias = symbol;

View File

@@ -1002,7 +1002,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
{
decl = sema_resolve_symbol(context, expr->identifier_expr.ident, expr->identifier_expr.path, expr->span);
(void)decl;
assert(!decl_ok(decl));
assert(!decl);
return false;
}
@@ -1081,7 +1081,7 @@ static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *e
Decl *decl = sema_resolve_symbol(context, expr->ct_ident_expr.identifier, NULL, expr->span);
// Already handled
if (!decl_ok(decl))
if (!decl)
{
return expr_poison(expr);
}
@@ -1102,7 +1102,7 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Type
Decl *decl = sema_resolve_symbol(context, expr->hash_ident_expr.identifier, NULL, expr->span);
// Already handled
if (!decl_ok(decl)) return expr_poison(expr);
if (!decl) return expr_poison(expr);
assert(decl->decl_kind == DECL_VAR);
expr_replace(expr, copy_expr_single(decl->var.init_expr));
@@ -3180,7 +3180,7 @@ RETRY:
{
assert(child->resolve_status != RESOLVE_DONE);
Decl *decl = sema_resolve_symbol(context, child->hash_ident_expr.identifier, NULL, child->span);
if (!decl_ok(decl)) return NULL;
if (!decl) return NULL;
Expr *expr = copy_expr_single(decl->var.init_expr);
return sema_expr_resolve_access_child(decl->var.hash_var.context, expr, missing);
}
@@ -5096,8 +5096,7 @@ static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Ex
if (!decl)
{
SEMA_ERROR(info, "'%s' is not defined in this scope yet.", info->unresolved.name);
return false;
RETURN_SEMA_ERROR(info, "'%s' is not defined in this scope yet.", info->unresolved.name);
}
decl->var.init_expr = right;
expr->expr_kind = EXPR_NOP;
@@ -8203,8 +8202,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_HASH_IDENT:
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->hash_ident_expr.identifier, NULL, main_expr->span);
if (!decl_ok(decl)) return false;
if (!decl) RETURN_SEMA_ERROR(list[i], "No parameter '%s' found.", main_expr->hash_ident_expr.identifier);
if (!decl) return false;
main_expr = copy_expr_single(decl->var.init_expr);
goto RETRY;
}
@@ -8230,8 +8228,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_CT_IDENT:
{
Decl *decl = sema_resolve_symbol(active_context, main_expr->ct_ident_expr.identifier, NULL, main_expr->span);
if (!decl_ok(decl)) return false;
success = decl != NULL;
if (!decl) return false;
break;
}
case EXPR_CALL:
@@ -8794,7 +8791,7 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex
// Only hash ident style stringify reaches here.
assert(inner->expr_kind == EXPR_HASH_IDENT);
Decl *decl = sema_resolve_symbol(context, inner->ct_ident_expr.identifier, NULL, inner->span);
if (!decl_ok(decl)) return false;
if (!decl) return false;
const char *desc = span_to_string(decl->var.hash_var.span);
if (!desc)
{

View File

@@ -9,6 +9,7 @@
typedef long long int ssize_t;
#endif
INLINE bool sema_resolve_ambiguity(SemaContext *context, Decl **current, Decl *candidate, Decl **ambiguous);
static inline bool matches_subpath(Path *path_to_check, Path *path_to_find)
{
// This checks the full match.
@@ -124,13 +125,13 @@ static inline Decl *sema_find_decl_in_module(Module *module, Path *path, const c
return module_find_symbol(module, symbol);
}
static Decl *sema_find_decl_in_private_imports(Decl **imports, NameResolve *name_resolve, bool want_generic)
static bool sema_find_decl_in_private_imports(SemaContext *context, NameResolve *name_resolve, bool want_generic)
{
Decl *decl = NULL;
// 1. Loop over imports.
Path *path = name_resolve->path;
const char *symbol = name_resolve->symbol;
FOREACH(Decl *, import, imports)
FOREACH(Decl *, import, context->unit->imports)
{
if (import->import.module->is_generic != want_generic) continue;
if (!import->import.import_private_as_public) continue;
@@ -147,16 +148,8 @@ static Decl *sema_find_decl_in_private_imports(Decl **imports, NameResolve *name
{
if (!path)
{
// Prefer already found builtin over newly found non-builtin
if (decl->is_autoimport && !found->is_autoimport) continue;
// Prefer new builtin over non-builtin
if (found->is_autoimport && !decl->is_autoimport)
{
decl = found;
name_resolve->private_decl = NULL;
name_resolve->ambiguous_other_decl = NULL;
continue;
}
if (!sema_resolve_ambiguity(context, &decl, found, &name_resolve->ambiguous_other_decl)) return false;
continue;
}
// 11. Then set an ambiguous match.
name_resolve->ambiguous_other_decl = found;
@@ -167,7 +160,8 @@ static Decl *sema_find_decl_in_private_imports(Decl **imports, NameResolve *name
decl = found;
name_resolve->private_decl = NULL;
}
return decl;
name_resolve->found = decl;
return true;
}
static inline bool sema_is_path_found(Module **modules, Path *path, bool want_generic)
@@ -238,13 +232,97 @@ static bool decl_is_visible(CompilationUnit *unit, Decl *decl)
return false;
}
static bool sema_first_is_preferred(Decl *decl, Decl *decl2)
INLINE Type *sema_fold_weak(SemaContext *context, Decl *decl)
{
return (decl->is_autoimport && !decl2->is_autoimport)
|| (decl2->unit->module->generic_module && !decl->unit->module->generic_module);
while (decl->is_weak)
{
if (decl->resolve_status != RESOLVE_DONE)
{
if (!sema_analyse_decl(context, decl)) return NULL;
}
Type *type = decl->typedef_decl.type_info->type;
if (type->type_kind != TYPE_TYPEDEF) return type;
decl = type->decl;
}
return decl->type;
}
static Decl *sema_find_decl_in_global(CompilationUnit *unit, DeclTable *table, Module **module_list, NameResolve *name_resolve, bool want_generic)
/**
* We want to prefer abc::Foo over bcd::Foo if:
* (1) abc::Foo is autoimported and bcd::Foo isn't.
* (2) abc::Foo is from a normal module and bcd::Foo is from a generic module.
* (3) Folding bcd::Foo to it's @weak result gives the same as folding abc::Foo to its @weak type.
*
* @param context
* @param decl
* @param decl2
* @return
*/
static BoolErr sema_first_is_preferred(SemaContext *context, Decl *decl, Decl *decl2)
{
// (1) and (2)
if ((decl->is_autoimport && !decl2->is_autoimport)
|| (decl2->unit->module->generic_module && !decl->unit->module->generic_module)) return BOOL_TRUE;
// Now analyse common parents, we only check if this is a redef.
if (decl2->decl_kind != DECL_TYPEDEF || !decl2->is_weak) return BOOL_FALSE;
Type *weak2 = sema_fold_weak(context, decl2);
if (!weak2) return BOOL_ERR;
// Fast path: do the types match?
if (weak2 == decl->type) return BOOL_TRUE;
// If we can't fold the decl then we're done.
if (decl->decl_kind != DECL_TYPEDEF || !decl->is_weak) return BOOL_FALSE;
Type *weak = sema_fold_weak(context, decl);
if (!weak) return BOOL_ERR;
// Both fold to the same
if (weak == weak2) return BOOL_TRUE;
// Otherwise we fail.
return BOOL_FALSE;
}
INLINE bool sema_resolve_ambiguity(SemaContext *context, Decl **current, Decl *candidate, Decl **ambiguous)
{
Decl *original = *current;
if (!original)
{
*current = candidate;
return true;
}
// The candidate is preferred
BoolErr preferred = sema_first_is_preferred(context, candidate, original);
if (preferred == BOOL_ERR) return false;
if (preferred == BOOL_TRUE)
{
// Clear any ambiguity
*ambiguous = NULL;
*current = candidate;
return true;
}
// We already have something ambiguous, so keep that.
if (*ambiguous) return true;
// If the original is preferred over the candidate, then we just
// keep the original and there is no ambiguity:
switch (sema_first_is_preferred(context, original, candidate))
{
case BOOL_FALSE:
// Otherwise we have an ambiguity
*ambiguous = candidate;
FALLTHROUGH;
case BOOL_TRUE:
return true;
case BOOL_ERR:
return false;
}
UNREACHABLE;
}
static bool sema_find_decl_in_global(SemaContext *context, DeclTable *table, Module **module_list,
NameResolve *name_resolve, bool want_generic)
{
const char *symbol = name_resolve->symbol;
Path *path = name_resolve->path;
@@ -255,21 +333,25 @@ static Decl *sema_find_decl_in_global(CompilationUnit *unit, DeclTable *table, M
{
// Update the path found
if (path && !name_resolve->path_found) name_resolve->path_found = sema_is_path_found(module_list, path, want_generic);
return NULL;
name_resolve->found = NULL;
return true;
}
Decl *decls = declptr(decl_ids);
// There might just be a single match.
if (decls->decl_kind != DECL_DECLARRAY)
{
if (path && !matches_subpath(decl_module(decls)->name, path)) return NULL;
if (!decl_is_visible(unit, decls))
if (path && !matches_subpath(decl_module(decls)->name, path)) return true;
if (!decl_is_visible(context->unit, decls))
{
name_resolve->maybe_decl = decls;
return NULL;
}
name_resolve->private_decl = NULL;
return decls;
else
{
name_resolve->private_decl = NULL;
name_resolve->found = decls;
}
return true;
}
// Else go through the list
@@ -278,50 +360,27 @@ static Decl *sema_find_decl_in_global(CompilationUnit *unit, DeclTable *table, M
FOREACH(Decl *, candidate, decls->decl_list)
{
if (path && !matches_subpath(decl_module(candidate)->name, path)) continue;
if (!decl_is_visible(unit, candidate))
if (!decl_is_visible(context->unit, candidate))
{
maybe_decl = candidate;
continue;
}
if (ambiguous)
{
if (sema_first_is_preferred(candidate, decl))
{
ambiguous = NULL;
decl = candidate;
}
}
else
{
ambiguous = decl;
decl = candidate;
if (ambiguous)
{
// If we have a same match but one is builtin, prefer builtin.
if (sema_first_is_preferred(decl, ambiguous))
{
ambiguous = NULL;
}
else if (sema_first_is_preferred(ambiguous, decl))
{
decl = ambiguous;
ambiguous = NULL;
}
}
}
if (!sema_resolve_ambiguity(context, &decl, candidate, &ambiguous)) return false;
}
name_resolve->ambiguous_other_decl = ambiguous;
name_resolve->private_decl = NULL;
name_resolve->found = decl;
name_resolve->maybe_decl = maybe_decl;
return decl;
return true;
}
static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_resolve)
static bool sema_resolve_path_symbol(SemaContext *context, NameResolve *name_resolve)
{
Path *path = name_resolve->path;
name_resolve->ambiguous_other_decl = NULL;
Decl *decl = NULL;
name_resolve->path_found = false;
name_resolve->found = NULL;
assert(name_resolve->path && "Expected path.");
const char *symbol = name_resolve->symbol;
@@ -329,7 +388,8 @@ static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_re
if (path->module == global_context.std_module_path.module)
{
name_resolve->path_found = true;
return module_find_symbol(&global_context.std_module, symbol);
name_resolve->found = module_find_symbol(&global_context.std_module, symbol);
return true;
}
CompilationUnit *unit = context->unit;
@@ -338,15 +398,17 @@ static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_re
if (matches_subpath(unit->module->name, path))
{
// 2. If so try to locally get the symbol.
if ((decl = module_find_symbol(unit->module, symbol))) return decl;
if ((name_resolve->found = module_find_symbol(unit->module, symbol))) return true;
name_resolve->path_found = true;
}
// 3. Loop over imports.
decl = sema_find_decl_in_private_imports(unit->imports, name_resolve, false);
if (!sema_find_decl_in_private_imports(context, name_resolve, false)) return false;
// 4. Go to global search
return decl ? decl : sema_find_decl_in_global(unit, &global_context.symbols, global_context.module_list, name_resolve, false);
if (name_resolve->found) return true;
return sema_find_decl_in_global(context, &global_context.symbols, global_context.module_list,
name_resolve, false);
}
static inline Decl *sema_find_ct_local(SemaContext *context, const char *symbol)
@@ -387,37 +449,48 @@ static inline Decl *sema_find_local(SemaContext *context, const char *symbol)
return NULL;
}
static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name_resolve)
static bool sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name_resolve)
{
const char *symbol = name_resolve->symbol;
assert(name_resolve->path == NULL);
Decl *decl = sema_find_local(context, symbol);
if (decl) return decl;
Decl *decl;
if ((decl = sema_find_local(context, symbol)))
{
name_resolve->found = decl;
return true;
}
CompilationUnit *unit = context->unit;
// Search in file scope.
decl = htable_get(&unit->local_symbols, (void *) symbol);
if (decl) return decl;
if ((decl = htable_get(&unit->local_symbols, (void *) symbol)))
{
name_resolve->found = decl;
return true;
}
// Search in the module.
decl = module_find_symbol(unit->module, symbol);
if ((decl = module_find_symbol(unit->module, symbol)))
{
name_resolve->found = decl;
return true;
}
if (decl) return decl;
if (!sema_find_decl_in_private_imports(context, name_resolve, false)) return false;
if (name_resolve->found) return true;
decl = sema_find_decl_in_private_imports(unit->imports, name_resolve, false);
return decl ? decl : sema_find_decl_in_global(context->unit, &global_context.symbols, NULL, name_resolve, false);
return sema_find_decl_in_global(context, &global_context.symbols, NULL, name_resolve, false);
}
static void sema_report_error_on_decl(SemaContext *context, Decl *found, NameResolve *name_resolve)
static void sema_report_error_on_decl(SemaContext *context, NameResolve *name_resolve)
{
assert(!name_resolve->suppress_error);
const char *symbol = name_resolve->symbol;
SourceSpan span = name_resolve->span;
Decl *found = name_resolve->found;
const char *path_name = name_resolve->path ? name_resolve->path->module : NULL;
if (!found && name_resolve->private_decl)
{
@@ -491,18 +564,17 @@ static void sema_report_error_on_decl(SemaContext *context, Decl *found, NameRes
}
}
INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_resolve)
INLINE bool sema_resolve_symbol_common(SemaContext *context, NameResolve *name_resolve)
{
name_resolve->ambiguous_other_decl = NULL;
name_resolve->private_decl = NULL;
name_resolve->path_found = false;
Decl *decl;
if (name_resolve->path)
{
decl = sema_resolve_path_symbol(context, name_resolve);
if (!decl && !name_resolve->maybe_decl && !name_resolve->path_found)
if (!sema_resolve_path_symbol(context, name_resolve)) return false;
if (!name_resolve->found && !name_resolve->maybe_decl && !name_resolve->path_found)
{
if (name_resolve->suppress_error) return NULL;
if (name_resolve->suppress_error) return true;
bool path_found = false;
Module *module_with_path = NULL;
FOREACH(Module *, module, global_context.module_list)
@@ -519,42 +591,39 @@ INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_
{
if (matches_subpath(module->name, name_resolve->path))
{
SEMA_ERROR(name_resolve->path, "%s is a generic module, did you forget to add the generic parameter(s) (<...>) after '%s'?",
module->name->module, name_resolve->symbol);
return poisoned_decl;
RETURN_SEMA_ERROR(name_resolve->path,
"%s is a generic module, did you forget to add the generic parameter(s) (<...>) after '%s'?",
module->name->module, name_resolve->symbol);
}
}
}
if (module_with_path)
{
SEMA_ERROR(name_resolve, "'%s' could not be found in %s.", name_resolve->symbol, module_with_path->name->module);
RETURN_SEMA_ERROR(name_resolve, "'%s' could not be found in %s.", name_resolve->symbol, module_with_path->name->module);
}
else
{
SEMA_ERROR(name_resolve->path, "Unknown module '%.*s', did you type it right?", name_resolve->path->len, name_resolve->path->module);
}
return poisoned_decl;
RETURN_SEMA_ERROR(name_resolve->path, "Unknown module '%.*s', did you type it right?", name_resolve->path->len, name_resolve->path->module);
}
}
else
{
decl = sema_resolve_no_path_symbol(context, name_resolve);
if (!sema_resolve_no_path_symbol(context, name_resolve)) return false;
}
if (!decl || name_resolve->ambiguous_other_decl)
Decl *found = name_resolve->found;
if (!found || name_resolve->ambiguous_other_decl)
{
if (name_resolve->suppress_error) return NULL;
sema_report_error_on_decl(context, decl, name_resolve);
return poisoned_decl;
if (name_resolve->suppress_error) return name_resolve->found = NULL, true;
sema_report_error_on_decl(context, name_resolve);
return false;
}
unit_register_external_symbol(context, decl);
if (decl->is_if && context->call_env.in_if_resolution.a)
unit_register_external_symbol(context, found);
if (found->is_if && context->call_env.in_if_resolution.a)
{
sema_error_at(context, context->call_env.in_if_resolution, "This @if expression is dependent on '%s' which is also conditional.", decl->name);
SEMA_NOTE(decl, "'%s' is defined here.", decl->name);
return poisoned_decl;
sema_error_at(context, context->call_env.in_if_resolution, "This @if expression is dependent on '%s' which is also conditional.", found->name);
SEMA_NOTE(found, "'%s' is defined here.", found->name);
return false;
}
return decl;
return true;
}
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name)
@@ -781,45 +850,45 @@ Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *me
return found;
}
Decl *unit_resolve_parameterized_symbol(SemaContext *context, CompilationUnit *unit, NameResolve *name_resolve)
bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve)
{
name_resolve->ambiguous_other_decl = NULL;
name_resolve->private_decl = NULL;
name_resolve->path_found = false;
Decl *decl = sema_find_decl_in_private_imports(unit->imports, name_resolve, true);
if (!decl)
if (!sema_find_decl_in_private_imports(context, name_resolve, true)) return false;
if (!name_resolve->found)
{
decl = sema_find_decl_in_global(unit, &global_context.generic_symbols,
if (!sema_find_decl_in_global(context, &global_context.generic_symbols,
global_context.generic_module_list,
name_resolve, true);
name_resolve, true)) return false;
}
// 14. Error report
if (!decl || name_resolve->ambiguous_other_decl)
if (!name_resolve->found || name_resolve->ambiguous_other_decl)
{
if (name_resolve->suppress_error) return poisoned_decl;
sema_report_error_on_decl(context, decl, name_resolve);
return poisoned_decl;
if (name_resolve->suppress_error) return name_resolve->found = NULL, false;
sema_report_error_on_decl(context, name_resolve);
return false;
}
if (!decl_is_user_defined_type(decl) && !name_resolve->path)
if (!decl_is_user_defined_type(name_resolve->found) && !name_resolve->path)
{
if (name_resolve->suppress_error) return poisoned_decl;
SEMA_ERROR(name_resolve, "Function and variables must be prefixed with a path, e.g. 'foo::%s'.", name_resolve->symbol);
return poisoned_decl;
if (name_resolve->suppress_error) return false;
RETURN_SEMA_ERROR(name_resolve, "Function and variables must be prefixed with a path, e.g. 'foo::%s'.", name_resolve->symbol);
}
return decl;
return true;
}
/**
* Silently find a symbol, will return NULL, Poison or the value
*/
Decl *sema_find_symbol(SemaContext *context, const char *symbol)
{
NameResolve resolve = {
.suppress_error = true,
.symbol = symbol,
};
return sema_resolve_symbol_common(context, &resolve);
if (!sema_resolve_symbol_common(context, &resolve)) return poisoned_decl;
return resolve.found;
}
Decl *sema_find_label_symbol(SemaContext *context, const char *symbol)
@@ -850,21 +919,22 @@ Decl *sema_find_label_symbol_anywhere(SemaContext *context, const char *symbol)
return NULL;
}
bool sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol)
BoolErr sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol)
{
NameResolve resolve = {
.suppress_error = true,
.symbol = symbol,
};
Decl *decl = sema_resolve_symbol_common(c, &resolve);
if (!sema_resolve_symbol_common(c, &resolve)) return BOOL_ERR;
// Unknown symbol => not defined
if (!decl) return false;
Decl *found = resolve.found;
if (!found) return BOOL_FALSE;
// Defined in the same module => defined
if (decl_module(decl) == c->unit->module) return true;
if (decl_module(found) == c->unit->module) return BOOL_TRUE;
// Not a variable or function => defined
if (decl->decl_kind != DECL_VAR && decl->decl_kind != DECL_FUNC) return true;
if (found->decl_kind != DECL_VAR && found->decl_kind != DECL_FUNC) return BOOL_TRUE;
// Otherwise defined only if autoimport.
return decl->is_autoimport;
return found->is_autoimport ? BOOL_TRUE : BOOL_FALSE;
}
Decl *sema_find_path_symbol(SemaContext *context, const char *symbol, Path *path)
@@ -874,9 +944,14 @@ Decl *sema_find_path_symbol(SemaContext *context, const char *symbol, Path *path
.symbol = symbol,
.path = path
};
return sema_resolve_symbol_common(context, &resolve);
if (!sema_resolve_symbol_common(context, &resolve)) return poisoned_decl;
return resolve.found;
}
/**
* Resolves a symbol, return NULL if an error was found (and signalled),
* otherwise the decl.
*/
Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span)
{
NameResolve resolve = {
@@ -884,7 +959,11 @@ Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path,
.path = path,
.span = span
};
return sema_resolve_symbol_common(context, &resolve);
if (!sema_resolve_symbol_common(context, &resolve)) return NULL;
Decl *found = resolve.found;
assert(found);
if (!decl_ok(found)) return NULL;
return resolve.found;
}

View File

@@ -738,7 +738,9 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
// 1. Check if we are doing an implicit declaration.
if (!var_type && ident->expr_kind == EXPR_IDENTIFIER)
{
implicit_declaration = !sema_symbol_is_defined_in_scope(context, ident->identifier_expr.ident);
BoolErr res = sema_symbol_is_defined_in_scope(context, ident->identifier_expr.ident);
if (res == BOOL_ERR) return false;
implicit_declaration = res == BOOL_FALSE;
}
// 2. If we have a type for the variable, resolve it.
@@ -885,7 +887,9 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr)
}
if (!type && ident->expr_kind == EXPR_IDENTIFIER)
{
implicit_declaration = !sema_symbol_is_defined_in_scope(context, ident->identifier_expr.ident);
BoolErr res = sema_symbol_is_defined_in_scope(context, ident->identifier_expr.ident);
if (res == BOOL_ERR) return false;
implicit_declaration = res == BOOL_FALSE;
}
if (!type && !implicit_declaration)
@@ -993,8 +997,7 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond
case EXPR_CATCH_UNWRAP:
if (cond_type != COND_TYPE_UNWRAP_BOOL && cond_type != COND_TYPE_UNWRAP)
{
SEMA_ERROR(expr, "Catch unwrapping is only allowed inside of a 'while' or 'if' conditional, maybe '@catch(<expr>)' will do what you need?");
return false;
RETURN_SEMA_ERROR(expr, "Catch unwrapping is only allowed inside of a 'while' or 'if' conditional, maybe '@catch(<expr>)' will do what you need?");
}
return sema_analyse_catch_unwrap(context, expr);
default:
@@ -1013,7 +1016,9 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond
// Does the identifier exist in the parent scope?
// then again it can't be an any unwrap.
if (sema_symbol_is_defined_in_scope(context, left->identifier_expr.ident)) goto NORMAL_EXPR;
BoolErr defined_in_scope = sema_symbol_is_defined_in_scope(context, left->identifier_expr.ident);
if (defined_in_scope == BOOL_ERR) return false;
if (defined_in_scope == BOOL_TRUE) goto NORMAL_EXPR;
Expr *right = exprptr(expr->binary_expr.right);
bool is_deref = right->expr_kind == EXPR_UNARY && right->unary_expr.operator == UNARYOP_DEREF;

View File

@@ -202,12 +202,8 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
}
Decl *decl = sema_resolve_symbol(context, type_info->unresolved.name, type_info->unresolved.path, type_info->span);
assert(decl);
// Already handled
if (!decl_ok(decl))
{
return type_info_poison(type_info);
}
if (!decl) return type_info_poison(type_info);
decl = decl_flatten(decl);
switch (decl->decl_kind)

View File

@@ -384,58 +384,6 @@ bool type_flat_is_boolintlike(Type *type)
return kind == TYPE_BOOL || (kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST);
}
Decl *type_no_export(Type *type)
{
RETRY:
switch (type->type_kind)
{
case TYPE_POISONED:
case TYPE_UNTYPED_LIST:
case TYPE_WILDCARD:
case TYPE_MEMBER:
case TYPE_TYPEINFO:
return NULL;
case TYPE_VOID:
case TYPE_BOOL:
case ALL_INTS:
case ALL_FLOATS:
case TYPE_ANY:
case TYPE_INTERFACE:
case TYPE_ANYFAULT:
case TYPE_TYPEID:
return NULL;
case TYPE_POINTER:
type = type->pointer;
goto RETRY;
case TYPE_FUNC_PTR:
type = type->pointer;
FALLTHROUGH;
case TYPE_FUNC_RAW:
case TYPE_ENUM:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_FAULTTYPE:
case TYPE_DISTINCT:
case TYPE_BITSTRUCT:
case TYPE_TYPEDEF:
if (!type->decl || type->decl->is_export) return NULL;
return type->decl;
case TYPE_SLICE:
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_INFERRED_ARRAY:
type = type->array.base;
goto RETRY;
case TYPE_VECTOR:
case TYPE_INFERRED_VECTOR:
return NULL;
case TYPE_OPTIONAL:
type = type->optional;
goto RETRY;
}
UNREACHABLE
}
bool type_is_int128(Type *type)
{

View File

@@ -0,0 +1,32 @@
module abc;
import std::math;
def Vec2f = std::math::vector::Vec2f @weak;
fn Vec2f foo(Vec2f a) { return a * 2; }
module gog;
import std::math;
def Vec2f = std::math::vector::Vec2f;
module deef;
import gog;
def Vec2f = gog::Vec2f @weak;
fn Vec2f foo(Vec2f a) { return a * 2; }
module test;
import abc;
import std::math;
fn void test()
{
Vec2f a;
abc::foo(a);
}
module test2;
import abc;
import deef;
fn void test2()
{
Vec2f a; // #error: abc::Vec2f or deef::Vec2f
abc::foo(a);
}

View File

@@ -0,0 +1,32 @@
module abc;
import std::math;
def Vec2f = std::math::vector::Vec2f @weak;
fn Vec2f foo(Vec2f a) { return a * 2; }
module gog;
import std::math;
def Vec2f = std::math::vector::Vec2f @weak;
module deef;
import gog;
def Vec2f = gog::Vec2f @weak;
fn Vec2f foo(Vec2f a) { return a * 2; }
module test;
import abc;
import std::math;
fn void test()
{
Vec2f a;
abc::foo(a);
}
module test2;
import abc;
import deef;
fn void test2()
{
Vec2f a;
abc::foo(a);
}

View File

@@ -23,5 +23,5 @@ fn void test2()
c = foo::b;
c = bar::b;
c = foo::a;
c = b; // #error: global variable needs a path prefix (e.g. 'bar::b')
c = b; // #error: global variable needs a path prefix (e.g. 'foo::b')
}