mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
New import rules.
This commit is contained in:
committed by
Christoffer Lerno
parent
2d608a4d51
commit
09d50ebf6c
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::builtin;
|
||||
import libc;
|
||||
|
||||
fault VarCastResult
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::mem;
|
||||
import libc;
|
||||
|
||||
private fn void*! null_allocator_fn(void *data, usize bytes, usize alignment, void* old_pointer, AllocationKind kind)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module hello_world;
|
||||
|
||||
import std;
|
||||
import bar;
|
||||
$if (env::OS_TYPE == OsType.WIN32):
|
||||
fn int test_doubler(int x)
|
||||
{
|
||||
|
||||
@@ -1258,6 +1258,9 @@ typedef struct Module_
|
||||
Decl** generic_cache;
|
||||
HTable symbols;
|
||||
struct CompilationUnit_ **units;
|
||||
Module *parent_module;
|
||||
Module *top_module;
|
||||
Module **sub_modules;
|
||||
} Module;
|
||||
|
||||
|
||||
@@ -1322,6 +1325,13 @@ typedef struct
|
||||
LexMode mode;
|
||||
} Lexer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
uint32_t max_load;
|
||||
DeclId *entries;
|
||||
} DeclTable;
|
||||
|
||||
typedef struct CompilationUnit_
|
||||
{
|
||||
@@ -1405,13 +1415,6 @@ typedef struct SemaContext_
|
||||
Expr *return_expr;
|
||||
} SemaContext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
uint32_t max_load;
|
||||
DeclId *entries;
|
||||
} DeclTable;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -1535,6 +1538,7 @@ typedef struct
|
||||
{
|
||||
Decl *ambiguous_other_decl;
|
||||
Decl *private_decl;
|
||||
Decl *maybe_decl;
|
||||
Path *path;
|
||||
SourceSpan span;
|
||||
const char *symbol;
|
||||
|
||||
@@ -686,6 +686,8 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
ANALYSIS_NOT_BEGUN,
|
||||
ANALYSIS_MODULE_HIERARCHY,
|
||||
ANALYSIS_MODULE_TOP,
|
||||
ANALYSIS_IMPORTS,
|
||||
ANALYSIS_REGISTER_GLOBALS,
|
||||
ANALYSIS_CONDITIONAL_COMPILATION,
|
||||
|
||||
@@ -63,6 +63,8 @@ void sema_context_init(SemaContext *context, CompilationUnit *unit);
|
||||
void sema_context_destroy(SemaContext *context);
|
||||
Decl **global_context_acquire_locals_list(void);
|
||||
void generic_context_release_locals_list(Decl **);
|
||||
void sema_analyse_pass_top(Module *module);
|
||||
void sema_analyse_pass_module_hierarchy(Module *module);
|
||||
void sema_analysis_pass_process_imports(Module *module);
|
||||
void sema_analysis_pass_register_globals(Module *module);
|
||||
void sema_analysis_pass_conditional_compilation(Module *module);
|
||||
|
||||
@@ -156,6 +156,87 @@ static Decl *sema_find_decl_in_global(DeclTable *table, Module **module_list, Na
|
||||
return decl;
|
||||
}
|
||||
|
||||
static bool decl_is_visible(CompilationUnit *unit, Decl *decl)
|
||||
{
|
||||
Module *module = decl->module;
|
||||
// 1. Same module as unit -> ok
|
||||
if (module == unit->module) return true;
|
||||
Module *top = module->top_module;
|
||||
// 2. Same top module as unit -> ok
|
||||
if (top == unit->module->top_module) return true;
|
||||
|
||||
VECEACH(unit->imports, i)
|
||||
{
|
||||
Decl *import = unit->imports[i];
|
||||
Module *import_module = import->module;
|
||||
// 3. Same as import
|
||||
if (import_module == module) return true;
|
||||
// 4. If import and decl doesn't share a top module -> no match
|
||||
if (import_module->top_module != top) continue;
|
||||
Module *search = module->parent_module;
|
||||
// 5. Start upward from the decl module
|
||||
// break if no parent or we reached the import module.
|
||||
while (search && search != import_module) search = search->parent_module;
|
||||
// 6. We found the import module
|
||||
if (search) return true;
|
||||
// 7. Otherwise go to next
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Decl *sema_find_decl_in_global_new(CompilationUnit *unit, DeclTable *table, Module **module_list, NameResolve *name_resolve, bool want_generic)
|
||||
{
|
||||
const char *symbol = name_resolve->symbol;
|
||||
Path *path = name_resolve->path;
|
||||
DeclId decl_ids = decltable_get(table, symbol);
|
||||
Decl *maybe_decl = NULL;
|
||||
// We might have no match at all.
|
||||
if (!decl_ids)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
Decl *decls = declptr(decl_ids);
|
||||
// There might just be a single match.
|
||||
if (decls->decl_kind != DECL_DECLARRAY)
|
||||
{
|
||||
if (path && !matches_subpath(decls->module->name, path)) return NULL;
|
||||
if (!decl_is_visible(unit, decls))
|
||||
{
|
||||
name_resolve->maybe_decl = decls;
|
||||
return NULL;
|
||||
}
|
||||
name_resolve->private_decl = NULL;
|
||||
return decls;
|
||||
}
|
||||
|
||||
// Else go through the list
|
||||
Decl **decl_list = decls->decl_list;
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *decl = NULL;
|
||||
VECEACH(decl_list, i)
|
||||
{
|
||||
Decl *candidate = decl_list[i];
|
||||
if (path && !matches_subpath(candidate->module->name, path)) continue;
|
||||
if (!decl_is_visible(unit, candidate))
|
||||
{
|
||||
maybe_decl = candidate;
|
||||
continue;
|
||||
}
|
||||
if (!ambiguous)
|
||||
{
|
||||
ambiguous = decl;
|
||||
decl = candidate;
|
||||
}
|
||||
}
|
||||
name_resolve->ambiguous_other_decl = ambiguous;
|
||||
name_resolve->private_decl = NULL;
|
||||
name_resolve->maybe_decl = maybe_decl;
|
||||
return decl;
|
||||
}
|
||||
|
||||
static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_resolve)
|
||||
{
|
||||
Path *path = name_resolve->path;
|
||||
@@ -184,7 +265,7 @@ static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_re
|
||||
decl = sema_find_decl_in_imports(unit->imports, name_resolve, false);
|
||||
|
||||
// 4. Go to global search
|
||||
return decl ? decl : sema_find_decl_in_global(&global_context.symbols, global_context.module_list, name_resolve, false);
|
||||
return decl ? decl : sema_find_decl_in_global_new(unit, &global_context.symbols, global_context.module_list, name_resolve, false);
|
||||
}
|
||||
|
||||
static inline Decl *sema_find_local(SemaContext *context, const char *symbol)
|
||||
@@ -240,7 +321,7 @@ static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name
|
||||
if (decl) return decl;
|
||||
|
||||
decl = sema_find_decl_in_imports(unit->imports, name_resolve, false);
|
||||
return decl ? decl : sema_find_decl_in_global(&global_context.symbols, NULL, name_resolve, false);
|
||||
return decl ? decl : sema_find_decl_in_global_new(context->unit, &global_context.symbols, NULL, name_resolve, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +347,24 @@ static void sema_report_error_on_decl(Decl *found, NameResolve *name_resolve)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!found && name_resolve->maybe_decl)
|
||||
{
|
||||
const char *maybe_name = decl_to_name(name_resolve->maybe_decl);
|
||||
const char *module_name = name_resolve->maybe_decl->module->name->module;
|
||||
if (path_name)
|
||||
{
|
||||
sema_error_at(span, "Did you mean the %s '%s::%s' in module %s? If so please add 'import %s'.",
|
||||
maybe_name, module_name, symbol, module_name, module_name);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_error_at(span, "Did you mean the %s '%s' in module %s? If so please add 'import %s'.",
|
||||
maybe_name, symbol, module_name, module_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (name_resolve->ambiguous_other_decl)
|
||||
{
|
||||
assert(found);
|
||||
@@ -311,7 +409,7 @@ INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_
|
||||
if (name_resolve->path)
|
||||
{
|
||||
decl = sema_resolve_path_symbol(context, name_resolve);
|
||||
if (!decl && !name_resolve->path_found)
|
||||
if (!decl && !name_resolve->maybe_decl && !name_resolve->path_found)
|
||||
{
|
||||
if (!name_resolve->suppress_error) return NULL;
|
||||
SEMA_ERROR(name_resolve->path, "Unknown module '%.*s', did you type it right?", name_resolve->path->len, name_resolve->path->module);
|
||||
@@ -408,9 +506,9 @@ Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name
|
||||
Decl *decl = sema_find_decl_in_imports(unit->imports, name_resolve, true);
|
||||
if (!decl)
|
||||
{
|
||||
decl = sema_find_decl_in_global(&global_context.generic_symbols,
|
||||
global_context.generic_module_list,
|
||||
name_resolve, true);
|
||||
decl = sema_find_decl_in_global_new(unit, &global_context.generic_symbols,
|
||||
global_context.generic_module_list,
|
||||
name_resolve, true);
|
||||
}
|
||||
// 14. Error report
|
||||
if (!decl || name_resolve->ambiguous_other_decl)
|
||||
|
||||
@@ -4,6 +4,60 @@
|
||||
|
||||
#include "sema_internal.h"
|
||||
|
||||
void parent_path(StringSlice *slice)
|
||||
{
|
||||
for (int i = (int)slice->len - 1; i >= 0; i--)
|
||||
{
|
||||
if (slice->ptr[i] == ':')
|
||||
{
|
||||
slice->len = i - 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
slice->len = 0;
|
||||
}
|
||||
|
||||
void sema_analyse_pass_top(Module *module)
|
||||
{
|
||||
Module *parent = module;
|
||||
while (parent->parent_module) parent = parent->parent_module;
|
||||
module->top_module = parent;
|
||||
}
|
||||
|
||||
void sema_analyse_pass_module_hierarchy(Module *module)
|
||||
{
|
||||
const char *name = module->name->module;
|
||||
StringSlice slice = slice_from_string(name);
|
||||
// foo::bar::baz -> foo::bar
|
||||
parent_path(&slice);
|
||||
// foo -> return, no parent
|
||||
if (!slice.len) return;
|
||||
|
||||
|
||||
unsigned module_count = vec_size(global_context.module_list);
|
||||
for (int i = 0; i < module_count; i++)
|
||||
{
|
||||
Module *checked = global_context.module_list[i];
|
||||
Path *checked_name = checked->name;
|
||||
if (checked_name->len != slice.len) continue;
|
||||
// Found the parent! We're done, we add this parent
|
||||
// and this as a child.
|
||||
if (memcmp(checked_name->module, slice.ptr, slice.len) == 0)
|
||||
{
|
||||
module->parent_module = checked;
|
||||
vec_add(module->sub_modules, module);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No match, so we create a synthetic module.
|
||||
Path *path = path_create_from_string(slice.ptr, slice.len, module->name->span);
|
||||
DEBUG_LOG("Creating parent module for %s: %s", module->name->module, path->module);
|
||||
Module *parent_module = compiler_find_or_create_module(path, NULL, false /* always public */);
|
||||
module->parent_module = parent_module;
|
||||
vec_add(parent_module->sub_modules, module);
|
||||
sema_analyze_stage(parent_module, ANALYSIS_MODULE_HIERARCHY);
|
||||
}
|
||||
|
||||
|
||||
void sema_analysis_pass_process_imports(Module *module)
|
||||
{
|
||||
@@ -57,17 +111,6 @@ void sema_analysis_pass_process_imports(Module *module)
|
||||
// 8. Assign the module.
|
||||
DEBUG_LOG("* Import of %s.", path->module);
|
||||
import->module = import_module;
|
||||
for (unsigned j = 0; j < i; j++)
|
||||
{
|
||||
// 9. We might run into multiple imports of the same package.
|
||||
if (import->module == unit->imports[j]->module)
|
||||
{
|
||||
SEMA_ERROR(import, "Module '%s' was imported more than once, please remove the duplicates.", path->module);
|
||||
SEMA_PREV(unit->imports[j], "Previous import was here");
|
||||
decl_poison(import);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
import_count += imports;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,12 @@ void sema_analyze_stage(Module *module, AnalysisStage stage)
|
||||
{
|
||||
case ANALYSIS_NOT_BEGUN:
|
||||
UNREACHABLE
|
||||
case ANALYSIS_MODULE_HIERARCHY:
|
||||
sema_analyse_pass_module_hierarchy(module);
|
||||
break;
|
||||
case ANALYSIS_MODULE_TOP:
|
||||
sema_analyse_pass_top(module);
|
||||
break;
|
||||
case ANALYSIS_IMPORTS:
|
||||
sema_analysis_pass_process_imports(module);
|
||||
break;
|
||||
@@ -228,6 +234,7 @@ static void analyze_generic_module(Module *module)
|
||||
{
|
||||
register_generic_decls(module, module->units[index]->global_decls);
|
||||
}
|
||||
sema_analyze_stage(module, ANALYSIS_MODULE_HIERARCHY);
|
||||
}
|
||||
|
||||
static void sema_analyze_to_stage(AnalysisStage stage)
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.4"
|
||||
#define COMPILER_VERSION "0.2.5"
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
|
||||
struct St12
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
|
||||
import std;
|
||||
fn int foo()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
fn void test()
|
||||
{
|
||||
int x = foo();
|
||||
@@ -13,7 +14,7 @@ fn void test()
|
||||
}
|
||||
|
||||
|
||||
// #expect: unreachable.ll
|
||||
/* #expect: unreachable.ll
|
||||
|
||||
|
||||
define void @unreachable.test() #0 {
|
||||
@@ -29,7 +30,7 @@ if.then: ; preds = %entry
|
||||
ret void
|
||||
|
||||
if.exit: ; preds = %entry
|
||||
call void @"std::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 11)
|
||||
call void @"std::builtin.panic"(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0), i32 12)
|
||||
unreachable
|
||||
|
||||
after.unreachable: ; No predecessors!
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import libc;
|
||||
|
||||
enum Foo : uint (int val, char* testme)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
|
||||
import std;
|
||||
import libc;
|
||||
|
||||
struct Doc { Head *head; }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
import libc;
|
||||
fault Foo
|
||||
{
|
||||
X,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import libc;
|
||||
fn int! abc()
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import libc;
|
||||
fault Tester { FOO }
|
||||
|
||||
fn int! abc()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import libc;
|
||||
fault Tester { FOO }
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// #target: macos-x64
|
||||
module examples;
|
||||
|
||||
import std::io;
|
||||
import libc;
|
||||
import std;
|
||||
|
||||
fn void example_for()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module demo;
|
||||
import libc;
|
||||
import std::io;
|
||||
|
||||
fault MathError
|
||||
|
||||
@@ -11,6 +11,7 @@ fn Type addMult(Type x, Type a, Type b)
|
||||
}
|
||||
|
||||
module test;
|
||||
import gen;
|
||||
|
||||
define intMult = gen::mult<int>;
|
||||
define doubleAddMult = gen::addMult<double>;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import std::math;
|
||||
fn void main()
|
||||
{
|
||||
void* foekf = &math::log;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module test;
|
||||
import std::mem;
|
||||
import std::mem; // #error: was imported more
|
||||
import hello_world; // #error: No module named
|
||||
import test; // #error: Importing the current
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ module dde;
|
||||
|
||||
fn void test()
|
||||
{
|
||||
abc::test();
|
||||
Foo f;
|
||||
abc::test(); // #error: Did you mean the function 'abc::test'
|
||||
Foo f; // #error: Did you mean the struct 'Foo'
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// #target: macos-x64
|
||||
import std::io;
|
||||
import std::mem;
|
||||
import libc;
|
||||
union Baz
|
||||
{
|
||||
int x;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import std::io;
|
||||
import std::mem;
|
||||
import libc;
|
||||
union Baz
|
||||
{
|
||||
int x;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module foo;
|
||||
import std::io;
|
||||
import libc;
|
||||
|
||||
macro foo(y)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user