Browse Source

Delay checking foreign import paths until after global scope is checked

gingerBill 1 year ago
parent
commit
a1b8749e74
5 changed files with 118 additions and 83 deletions
  1. 88 80
      src/checker.cpp
  2. 3 0
      src/checker.hpp
  3. 1 0
      src/entity.cpp
  4. 25 3
      src/parser.cpp
  5. 1 0
      src/parser.hpp

+ 88 - 80
src/checker.cpp

@@ -1283,6 +1283,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
 	mpsc_init(&i->definition_queue, a); //); // 1<<20);
 	mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
 	mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
+	mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
 	mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
 
 	string_map_init(&i->load_directory_cache);
@@ -1307,6 +1308,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
 	mpsc_destroy(&i->definition_queue);
 	mpsc_destroy(&i->required_global_variable_queue);
 	mpsc_destroy(&i->required_foreign_imports_through_force_queue);
+	mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
 
 	map_destroy(&i->objc_msgSend_types);
 	string_map_destroy(&i->load_file_cache);
@@ -4874,105 +4876,112 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
 	return false;
 }
 
-gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
-	if (decl->state_flags & StateFlag_BeenHandled) return;
-	decl->state_flags |= StateFlag_BeenHandled;
+gb_internal void check_foreign_import_fullpaths(Checker *c) {
+	CheckerContext ctx = make_checker_context(c);
 
-	ast_node(fl, ForeignImportDecl, decl);
+	UntypedExprInfoMap untyped = {};
+	defer (map_destroy(&untyped));
 
-	Scope *parent_scope = ctx->scope;
-	GB_ASSERT(parent_scope->flags&ScopeFlag_File);
+	for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_imports_to_check_fullpaths, &e); /**/) {
+		GB_ASSERT(e != nullptr);
+		GB_ASSERT(e->kind == Entity_LibraryName);
+		Ast *decl = e->LibraryName.decl;
+		ast_node(fl, ForeignImportDecl, decl);
 
-	String base_dir = dir_from_path(decl->file()->fullpath);
+		AstFile *f = decl->file();
 
-	auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
+		reset_checker_context(&ctx, f, &untyped);
+		ctx.collect_delayed_decls = false;
 
-	for (Ast *fp_node : fl->filepaths) {
-		Operand op = {};
-		check_expr(ctx, &op, fp_node);
-		if (op.mode != Addressing_Constant && op.value.kind != ExactValue_String) {
-			gbString s = expr_to_string(op.expr);
-			error(fp_node, "Expected a constant string value, got '%s'", s);
-			gb_string_free(s);
-			continue;
-		}
-		if (!is_type_string(op.type)) {
-			gbString s = type_to_string(op.type);
-			error(fp_node, "Expected a constant string value, got value of type '%s'", s);
-			gb_string_free(s);
-			continue;
-		}
+		GB_ASSERT(ctx.scope == e->scope);
 
-		String file_str = op.value.value_string;
-		file_str = string_trim_whitespace(file_str);
+		if (fl->fullpaths.count == 0) {
+			String base_dir = dir_from_path(decl->file()->fullpath);
 
-		String fullpath = file_str;
-		if (allow_check_foreign_filepath()) {
-			String foreign_path = {};
-			bool ok = determine_path_from_string(nullptr, decl, base_dir, file_str, &foreign_path);
-			gb_unused(ok);
-			fullpath = foreign_path;
-		}
-		array_add(&fullpaths, fullpath);
-	}
-	fl->fullpaths = slice_from_array(fullpaths);
+			auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
 
+			for (Ast *fp_node : fl->filepaths) {
+				Operand op = {};
+				check_expr(&ctx, &op, fp_node);
+				if (op.mode != Addressing_Constant && op.value.kind != ExactValue_String) {
+					gbString s = expr_to_string(op.expr);
+					error(fp_node, "Expected a constant string value, got '%s'", s);
+					gb_string_free(s);
+					continue;
+				}
+				if (!is_type_string(op.type)) {
+					gbString s = type_to_string(op.type);
+					error(fp_node, "Expected a constant string value, got value of type '%s'", s);
+					gb_string_free(s);
+					continue;
+				}
 
-	if (fl->fullpaths.count == 0) {
-		return;
-	}
-	String fullpath = fl->fullpaths[0];
-	String library_name = path_to_entity_name(fl->library_name.string, fullpath);
-	if (is_blank_ident(library_name)) {
-		error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
-		return;
-	}
+				String file_str = op.value.value_string;
+				file_str = string_trim_whitespace(file_str);
 
-	for (String const &path : fl->fullpaths) {
-		String ext = path_extension(path);
-		if (str_eq_ignore_case(ext, ".c") ||
-		    str_eq_ignore_case(ext, ".cpp") ||
-		    str_eq_ignore_case(ext, ".cxx") ||
-		    str_eq_ignore_case(ext, ".h") ||
-		    str_eq_ignore_case(ext, ".hpp") ||
-		    str_eq_ignore_case(ext, ".hxx") ||
-		    false
-		) {
-			error(fl->token, "With 'foreign import', you cannot import a %.*s file directory, you must precompile the library and link against that", LIT(ext));
-			break;
+				String fullpath = file_str;
+				if (allow_check_foreign_filepath()) {
+					String foreign_path = {};
+					bool ok = determine_path_from_string(nullptr, decl, base_dir, file_str, &foreign_path, /*use error not syntax_error*/true);
+					if (ok) {
+						fullpath = foreign_path;
+					}
+				}
+				array_add(&fullpaths, fullpath);
+			}
+			fl->fullpaths = slice_from_array(fullpaths);
+		}
+
+		for (String const &path : fl->fullpaths) {
+			String ext = path_extension(path);
+			if (str_eq_ignore_case(ext, ".c") ||
+			    str_eq_ignore_case(ext, ".cpp") ||
+			    str_eq_ignore_case(ext, ".cxx") ||
+			    str_eq_ignore_case(ext, ".h") ||
+			    str_eq_ignore_case(ext, ".hpp") ||
+			    str_eq_ignore_case(ext, ".hxx") ||
+			    false
+			) {
+				error(fl->token, "With 'foreign import', you cannot import a %.*s file/directory, you must precompile the library and link against that", LIT(ext));
+				break;
+			}
 		}
+
+		add_untyped_expressions(ctx.info, &untyped);
+
+		e->LibraryName.paths = fl->fullpaths;
 	}
+}
+
+gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
+	if (decl->state_flags & StateFlag_BeenHandled) return;
+	decl->state_flags |= StateFlag_BeenHandled;
 
+	ast_node(fl, ForeignImportDecl, decl);
 
-	// if (fl->collection_name != "system") {
-	// 	char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
-	// 	defer (gb_free(heap_allocator(), c_str));
-	// 	gb_memmove(c_str, fullpath.text, fullpath.len);
-	// 	c_str[fullpath.len] = '\0';
+	Scope *parent_scope = ctx->scope;
+	GB_ASSERT(parent_scope->flags&ScopeFlag_File);
 
-	// 	gbFile f = {};
-	// 	gbFileError file_err = gb_file_open(&f, c_str);
-	// 	defer (gb_file_close(&f));
+	String library_name = fl->library_name.string;
+	if (library_name.len == 0 && fl->fullpaths.count != 0) {
+		String fullpath = fl->fullpaths[0];
+		library_name = path_to_entity_name(fl->library_name.string, fullpath);
+	}
+	if (library_name.len == 0 || is_blank_ident(library_name)) {
+		error(fl->token, "File name, '%.*s', cannot be as a library name as it is not a valid identifier", LIT(library_name));
+		return;
+	}
 
-	// 	switch (file_err) {
-	// 	case gbFileError_Invalid:
-	// 		error(decl, "Invalid file or cannot be found ('%.*s')", LIT(fullpath));
-	// 		return;
-	// 	case gbFileError_NotExists:
-	// 		error(decl, "File cannot be found ('%.*s')", LIT(fullpath));
-	// 		return;
-	// 	}
-	// }
 
 	GB_ASSERT(fl->library_name.pos.line != 0);
 	fl->library_name.string = library_name;
 
 	Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
 	                                      fl->fullpaths, library_name);
