summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analysis/typecheck.c2
-rw-r--r--src/lsp/lsp_project.c2
-rw-r--r--src/main.c6
-rw-r--r--src/parser/parser.h15
-rw-r--r--src/parser/parser_expr.c5
-rw-r--r--src/parser/parser_struct.c28
-rw-r--r--src/parser/parser_type.c75
-rw-r--r--src/parser/parser_utils.c56
8 files changed, 178 insertions, 11 deletions
diff --git a/src/analysis/typecheck.c b/src/analysis/typecheck.c
index 2b06bb4..b1b7f24 100644
--- a/src/analysis/typecheck.c
+++ b/src/analysis/typecheck.c
@@ -97,6 +97,7 @@ static void check_use_validity(TypeChecker *tc, ASTNode *var_node, Symbol *sym)
static void mark_symbol_moved(TypeChecker *tc, Symbol *sym, ASTNode *context_node)
{
+ (void)context_node;
if (!sym)
{
return;
@@ -112,6 +113,7 @@ static void mark_symbol_moved(TypeChecker *tc, Symbol *sym, ASTNode *context_nod
static void mark_symbol_valid(TypeChecker *tc, Symbol *sym)
{
+ (void)tc;
if (sym)
{
sym->is_moved = 0;
diff --git a/src/lsp/lsp_project.c b/src/lsp/lsp_project.c
index 71e7d3c..7d19d0a 100644
--- a/src/lsp/lsp_project.c
+++ b/src/lsp/lsp_project.c
@@ -38,6 +38,8 @@ void lsp_project_init(const char *root_path)
void lsp_default_on_error(void *data, Token t, const char *msg)
{
(void)data;
+ (void)t;
+ (void)msg;
// We can log it if we want, but standard zpanic_at already printed it to stderr.
// The important thing is that we exist so zpanic_at returns.
// Maybe we suppress duplicates or just let it pass.
diff --git a/src/main.c b/src/main.c
index da1bec6..17cbdf6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -269,6 +269,12 @@ int main(int argc, char **argv)
return 1;
}
+ if (!validate_types(&ctx))
+ {
+ // Type validation failed
+ return 1;
+ }
+
if (g_config.mode_check)
{
// Just verify
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 6f62435..6ac55bf 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -268,8 +268,23 @@ struct ParserContext
int is_repl; // REPL mode flag
int has_async; // Track if async features are used
int in_defer_block; // Track if currently parsing inside a defer block
+
+ // Type Validation
+ struct TypeUsage *pending_type_validations;
+ int is_speculative; // Flag to suppress side effects during speculative parsing
};
+typedef struct TypeUsage
+{
+ char *name;
+ Token location;
+ struct TypeUsage *next;
+} TypeUsage;
+
+// Type validation prototypes
+void register_type_usage(ParserContext *ctx, const char *name, Token t);
+int validate_types(ParserContext *ctx);
+
// Token helpers
char *token_strdup(Token t);
int is_token(Token t, const char *s);
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index 990942d..ae7abe9 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -1611,6 +1611,8 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
lexer_next(&lookahead);
int valid_generic = 0;
+ int saved_speculative = ctx->is_speculative;
+ ctx->is_speculative = 1;
while (1)
{
parse_type(ctx, &lookahead);
@@ -1625,6 +1627,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
break;
}
+ ctx->is_speculative = saved_speculative;
if (valid_generic)
{
@@ -2433,7 +2436,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
register_tuple(ctx, sig);
- char tuple_name[256];
+ char tuple_name[1024];
sprintf(tuple_name, "Tuple_%s", sig);
char *code = xmalloc(4096);
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
index 600d60d..01d1156 100644
--- a/src/parser/parser_struct.c
+++ b/src/parser/parser_struct.c
@@ -166,6 +166,11 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
}
}
+ if (gen_param)
+ {
+ register_generic(ctx, gen_param);
+ }
+
// Check for "for" (Trait impl)
Token pk = lexer_peek(l);
if (pk.type == TOK_FOR ||
@@ -324,6 +329,10 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
register_impl_template(ctx, name2, gp, n);
}
+ if (gen_param)
+ {
+ ctx->known_generics_count--;
+ }
return n;
}
else
@@ -463,6 +472,10 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
n->impl.methods = h;
register_impl_template(ctx, name1, gen_param, n);
ctx->current_impl_struct = NULL;
+ if (gen_param)
+ {
+ ctx->known_generics_count--;
+ }
return NULL; // Do not emit generic template
}
else
@@ -549,6 +562,11 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
n->impl.struct_name = name1;
n->impl.methods = h;
add_to_impl_list(ctx, n);
+
+ if (gen_param)
+ {
+ ctx->known_generics_count--;
+ }
return n;
}
}
@@ -588,7 +606,11 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
zpanic_at(next, "Expected ',' or '>' in generic parameter list");
}
}
- register_generic(ctx, name);
+
+ for (int i = 0; i < gp_count; i++)
+ {
+ register_generic(ctx, gps[i]);
+ }
}
// Check for prototype (forward declaration)
@@ -798,6 +820,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
if (gp_count > 0)
{
node->strct.is_template = 1;
+ ctx->known_generics_count -= gp_count;
register_template(ctx, name, node);
}
@@ -841,7 +864,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
Token g = lexer_next(l);
gp = token_strdup(g);
lexer_next(l); // eat >
- register_generic(ctx, n.start ? token_strdup(n) : "anon");
+ register_generic(ctx, gp);
}
lexer_next(l); // eat {
@@ -934,6 +957,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
if (gp)
{
node->enm.is_template = 1;
+ ctx->known_generics_count--;
register_template(ctx, node->enm.name, node);
}
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index 4e44c00..b11bedb 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -368,6 +368,76 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
free(name);
return type_new(TYPE_CHAR);
}
+ if (strcmp(name, "long") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I64);
+ }
+ if (strcmp(name, "short") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I16);
+ }
+ if (strcmp(name, "unsigned") == 0)
+ {
+ free(name);
+ return type_new(TYPE_UINT);
+ }
+ if (strcmp(name, "signed") == 0)
+ {
+ free(name);
+ return type_new(TYPE_INT);
+ }
+ if (strcmp(name, "int8_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I8);
+ }
+ if (strcmp(name, "uint8_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_U8);
+ }
+ if (strcmp(name, "int16_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I16);
+ }
+ if (strcmp(name, "uint16_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_U16);
+ }
+ if (strcmp(name, "int32_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I32);
+ }
+ if (strcmp(name, "uint32_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_U32);
+ }
+ if (strcmp(name, "int64_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_I64);
+ }
+ if (strcmp(name, "uint64_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_U64);
+ }
+ if (strcmp(name, "size_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_USIZE);
+ }
+ if (strcmp(name, "ssize_t") == 0)
+ {
+ free(name);
+ return type_new(TYPE_ISIZE);
+ }
// Selective imports ONLY apply when we're NOT in a module context
if (!ctx->current_module_prefix)
@@ -395,6 +465,11 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
name = prefixed_name;
}
+ if (!is_known_generic(ctx, name) && strcmp(name, "Self") != 0)
+ {
+ register_type_usage(ctx, name, t);
+ }
+
Type *ty = type_new(TYPE_STRUCT);
ty->name = name;
ty->is_explicit_struct = explicit_struct;
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 97e6e78..b322881 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -876,10 +876,10 @@ char *replace_in_string(const char *src, const char *old_w, const char *new_w)
while (*p_ptr && *c_ptr)
{
char *p_end = strchr(p_ptr, ',');
- int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+ int p_len = p_end ? (int)(p_end - p_ptr) : (int)strlen(p_ptr);
char *c_end = strchr(c_ptr, ',');
- int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
+ int c_len = c_end ? (int)(c_end - c_ptr) : (int)strlen(c_ptr);
char *curr_p = xmalloc(p_len + 1);
strncpy(curr_p, p_ptr, p_len);
@@ -1007,12 +1007,12 @@ char *replace_type_str(const char *src, const char *param, const char *concrete,
while (*p_ptr && *c_ptr)
{
char *p_end = strchr(p_ptr, ',');
- int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+ int p_len = p_end ? (int)(p_end - p_ptr) : (int)strlen(p_ptr);
char *c_end = strchr(c_ptr, ',');
- int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
+ int c_len = c_end ? (int)(c_end - c_ptr) : (int)strlen(c_ptr);
- if (strlen(src) == p_len && strncmp(src, p_ptr, p_len) == 0)
+ if ((int)strlen(src) == p_len && strncmp(src, p_ptr, p_len) == 0)
{
char *ret = xmalloc(c_len + 1);
strncpy(ret, c_ptr, c_len);
@@ -1299,11 +1299,11 @@ Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os,
while (*p_ptr && *c_ptr)
{
char *p_end = strchr(p_ptr, ',');
- int p_len = p_end ? (p_end - p_ptr) : strlen(p_ptr);
+ int p_len = p_end ? (int)(p_end - p_ptr) : (int)strlen(p_ptr);
char *c_end = strchr(c_ptr, ',');
- int c_len = c_end ? (c_end - c_ptr) : strlen(c_ptr);
+ int c_len = c_end ? (int)(c_end - c_ptr) : (int)strlen(c_ptr);
- if (strlen(t->name) == p_len && strncmp(t->name, p_ptr, p_len) == 0)
+ if ((int)strlen(t->name) == p_len && strncmp(t->name, p_ptr, p_len) == 0)
{
char *c_part = xmalloc(c_len + 1);
strncpy(c_part, c_ptr, c_len);
@@ -1991,6 +1991,8 @@ char *instantiate_function_template(ParserContext *ctx, const char *name, const
char *process_fstring(ParserContext *ctx, const char *content, char ***used_syms, int *count)
{
+ (void)used_syms;
+ (void)count;
char *gen = xmalloc(8192); // Increased buffer size
strcpy(gen, "({ static char _b[4096]; _b[0]=0; char _t[1024]; ");
@@ -3435,3 +3437,41 @@ const char *resolve_plugin(ParserContext *ctx, const char *name_or_alias)
}
return NULL; // Plugin not found
}
+
+// Type Validation
+void register_type_usage(ParserContext *ctx, const char *name, Token t)
+{
+ if (ctx->is_speculative)
+ {
+ return;
+ }
+
+ TypeUsage *u = xmalloc(sizeof(TypeUsage));
+ u->name = xstrdup(name);
+ u->location = t;
+ u->next = ctx->pending_type_validations;
+ ctx->pending_type_validations = u;
+}
+
+int validate_types(ParserContext *ctx)
+{
+ int errors = 0;
+ TypeUsage *u = ctx->pending_type_validations;
+ while (u)
+ {
+ ASTNode *def = find_struct_def(ctx, u->name);
+ const char *alias = find_type_alias(ctx, u->name);
+
+ if (!def && !alias)
+ {
+ SelectiveImport *si = find_selective_import(ctx, u->name);
+ if (!si && !is_trait(u->name))
+ {
+ zpanic_at(u->location, "Unknown type '%s'", u->name);
+ errors++;
+ }
+ }
+ u = u->next;
+ }
+ return errors == 0;
+}