diff --git a/tslang/lib/TypeScript/MLIRGenFunctions.cpp b/tslang/lib/TypeScript/MLIRGenFunctions.cpp index ba806c1fd..e76c155c0 100644 --- a/tslang/lib/TypeScript/MLIRGenFunctions.cpp +++ b/tslang/lib/TypeScript/MLIRGenFunctions.cpp @@ -51,6 +51,13 @@ namespace mlirgen namePtr = getArgumentName(index); } + // A written `this:` on a method only annotates the receiver the method already has; as a + // parameter of its own it shifted every argument by one slot. + if (namePtr == THIS_NAME && !params.empty() && params.front()->getName() == THIS_NAME) + { + continue; + } + auto isBindingPattern = arg->name == SyntaxKind::ObjectBindingPattern || arg->name == SyntaxKind::ArrayBindingPattern; mlir::Type type; diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index a90056cb0..0d10fb412 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -553,6 +553,7 @@ tslang_add_test(NAME test-compile-00-try-catch-return-dispose COMMAND test-runne tslang_add_test(NAME test-compile-01-try-catch-return-dispose COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01try_catch_return_dispose.ts") tslang_add_test(NAME test-compile-00-property-access-conditional COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00property_access_cond.ts") tslang_add_test(NAME test-compile-00-method-access-conditional COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00method_access_cond.ts") +tslang_add_test(NAME test-compile-00-method-this-param COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00method_this_param.ts") tslang_add_test(NAME test-compile-01-method-access-conditional COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/01method_access_cond.ts") tslang_add_test(NAME test-compile-00-question-question COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00question_question.ts") tslang_add_test(NAME test-compile-00-spread-assignment COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00spread_assignment.ts") @@ -998,6 +999,7 @@ tslang_add_test(NAME test-jit-01-try-catch-return-dispose COMMAND test-runner -j tslang_add_test(NAME test-jit-00-types COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00types.ts") tslang_add_test(NAME test-jit-00-property-access-conditional COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00property_access_cond.ts") tslang_add_test(NAME test-jit-00-method-access-conditional COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00method_access_cond.ts") +tslang_add_test(NAME test-jit-00-method-this-param COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00method_this_param.ts") tslang_add_test(NAME test-jit-01-method-access-conditional COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/01method_access_cond.ts") tslang_add_test(NAME test-jit-00-question-question COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00question_question.ts") tslang_add_test(NAME test-jit-00-spread-assignment COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00spread_assignment.ts") @@ -1686,6 +1688,7 @@ set(TSLANG_CORPUS 00length.ts 00map.ts 00method_access_cond.ts + 00method_this_param.ts 00mixed_type_ops.ts 00names_conflict.ts 00nested_catch.ts @@ -2275,6 +2278,7 @@ set(call_arity_cases "plain|Expected 2 arguments, but got 1\\." "optional|Expected 2\\-3 arguments, but got 1\\." "method|Expected 2 arguments, but got 1\\." + "method_this|Expected 2 arguments, but got 1\\." "constructor|Expected 2 arguments, but got 1\\." "closure|Expected 2 arguments, but got 1\\." "declared|Expected 2 arguments, but got 1\\." diff --git a/tslang/test/tester/call-arity/method_this.ts b/tslang/test/tester/call-arity/method_this.ts new file mode 100644 index 000000000..6b7553503 --- /dev/null +++ b/tslang/test/tester/call-arity/method_this.ts @@ -0,0 +1,12 @@ +class O { + x = 1; + + m(this: O, a: number, b: number) { + return a + b + this.x; + } +} + +function main() { + const o = new O(); + print(o.m(1)); +} diff --git a/tslang/test/tester/tests/00method_this_param.ts b/tslang/test/tester/tests/00method_this_param.ts new file mode 100644 index 000000000..48a21eba8 --- /dev/null +++ b/tslang/test/tester/tests/00method_this_param.ts @@ -0,0 +1,48 @@ +// A written `this:` parameter on a method annotates the receiver; it is not a parameter. It was +// added next to the implicit receiver, which shifted every argument by one (#342). + +class O { + x = 1; + + m(this: O, a: number, b: number) { + return a + b + this.x; + } +} + +interface I { + x: number; + m(this: I, a: number, b: number): number; +} + +class C implements I { + x: number = 10; + + m(this: I, a: number, b: number) { + return a + b + this.x; + } +} + +// a free function keeps its `this:` as the receiver it binds (the extension-function form) +function ext(this: O, a: number) { + return this.x + a; +} + +function main() { + const o = new O(); + assert(o.m(1, 2) == 4); + + const i: I = new C(); + assert(i.m(1, 2) == 13); + + const lit = { + x: 100, + m(this: { x: number }, a: number, b: number) { + return a + b + this.x; + } + }; + assert(lit.m(1, 2) == 103); + + assert(o.ext(5) == 6); + + print("done."); +}