浏览代码

Support multiple paths for wasm in `foreign import`

gingerBill 8 月之前
父节点
当前提交
c8ad2a4245
共有 3 个文件被更改,包括 77 次插入46 次删除
  1. 42 46
      src/check_decl.cpp
  2. 34 0
      src/checker.cpp
  3. 1 0
      src/checker.hpp

+ 42 - 46
src/check_decl.cpp

@@ -971,6 +971,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
 	}
 }
 
+gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
+	GB_ASSERT(e != nullptr);
+	GB_ASSERT(e->kind == Entity_Procedure);
+	String name = e->Procedure.link_name;
+
+	mutex_lock(&ctx->info->foreign_mutex);
+
+	auto *fp = &ctx->info->foreigns;
+	StringHashKey key = string_hash_string(name);
+	Entity **found = string_map_get(fp, key);
+	if (found && e != *found) {
+		Entity *f = *found;
+		TokenPos pos = f->token.pos;
+		Type *this_type = base_type(e->type);
+		Type *other_type = base_type(f->type);
+		if (is_type_proc(this_type) && is_type_proc(other_type)) {
+			if (!are_signatures_similar_enough(this_type, other_type)) {
+				error(d->proc_lit,
+				      "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
+				      "\tat %s",
+				      LIT(name), token_pos_to_string(pos));
+			}
+		} else if (!signature_parameter_similar_enough(this_type, other_type)) {
+			error(d->proc_lit,
+			      "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
+			      "\tat %s",
+			      LIT(name), token_pos_to_string(pos));
+		}
+	} else if (name == "main") {
+		error(d->proc_lit, "The link name 'main' is reserved for internal use");
+	} else {
+		string_map_set(fp, key, e);
+	}
+
+	mutex_unlock(&ctx->info->foreign_mutex);
+}
+
 gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	GB_ASSERT(e->type == nullptr);
 	if (d->proc_lit->kind != Ast_ProcLit) {
@@ -1307,57 +1344,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 			name = e->Procedure.link_name;
 		}
 		Entity *foreign_library = init_entity_foreign_library(ctx, e);
-		
-		if (is_arch_wasm() && foreign_library != nullptr) {
-			String module_name = str_lit("env");
-			GB_ASSERT (foreign_library->kind == Entity_LibraryName);
-			if (foreign_library->LibraryName.paths.count != 1) {
-				error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
-				      LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
-			}
-
-			if (foreign_library->LibraryName.paths.count >= 1) {
-				module_name = foreign_library->LibraryName.paths[0];
-			}
-
-			if (!string_ends_with(module_name, str_lit(".o"))) {
-				name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
-			}
-		}
-
 		e->Procedure.is_foreign = true;
 		e->Procedure.link_name = name;
+		e->Procedure.foreign_library = foreign_library;
 
-		mutex_lock(&ctx->info->foreign_mutex);
-
-		auto *fp = &ctx->info->foreigns;
-		StringHashKey key = string_hash_string(name);
-		Entity **found = string_map_get(fp, key);
-		if (found && e != *found) {
-			Entity *f = *found;
-			TokenPos pos = f->token.pos;
-			Type *this_type = base_type(e->type);
-			Type *other_type = base_type(f->type);
-			if (is_type_proc(this_type) && is_type_proc(other_type)) {
-				if (!are_signatures_similar_enough(this_type, other_type)) {
-					error(d->proc_lit,
-					      "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
-					      "\tat %s",
-					      LIT(name), token_pos_to_string(pos));
-				}
-			} else if (!signature_parameter_similar_enough(this_type, other_type)) {
-				error(d->proc_lit,
-				      "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
-				      "\tat %s",
-				      LIT(name), token_pos_to_string(pos));
-			}
-		} else if (name == "main") {
-			error(d->proc_lit, "The link name 'main' is reserved for internal use");
+		if (is_arch_wasm() && foreign_library != nullptr) {
+			// NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later
+			mpsc_enqueue(&ctx->info->foreign_decls_to_check, e);
 		} else {
-			string_map_set(fp, key, e);
+			check_foreign_procedure(ctx, e, d);
 		}
-
-		mutex_unlock(&ctx->info->foreign_mutex);
 	} else {
 		String name = e->token.string;
 		if (e->Procedure.link_name.len > 0) {

+ 34 - 0
src/checker.cpp

@@ -1356,6 +1356,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
 	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->foreign_decls_to_check, 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);
@@ -1382,6 +1383,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
 	mpsc_destroy(&i->required_global_variable_queue);
 	mpsc_destroy(&i->required_foreign_imports_through_force_queue);
 	mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
+	mpsc_destroy(&i->foreign_decls_to_check);
 
 	map_destroy(&i->objc_msgSend_types);
 	string_map_destroy(&i->load_file_cache);
@@ -5094,6 +5096,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) {
 
 		e->LibraryName.paths = fl->fullpaths;
 	}
+
+	for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) {
+		GB_ASSERT(e != nullptr);
+		if (e->kind != Entity_Procedure) {
+			continue;
+		}
+		if (!is_arch_wasm()) {
+			continue;
+		}
+		Entity *foreign_library = e->Procedure.foreign_library;
+		GB_ASSERT(foreign_library != nullptr);
+
+		String name = e->Procedure.link_name;
+
+		String module_name = str_lit("env");
+		GB_ASSERT (foreign_library->kind == Entity_LibraryName);
+		if (foreign_library->LibraryName.paths.count != 1) {
+			error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
+			      LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
+		}
+
+		if (foreign_library->LibraryName.paths.count >= 1) {
+			module_name = foreign_library->LibraryName.paths[0];
+		}
+
+		if (!string_ends_with(module_name, str_lit(".o"))) {
+			name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
+		}
+		e->Procedure.link_name = name;
+
+		check_foreign_procedure(&ctx, e, e->decl_info);
+	}
 }
 
 gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {

+ 1 - 0
src/checker.hpp

@@ -461,6 +461,7 @@ struct CheckerInfo {
 	MPSCQueue<Entity *> required_global_variable_queue;
 	MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
 	MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
+	MPSCQueue<Entity *> foreign_decls_to_check;
 
 	MPSCQueue<Ast *> intrinsics_entry_point_usage;