aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp158
1 files changed, 134 insertions, 24 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index 055d0d356..e1c827529 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -504,6 +504,7 @@ enum VettedEntityKind {
VettedEntity_Unused,
VettedEntity_Shadowed,
+ VettedEntity_Shadowed_And_Unused,
};
struct VettedEntity {
VettedEntityKind kind;
@@ -625,12 +626,18 @@ void check_scope_usage(Checker *c, Scope *scope) {
MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) {
Entity *e = scope->elements.entries[i].value;
if (e == nullptr) continue;
- VettedEntity ve = {};
- if (vet_unused && check_vet_unused(c, e, &ve)) {
- array_add(&vetted_entities, ve);
- }
- if (vet_shadowing && check_vet_shadowing(c, e, &ve)) {
- array_add(&vetted_entities, ve);
+ VettedEntity ve_unused = {};
+ VettedEntity ve_shadowed = {};
+ bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused);
+ bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed);
+ if (is_unused && is_shadowed) {
+ VettedEntity ve_both = ve_shadowed;
+ ve_both.kind = VettedEntity_Shadowed_And_Unused;
+ array_add(&vetted_entities, ve_both);
+ } else if (is_unused) {
+ array_add(&vetted_entities, ve_unused);
+ } else if (is_shadowed) {
+ array_add(&vetted_entities, ve_shadowed);
}
}
@@ -642,16 +649,18 @@ void check_scope_usage(Checker *c, Scope *scope) {
Entity *other = ve.other;
String name = e->token.string;
- if (build_context.vet) {
+ if (ve.kind == VettedEntity_Shadowed_And_Unused) {
+ error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
+ } else if (build_context.vet) {
switch (ve.kind) {
case VettedEntity_Unused:
error(e->token, "'%.*s' declared but not used", LIT(name));
break;
case VettedEntity_Shadowed:
if (e->flags&EntityFlag_Using) {
- error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line);
+ error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line);
} else {
- error(e->token, "Declaration of '%.*s' shadows declaration at line %lld", LIT(name), cast(long long)other->token.pos.line);
+ error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line);
}
break;
default:
@@ -688,12 +697,17 @@ void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
ptr_set_add(&d->deps, e);
mutex_unlock(&info->deps_mutex);
}
-void add_type_info_dependency(DeclInfo *d, Type *type) {
+void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type, bool require_mutex) {
if (d == nullptr) {
return;
}
- // NOTE(bill): no mutex is required here because the only procedure calling it is wrapped in a mutex already
+ if (require_mutex) {
+ mutex_lock(&info->deps_mutex);
+ }
ptr_set_add(&d->type_info_deps, type);
+ if (require_mutex) {
+ mutex_unlock(&info->deps_mutex);
+ }
}
AstPackage *get_core_package(CheckerInfo *info, String name) {
@@ -919,6 +933,16 @@ void init_universal(void) {
add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]);
}
+ {
+ GlobalEnumValue values[ErrorPosStyle_COUNT] = {
+ {"Default", ErrorPosStyle_Default},
+ {"Unix", ErrorPosStyle_Unix},
+ };
+
+ auto fields = add_global_enum_type(str_lit("Odin_Error_Pos_Style_Type"), values, gb_count_of(values));
+ add_global_enum_constant(fields, "ODIN_ERROR_POS_STYLE", build_context.ODIN_ERROR_POS_STYLE);
+ }
+
add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG);
add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT);
@@ -1620,7 +1644,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
return;
}
- add_type_info_dependency(c->decl, t);
+ add_type_info_dependency(c->info, c->decl, t, false);
auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
@@ -1749,6 +1773,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
} else {
add_type_info_type_internal(c, t_type_info_ptr);
}
+ add_type_info_type_internal(c, bt->Union.polymorphic_params);
for_array(i, bt->Union.variants) {
add_type_info_type_internal(c, bt->Union.variants[i]);
}
@@ -1772,6 +1797,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
}
}
}
+ add_type_info_type_internal(c, bt->Struct.polymorphic_params);
for_array(i, bt->Struct.fields) {
Entity *f = bt->Struct.fields[i];
add_type_info_type_internal(c, f->type);
@@ -1965,6 +1991,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
} else {
add_min_dep_type_info(c, t_type_info_ptr);
}
+ add_min_dep_type_info(c, bt->Union.polymorphic_params);
for_array(i, bt->Union.variants) {
add_min_dep_type_info(c, bt->Union.variants[i]);
}
@@ -1988,6 +2015,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
}
}
}
+ add_min_dep_type_info(c, bt->Struct.polymorphic_params);
for_array(i, bt->Struct.fields) {
Entity *f = bt->Struct.fields[i];
add_min_dep_type_info(c, f->type);
@@ -3479,9 +3507,12 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
if (entity_visibility_kind == EntityVisiblity_Public &&
(c->scope->flags&ScopeFlag_File) &&
- c->scope->file &&
- (c->scope->file->flags & AstFile_IsPrivate)) {
- entity_visibility_kind = EntityVisiblity_PrivateToPackage;
+ c->scope->file) {
+ if (c->scope->file->flags & AstFile_IsPrivateFile) {
+ entity_visibility_kind = EntityVisiblity_PrivateToFile;
+ } else if (c->scope->file->flags & AstFile_IsPrivatePkg) {
+ entity_visibility_kind = EntityVisiblity_PrivateToPackage;
+ }
}
if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) {
@@ -3572,9 +3603,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
if (is_ast_type(init)) {
e = alloc_entity_type_name(d->scope, token, nullptr);
- // if (vd->type != nullptr) {
- // error(name, "A type declaration cannot have an type parameter");
- // }
} else if (init->kind == Ast_ProcLit) {
if (c->scope->flags&ScopeFlag_Type) {
error(name, "Procedure declarations are not allowed within a struct");
@@ -3677,6 +3705,59 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) {
check_collect_entities(&c, block->stmts);
}
+bool correct_single_type_alias(CheckerContext *c, Entity *e) {
+ if (e->kind == Entity_Constant) {
+ DeclInfo *d = e->decl_info;
+ if (d != nullptr && d->init_expr != nullptr) {
+ Ast *init = d->init_expr;
+ Entity *alias_of = check_entity_from_ident_or_selector(c, init, true);
+ if (alias_of != nullptr && alias_of->kind == Entity_TypeName) {
+ e->kind = Entity_TypeName;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) {
+ isize n = s->elements.entries.count;
+ bool correction = false;
+ for (isize i = n-1; i >= 0; i--) {
+ correction |= correct_single_type_alias(c, s->elements.entries[i].value);
+ }
+ return correction;
+}
+bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) {
+ isize n = s->elements.entries.count;
+ bool correction = false;
+ for (isize i = 0; i < n; i++) {
+ correction |= correct_single_type_alias(c, s->elements.entries[i].value);
+ }
+ return correction;
+}
+
+
+void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) {
+ // NOTE(bill, 2022-02-04): This is used to solve the problem caused by type aliases
+ // of type aliases being "confused" as constants
+ //
+ // A :: C
+ // B :: A
+ // C :: struct {b: ^B}
+ //
+ // See @TypeAliasingProblem for more information
+ for (;;) {
+ bool corrections = false;
+ corrections |= correct_type_alias_in_scope_backwards(c, s);
+ corrections |= correct_type_alias_in_scope_forwards(c, s);
+ if (!corrections) {
+ return;
+ }
+ }
+}
+
+
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes) {
AstFile *curr_file = nullptr;
@@ -3748,6 +3829,7 @@ void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes) {
}
}
+ // correct_type_aliases(c);
// NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source
@@ -4393,10 +4475,11 @@ bool collect_file_decls(CheckerContext *ctx, Slice<Ast *> const &decls) {
for_array(i, decls) {
if (collect_file_decl(ctx, decls[i])) {
+ correct_type_aliases_in_scope(ctx, ctx->scope);
return true;
}
}
-
+ correct_type_aliases_in_scope(ctx, ctx->scope);
return false;
}
@@ -4666,6 +4749,15 @@ void check_import_entities(Checker *c) {
}
add_untyped_expressions(ctx.info, &untyped);
}
+
+ for_array(i, pkg->files) {
+ AstFile *f = pkg->files[i];
+ reset_checker_context(&ctx, f, &untyped);
+ ctx.collect_delayed_decls = false;
+
+ correct_type_aliases_in_scope(&ctx, pkg->scope);
+ }
+
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
reset_checker_context(&ctx, f, &untyped);
@@ -4887,6 +4979,9 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc
bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0;
+ bool type_assert = (pi->tags & ProcTag_type_assert) != 0;
+ bool no_type_assert = (pi->tags & ProcTag_no_type_assert) != 0;
+
if (bounds_check) {
ctx.state_flags |= StateFlag_bounds_check;
ctx.state_flags &= ~StateFlag_no_bounds_check;
@@ -4894,6 +4989,15 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc
ctx.state_flags |= StateFlag_no_bounds_check;
ctx.state_flags &= ~StateFlag_bounds_check;
}
+
+ if (type_assert) {
+ ctx.state_flags |= StateFlag_type_assert;
+ ctx.state_flags &= ~StateFlag_no_type_assert;
+ } else if (no_type_assert) {
+ ctx.state_flags |= StateFlag_no_type_assert;
+ ctx.state_flags &= ~StateFlag_type_assert;
+ }
+
if (pi->body != nullptr && e != nullptr) {
GB_ASSERT((e->flags & EntityFlag_ProcBodyChecked) == 0);
}
@@ -5307,12 +5411,18 @@ void check_unique_package_names(Checker *c) {
string_map_set(&pkgs, key, pkg);
continue;
}
+ auto *curr = pkg->files[0]->pkg_decl;
+ auto *prev = (*found)->files[0]->pkg_decl;
+ if (curr == prev) {
+ // NOTE(bill): A false positive was found, ignore it
+ continue;
+ }
- error(pkg->files[0]->pkg_decl, "Duplicate declaration of 'package %.*s'", LIT(name));
+ error(curr, "Duplicate declaration of 'package %.*s'", LIT(name));
error_line("\tA package name must be unique\n"
"\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
"\tA package name is required for link name prefixing to have a consistent ABI\n");
- error((*found)->files[0]->pkg_decl, "found at previous location");
+ error(prev, "found at previous location");
}
}
@@ -5504,9 +5614,6 @@ void check_parsed_files(Checker *c) {
TIME_SECTION("calculate global init order");
calculate_global_init_order(c);
- TIME_SECTION("generate minimum dependency set");
- generate_minimum_dependency_set(c, c->info.entry_point);
-
TIME_SECTION("check test procedures");
check_test_procedures(c);
@@ -5517,6 +5624,9 @@ void check_parsed_files(Checker *c) {
add_type_info_for_type_definitions(c);
check_merge_queues_into_arrays(c);
+ TIME_SECTION("generate minimum dependency set");
+ generate_minimum_dependency_set(c, c->info.entry_point);
+
TIME_SECTION("check entry point");
if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) {
Scope *s = c->info.init_scope;