diff --git a/tslang/lib/TypeScript/MLIRGenFunctions.cpp b/tslang/lib/TypeScript/MLIRGenFunctions.cpp index e87761f4b..224b60f4e 100644 --- a/tslang/lib/TypeScript/MLIRGenFunctions.cpp +++ b/tslang/lib/TypeScript/MLIRGenFunctions.cpp @@ -597,6 +597,32 @@ namespace mlirgen return mlir::success(); } + // A declared function binds one external symbol, and that has one signature: a second + // declaration of it with another was "redefinition of symbol" from the verifier. The same + // declaration again - one C function in two .d.ts files - is left to the first. + if (!functionDeclarationAST->body) + { + auto [fullName, name] = getNameOfFunction(functionDeclarationAST, genContext); + auto declared = declaredFunctions.find(fullName); + if (declared == declaredFunctions.end() || declared->second.second != theModule.getOperation()) + { + declaredFunctions[fullName] = {functionDeclarationAST, theModule.getOperation()}; + } + else if (declared->second.first != functionDeclarationAST) + { + if (print(declared->second.first) == print(functionDeclarationAST)) + { + return mlir::success(); + } + + emitError(loc(functionDeclarationAST)) + << "'" << name << "' is declared again with another signature: a declared function is one external " + << "symbol, so it can't have overloads. Declare it once, with optional or union parameters, or " + << "give each signature a name of its own and bind them with @linkname"; + return mlir::failure(); + } + } + auto funcGenContext = GenContext(genContext); funcGenContext.clearScopeVars(); // declaring function which is nested and object should not have this context (unless it is part of object declaration) diff --git a/tslang/lib/TypeScript/MLIRGenImpl.h b/tslang/lib/TypeScript/MLIRGenImpl.h index 98fb27683..eb8115947 100644 --- a/tslang/lib/TypeScript/MLIRGenImpl.h +++ b/tslang/lib/TypeScript/MLIRGenImpl.h @@ -12706,6 +12706,11 @@ class MLIRGenImpl // imports a) stops instead of recursing until the stack overflows. llvm::StringSet<> filesInProgress; + // the declaration (no body) each declared function's full name came from, and the module it was + // generated into - discovery's is thrown away, and a library's __decls is parsed again for the + // next pass; see mlirGen(FunctionDeclaration) + std::map> declaredFunctions; + // set while an `import { a as b }` alias is resolved to its target (resolveImportAlias) bool resolvingImportAlias = false; diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 630d58d79..37d38d8d0 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -274,6 +274,7 @@ tslang_add_test(NAME test-compile-00-global-const-object-method COMMAND test-run tslang_add_test(NAME test-compile-00-funcs COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs.ts") tslang_add_test(NAME test-compile-00-funcs-capture COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_capture.ts") tslang_add_test(NAME test-compile-00-funcs-vararg COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_vararg.ts") +tslang_add_test(NAME test-compile-00-declare-function-twice COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00declare_function_twice.ts") tslang_add_test(NAME test-compile-00-function-overloads COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00function_overloads.ts") tslang_add_test(NAME test-compile-01-funcs-vararg COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01funcs_vararg.ts") # printf is avaliable in JIT only, C has snprintf @@ -720,6 +721,7 @@ tslang_add_test(NAME test-jit-00-global-const-object-method COMMAND test-runner tslang_add_test(NAME test-jit-00-funcs COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs.ts") tslang_add_test(NAME test-jit-00-funcs-capture COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_capture.ts") tslang_add_test(NAME test-jit-00-funcs-vararg COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_vararg.ts") +tslang_add_test(NAME test-jit-00-declare-function-twice COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00declare_function_twice.ts") tslang_add_test(NAME test-jit-00-function-overloads COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00function_overloads.ts") tslang_add_test(NAME test-jit-01-funcs-vararg COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01funcs_vararg.ts") tslang_add_test(NAME test-jit-02-funcs-vararg COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/02funcs_vararg.ts") @@ -2465,6 +2467,16 @@ endforeach() # parameter, and varargs with and without extra arguments. tslang_add_test(NAME test-compile-call-arity-positive COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/call-arity/positive.ts") +# A declared function with a second signature: one external symbol has one signature, and the +# error says so (it was "redefinition of symbol"). +add_test(NAME test-compile-declare-overloads-error + COMMAND $ --emit=obj --no-default-lib -mm=none + "${PROJECT_SOURCE_DIR}/test/tester/declare-overloads/overload.ts" + -o "${CMAKE_CURRENT_BINARY_DIR}/declare-overloads.obj") +set_tests_properties(test-compile-declare-overloads-error + PROPERTIES PASS_REGULAR_EXPRESSION "'abs' is declared again with another signature" + FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed|redefinition of symbol") + # The shared-component tier under the other two models. A shared library records the model # it was built under, so both halves of a pair are built with the same flag - which is what # these run. The file pairs are the default model's, verbatim. diff --git a/tslang/test/tester/declare-overloads/overload.ts b/tslang/test/tester/declare-overloads/overload.ts new file mode 100644 index 000000000..3bef9ab60 --- /dev/null +++ b/tslang/test/tester/declare-overloads/overload.ts @@ -0,0 +1,8 @@ +// A declared function is one external symbol with one signature: a second signature is an error +// that says so. It used to be "redefinition of symbol" from the verifier. +declare function abs(x: i32): i32; +declare function abs(x: i32, y: i32): i32; + +function main() { + print(abs(-3)); +} diff --git a/tslang/test/tester/tests/00declare_function_twice.ts b/tslang/test/tester/tests/00declare_function_twice.ts new file mode 100644 index 000000000..844f4f923 --- /dev/null +++ b/tslang/test/tester/tests/00declare_function_twice.ts @@ -0,0 +1,9 @@ +// The same declared function twice - one C function declared in two .d.ts files - is one +// declaration. It used to be "redefinition of symbol". +declare function abs(x: i32): i32; +declare function abs(x: i32): i32; + +function main() { + assert(abs(-3) == 3); + print("done."); +}