+	e->LibraryName.decl = decl;
 	add_entity_flags_from_file(ctx, e, parent_scope);
 	add_entity(ctx, parent_scope, nullptr, e);
 
-
 	AttributeContext ac = {};
 	check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
 	if (ac.require_declaration) {
@@ -4987,12 +4996,8 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 		e->LibraryName.extra_linker_flags = extra_linker_flags;
 	}
 
-	if (has_asm_extension(fullpath)) {
-		if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.os != TargetOs_darwin) {
-			error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s",
-			      LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch]));
-		}
-	}
+	mpsc_enqueue(&ctx->info->foreign_imports_to_check_fullpaths, e);
+
 }
 
 // Returns true if a new package is present
@@ -6354,6 +6359,9 @@ gb_internal void check_parsed_files(Checker *c) {
 	TIME_SECTION("check procedure bodies");
 	check_procedure_bodies(c);
 
+	TIME_SECTION("check foreign import fullpaths");
+	check_foreign_import_fullpaths(c);
+
 	TIME_SECTION("add entities from procedure bodies");
 	check_merge_queues_into_arrays(c);
 

+ 3 - 0
src/checker.hpp

@@ -414,6 +414,7 @@ struct CheckerInfo {
 	MPSCQueue<Entity *> entity_queue;
 	MPSCQueue<Entity *> required_global_variable_queue;
 	MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
+	MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
 
 	MPSCQueue<Ast *> intrinsics_entry_point_usage;
 
@@ -434,6 +435,8 @@ struct CheckerInfo {
 	BlockingMutex                       load_directory_mutex;
 	StringMap<LoadDirectoryCache *>     load_directory_cache;
 	PtrMap<Ast *, LoadDirectoryCache *> load_directory_map; // Key: Ast_CallExpr *
+
+
 };
 
 struct CheckerContext {

+ 1 - 0
src/entity.cpp

@@ -266,6 +266,7 @@ struct Entity {
 			Scope *scope;
 		} ImportName;
 		struct {
+			Ast *decl;
 			Slice<String> paths;
 			String name;
 			i64 priority_index;

+ 25 - 3
src/parser.cpp

@@ -1285,13 +1285,15 @@ gb_internal Ast *ast_import_decl(AstFile *f, Token token, Token relpath, Token i
 }
 
 gb_internal Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Ast *> filepaths, Token library_name,
-                             CommentGroup *docs, CommentGroup *comment) {
+                                         bool multiple_filepaths,
+                                         CommentGroup *docs, CommentGroup *comment) {
 	Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl);
 	result->ForeignImportDecl.token        = token;
 	result->ForeignImportDecl.filepaths    = slice_from_array(filepaths);
 	result->ForeignImportDecl.library_name = library_name;
 	result->ForeignImportDecl.docs         = docs;
 	result->ForeignImportDecl.comment      = comment;
+	result->ForeignImportDecl.multiple_filepaths = multiple_filepaths;
 	result->ForeignImportDecl.attributes.allocator = ast_allocator(f);
 
 	return result;
@@ -4882,8 +4884,11 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
 		if (is_blank_ident(lib_name)) {
 			syntax_error(lib_name, "Illegal foreign import name: '_'");
 		}
+		bool multiple_filepaths = false;
+
 		Array<Ast *> filepaths = {};
 		if (allow_token(f, Token_OpenBrace)) {
+			multiple_filepaths = true;
 			array_init(&filepaths, ast_allocator(f));
 
 			while (f->curr_token.kind != Token_CloseBrace &&
@@ -4912,7 +4917,7 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
 			syntax_error(lib_name, "You cannot use foreign import within a procedure. This must be done at the file scope");
 			s = ast_bad_decl(f, lib_name, ast_token(filepaths[0]));
 		} else {
-			s = ast_foreign_import_decl(f, token, filepaths, lib_name, docs, f->line_comment);
+			s = ast_foreign_import_decl(f, token, filepaths, lib_name, multiple_filepaths, docs, f->line_comment);
 		}
 		expect_semicolon(f);
 		return s;
@@ -5859,7 +5864,24 @@ gb_internal void parse_setup_file_decls(Parser *p, AstFile *f, String const &bas
 				syntax_error(decls[i], "No foreign paths found");
 				decls[i] = ast_bad_decl(f, ast_token(fl->filepaths[0]), ast_end_token(fl->filepaths[fl->filepaths.count-1]));
 				goto end;
-
+			} else if (!fl->multiple_filepaths &&
+			           fl->filepaths.count == 1) {
+				Ast *fp = fl->filepaths[0];
+				GB_ASSERT(fp->kind == Ast_BasicLit);
+				Token fp_token = fp->BasicLit.token;
+				String file_str = string_trim_whitespace(string_value_from_token(f, fp_token));
+				String fullpath = file_str;
+				if (allow_check_foreign_filepath()) {
+					String foreign_path = {};
+					bool ok = determine_path_from_string(&p->file_decl_mutex, node, base_dir, file_str, &foreign_path);
+					if (!ok) {
+						decls[i] = ast_bad_decl(f, fp_token, fp_token);
+						goto end;
+					}
+					fullpath = foreign_path;
+				}
+				fl->fullpaths = slice_make<String>(permanent_allocator(), 1);
+				fl->fullpaths[0] = fullpath;
 			}
 
 		} else if (node->kind == Ast_WhenStmt) {

+ 1 - 0
src/parser.hpp

@@ -632,6 +632,7 @@ AST_KIND(_DeclBegin,      "", bool) \
 	AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
 		Token    token;           \
 		Slice<Ast *> filepaths;   \
+		bool multiple_filepaths;  \
 		Token    library_name;    \
 		String   collection_name; \
 		Slice<String> fullpaths;  \