New import rules.

This commit is contained in:
Christoffer Lerno
2022-05-23 14:16:26 +02:00
committed by Christoffer Lerno
parent 2d608a4d51
commit 09d50ebf6c
27 changed files with 207 additions and 38 deletions

View File

@@ -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
{

View File

@@ -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)
{

View File

@@ -1,5 +1,6 @@
module hello_world;
import std;
import bar;
$if (env::OS_TYPE == OsType.WIN32):
fn int test_doubler(int x)
{

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.2.4"
#define COMPILER_VERSION "0.2.5"

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module test;
import std;
struct St12
{

View File

@@ -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!

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module test;
import libc;
enum Foo : uint (int val, char* testme)
{

View File

@@ -1,6 +1,6 @@
// #target: macos-x64
module test;
import std;
import libc;
struct Doc { Head *head; }

View File

@@ -1,7 +1,7 @@
// #target: macos-x64
module foo;
import std::io;
import libc;
fault Foo
{
X,

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module test;
import libc;
fn int! abc()
{
return 1;

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module test;
import libc;
fault Tester { FOO }
fn int! abc()

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module test;
import libc;
fault Tester { FOO }

View File

@@ -1,7 +1,7 @@
// #target: macos-x64
module examples;
import std::io;
import libc;
import std;
fn void example_for()
{

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module demo;
import libc;
import std::io;
fault MathError

View File

@@ -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>;

View File

@@ -1,5 +1,6 @@
// #target: macos-x64
module foo;
import std::math;
fn void main()
{
void* foekf = &math::log;

View File

@@ -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

View File

@@ -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'
}

View File

@@ -1,6 +1,7 @@
// #target: macos-x64
import std::io;
import std::mem;
import libc;
union Baz
{
int x;

View File

@@ -2,6 +2,7 @@
import std::io;
import std::mem;
import libc;
union Baz
{
int x;

View File

@@ -1,5 +1,5 @@
module foo;
import std::io;
import libc;
macro foo(y)
{