aboutsummaryrefslogtreecommitdiff
path: root/src/check_decl.cpp
diff options
context:
space:
mode:
authorChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
committerChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
commit153e7525b5d64f12deb318d50aee1d9dbeb1fc8e (patch)
treeb8ac88c0788af31bcb3c5041d78306c2120714f6 /src/check_decl.cpp
parentd85893954dccc7833e3d954db641d9fd2a3c7451 (diff)
parent44a303e5778fb8564964d53523634f34f8589489 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src/check_decl.cpp')
-rw-r--r--src/check_decl.cpp247
1 files changed, 163 insertions, 84 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 1a6fad918..ebfc29899 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
}
if (operand->mode == Addressing_Type) {
- gbString t = type_to_string(operand->type);
- error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
- gb_string_free(t);
- e->type = operand->type;
- return nullptr;
+ if (e->type != nullptr && is_type_typeid(e->type)) {
+ add_type_info_type(ctx, operand->type);
+ add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
+ return e->type;
+ } else {
+ gbString t = type_to_string(operand->type);
+ defer (gb_string_free(t));
+ error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
+ if (e->type == nullptr) {
+ error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
+ }
+ e->type = operand->type;
+ return nullptr;
+ }
}
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) {
- rhs_count--;
+ // TODO(bill): Should I ignore invalid parameters?
+ // rhs_count--;
}
}
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
}
-void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
+void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(e);
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
}
-
- bool is_distinct = is_type_distinct(type_expr);
- Ast *te = remove_type_alias_clutter(type_expr);
+ bool is_distinct = is_type_distinct(init_expr);
+ Ast *te = remove_type_alias_clutter(init_expr);
e->type = t_invalid;
String name = e->token.string;
Type *named = alloc_type_named(name, nullptr, e);
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
named->Named.base = base_type(bt);
if (is_distinct && is_type_typeid(e->type)) {
- error(type_expr, "'distinct' cannot be applied to 'typeid'");
+ error(init_expr, "'distinct' cannot be applied to 'typeid'");
is_distinct = false;
}
if (!is_distinct) {
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
e->TypeName.is_type_alias = true;
}
+
+ if (decl->type_expr != nullptr) {
+ Type *t = check_type(ctx, decl->type_expr);
+ if (t != nullptr && !is_type_typeid(t)) {
+ Operand operand = {};
+ operand.mode = Addressing_Type;
+ operand.type = e->type;
+ operand.expr = init_expr;
+ check_assignment(ctx, &operand, t, str_lit("constant declaration"));
+ }
+ }
+
+
// using decl
if (decl->is_using) {
// NOTE(bill): Must be an enum declaration
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
switch (operand.mode) {
case Addressing_Type: {
+ if (e->type != nullptr && !is_type_typeid(e->type)) {
+ check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
+ }
+
e->kind = Entity_TypeName;
e->type = nullptr;
- DeclInfo *d = ctx->decl;
- if (d->type_expr != nullptr) {
- error(e->token, "A type declaration cannot have an type parameter");
- }
- d->type_expr = d->init_expr;
- check_type_decl(ctx, e, d->type_expr, named_type);
+ check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
return;
}
@@ -654,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
- bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 ||
@@ -714,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
- if (pt->result_count == 0 && is_require_results) {
- error(pl->type, "'#require_results' is not needed on a procedure with no results");
+ if (pt->result_count == 0 && ac.require_results) {
+ error(pl->type, "'require_results' is not needed on a procedure with no results");
} else {
- pt->require_results = is_require_results;
+ pt->require_results = ac.require_results;
}
if (ac.link_name.len > 0) {
@@ -791,7 +811,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
-void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
+void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
@@ -805,6 +825,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
DeclInfo *decl = decl_info_of_entity(e);
+ GB_ASSERT(decl == ctx->decl);
if (decl != nullptr) {
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
}
@@ -936,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
ptr_set_destroy(&entity_set);
-
for_array(j, pge->entities) {
Entity *p = pge->entities[j];
if (p->type == t_invalid) {
@@ -962,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
defer (end_error_block());
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
- switch (kind) {
+ bool both_have_where_clauses = false;
+ if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
+ GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
+ GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
+ auto pl = &p->decl_info->proc_lit->ProcLit;
+ auto ql = &q->decl_info->proc_lit->ProcLit;
+
+ // Allow collisions if the procedures both have 'where' clauses and are both polymorphic
+ bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
+ bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
+ both_have_where_clauses = pw && qw;
+ }
+
+ if (!both_have_where_clauses) switch (kind) {
case ProcOverload_Identical:
- error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
// case ProcOverload_CallingConvention:
- // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
// is_invalid = true;
// break;
case ProcOverload_ParamVariadic:
- error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_ResultCount:
case ProcOverload_ResultTypes:
- error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_Polymorphic:
#if 0
- error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
is_invalid = true;
#endif
break;
@@ -1051,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
switch (e->kind) {
case Entity_Variable:
- check_var_decl(&c, e, d->type_expr, d->init_expr);
+ check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName: {
- check_type_decl(&c, e, d->type_expr, named_type);
+ check_type_decl(&c, e, d->init_expr, named_type);
break;
}
case Entity_Procedure:
@@ -1074,6 +1107,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
}
+struct ProcUsingVar {
+ Entity *e;
+ Entity *uvar;
+};
+
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
if (body == nullptr) {
@@ -1098,76 +1136,117 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
ctx->curr_proc_decl = decl;
ctx->curr_proc_sig = type;
- GB_ASSERT(type->kind == Type_Proc);
- if (type->Proc.param_count > 0) {
- TypeTuple *params = &type->Proc.params->Tuple;
- for_array(i, params->variables) {
- Entity *e = params->variables[i];
- if (e->kind != Entity_Variable) {
- continue;
- }
- if (!(e->flags & EntityFlag_Using)) {
- continue;
- }
- bool is_immutable = e->Variable.is_immutable;
- bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
- String name = e->token.string;
- Type *t = base_type(type_deref(e->type));
- if (t->kind == Type_Struct) {
- Scope *scope = t->Struct.scope;
- if (scope == nullptr) {
- scope = scope_of_node(t->Struct.node);
+ ast_node(bs, BlockStmt, body);
+
+ Array<ProcUsingVar> using_entities = {};
+ using_entities.allocator = heap_allocator();
+ defer (array_free(&using_entities));
+
+ {
+ GB_ASSERT(type->kind == Type_Proc);
+ if (type->Proc.param_count > 0) {
+ TypeTuple *params = &type->Proc.params->Tuple;
+ for_array(i, params->variables) {
+ Entity *e = params->variables[i];
+ if (e->kind != Entity_Variable) {
+ continue;
+ }
+ if (!(e->flags & EntityFlag_Using)) {
+ continue;
}
- GB_ASSERT(scope != nullptr);
- for_array(i, scope->elements.entries) {
- Entity *f = scope->elements.entries[i].value;
- if (f->kind == Entity_Variable) {
- Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
- uvar->Variable.is_immutable = is_immutable;
- if (is_value) uvar->flags |= EntityFlag_Value;
-
- Entity *prev = scope_insert(ctx->scope, uvar);
- if (prev != nullptr) {
- error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
- break;
+ bool is_immutable = e->Variable.is_immutable;
+ bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
+ String name = e->token.string;
+ Type *t = base_type(type_deref(e->type));
+ if (t->kind == Type_Struct) {
+ Scope *scope = t->Struct.scope;
+ if (scope == nullptr) {
+ scope = scope_of_node(t->Struct.node);
+ }
+ GB_ASSERT(scope != nullptr);
+ for_array(i, scope->elements.entries) {
+ Entity *f = scope->elements.entries[i].value;
+ if (f->kind == Entity_Variable) {
+ Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
+ uvar->Variable.is_immutable = is_immutable;
+ if (is_value) uvar->flags |= EntityFlag_Value;
+
+ ProcUsingVar puv = {e, uvar};
+ array_add(&using_entities, puv);
+
}
}
+ } else {
+ error(e->token, "'using' can only be applied to variables of type struct");
+ break;
}
- } else {
- error(e->token, "'using' can only be applied to variables of type struct");
- break;
}
}
}
- ast_node(bs, BlockStmt, body);
- // check_open_scope(ctx, body);
- check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
- if (type->Proc.result_count > 0) {
- if (!check_is_terminating(body)) {
- if (token.kind == Token_Ident) {
- error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
- } else {
- // NOTE(bill): Anonymous procedure (lambda)
- error(bs->close, "Missing return statement at the end of the procedure");
+
+ for_array(i, using_entities) {
+ Entity *e = using_entities[i].e;
+ Entity *uvar = using_entities[i].uvar;
+ Entity *prev = scope_insert(ctx->scope, uvar);
+ if (prev != nullptr) {
+ error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
+ break;
+ }
+ }
+
+
+ bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
+ if (!where_clause_ok) {
+ // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
+ return;
+ }
+
+ check_open_scope(ctx, body);
+ {
+ for_array(i, using_entities) {
+ Entity *e = using_entities[i].e;
+ Entity *uvar = using_entities[i].uvar;
+ Entity *prev = scope_insert(ctx->scope, uvar);
+ // NOTE(bill): Don't err here
+ }
+
+ check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
+
+ if (type->Proc.result_count > 0) {
+ if (!check_is_terminating(body)) {
+ if (token.kind == Token_Ident) {
+ error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
+ } else {
+ // NOTE(bill): Anonymous procedure (lambda)
+ error(bs->close, "Missing return statement at the end of the procedure");
+ }
}
}
}
- // check_close_scope(ctx);
+ check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope);
+#if 1
if (decl->parent != nullptr) {
- // NOTE(bill): Add the dependencies from the procedure literal (lambda)
- for_array(i, decl->deps.entries) {
- Entity *e = decl->deps.entries[i].ptr;
- ptr_set_add(&decl->parent->deps, e);
- }
- for_array(i, decl->type_info_deps.entries) {
- Type *t = decl->type_info_deps.entries[i].ptr;
- ptr_set_add(&decl->parent->type_info_deps, t);
+ Scope *ps = decl->parent->scope;
+ if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
+ return;
+ } else {
+ // NOTE(bill): Add the dependencies from the procedure literal (lambda)
+ // But only at the procedure level
+ for_array(i, decl->deps.entries) {
+ Entity *e = decl->deps.entries[i].ptr;
+ ptr_set_add(&decl->parent->deps, e);
+ }
+ for_array(i, decl->type_info_deps.entries) {
+ Type *t = decl->type_info_deps.entries[i].ptr;
+ ptr_set_add(&decl->parent->type_info_deps, t);
+ }
}
}
+#endif
}