diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 18b99314c..d56bbb2b2 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -1135,7 +1135,7 @@ export class CodeGenerator { name = _name; switch (suffix) { case "bind": - value = `${value}.bind(this)`; + value = `(${value}).bind(this)`; break; case "alike": break; diff --git a/tests/components/__snapshots__/props.test.ts.snap b/tests/components/__snapshots__/props.test.ts.snap index af9913b7e..840c577f4 100644 --- a/tests/components/__snapshots__/props.test.ts.snap +++ b/tests/components/__snapshots__/props.test.ts.snap @@ -349,7 +349,7 @@ exports[`bound functions are considered 'alike' 1`] = ` return function template(ctx, node, key = \\"\\") { const b2 = text(ctx['state'].val); - const b3 = comp1({fn: ctx['someFunction'].bind(this)}, key + \`__1\`, node, this, null); + const b3 = comp1({fn: (ctx['someFunction']).bind(this)}, key + \`__1\`, node, this, null); return multi([b2, b3]); } }" @@ -373,7 +373,7 @@ exports[`bound functions is not referentially equal after update 1`] = ` const comp1 = app.createComponent(\`Child\`, true, false, false, [\\"val\\"]); return function template(ctx, node, key = \\"\\") { - return comp1({val: ctx['state'].val,fn: ctx['someFunction'].bind(this)}, key + \`__1\`, node, this, null); + return comp1({val: ctx['state'].val,fn: (ctx['someFunction']).bind(this)}, key + \`__1\`, node, this, null); } }" `; @@ -396,7 +396,7 @@ exports[`can bind function prop with bind suffix 1`] = ` const comp1 = app.createComponent(\`Child\`, true, false, false, []); return function template(ctx, node, key = \\"\\") { - return comp1({doSomething: ctx['doSomething'].bind(this)}, key + \`__1\`, node, this, null); + return comp1({doSomething: (ctx['doSomething']).bind(this)}, key + \`__1\`, node, this, null); } }" `; @@ -411,3 +411,27 @@ exports[`can bind function prop with bind suffix 2`] = ` } }" `; + +exports[`do not crash when binding anonymous function prop with bind suffix 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + const comp1 = app.createComponent(\`Child\`, true, false, false, []); + + return function template(ctx, node, key = \\"\\") { + const v1 = ctx['this']; + return comp1({doSomething: ((_val)=>v1.doSomething(_val)).bind(this)}, key + \`__1\`, node, this, null); + } +}" +`; + +exports[`do not crash when binding anonymous function prop with bind suffix 2`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + + return function template(ctx, node, key = \\"\\") { + return text(\`child\`); + } +}" +`; diff --git a/tests/components/__snapshots__/slots.test.ts.snap b/tests/components/__snapshots__/slots.test.ts.snap index ee492341c..8a45d6554 100644 --- a/tests/components/__snapshots__/slots.test.ts.snap +++ b/tests/components/__snapshots__/slots.test.ts.snap @@ -90,7 +90,7 @@ exports[`slots can define and call slots with bound params 1`] = ` return function template(ctx, node, key = \\"\\") { const ctx1 = capture(ctx); - return comp1({slots: markRaw({'abc': {__render: slot1.bind(this), __ctx: ctx1, getValue: ctx['getValue'].bind(this)}})}, key + \`__1\`, node, this, null); + return comp1({slots: markRaw({'abc': {__render: slot1.bind(this), __ctx: ctx1, getValue: (ctx['getValue']).bind(this)}})}, key + \`__1\`, node, this, null); } }" `; @@ -1516,7 +1516,7 @@ exports[`slots simple default slot with params and bound function 2`] = ` let { callSlot } = helpers; return function template(ctx, node, key = \\"\\") { - return callSlot(ctx, node, key, 'default', false, {fn: ctx['getValue'].bind(this)}); + return callSlot(ctx, node, key, 'default', false, {fn: (ctx['getValue']).bind(this)}); } }" `; diff --git a/tests/components/__snapshots__/t_call.test.ts.snap b/tests/components/__snapshots__/t_call.test.ts.snap index 4478fc6ae..31284ce1e 100644 --- a/tests/components/__snapshots__/t_call.test.ts.snap +++ b/tests/components/__snapshots__/t_call.test.ts.snap @@ -556,7 +556,7 @@ exports[`t-call t-call-context: ComponentNode is not looked up in the context 2` let ref1 = (el) => this.__owl__.setRef((\`myRef\`), el); const b2 = block2([ref1]); const ctx1 = capture(ctx); - const b6 = comp1({prop: ctx['method'].bind(this),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null); + const b6 = comp1({prop: (ctx['method']).bind(this),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null); return multi([b2, b6]); } }" diff --git a/tests/components/props.test.ts b/tests/components/props.test.ts index 8b8c7d828..3cbea392a 100644 --- a/tests/components/props.test.ts +++ b/tests/components/props.test.ts @@ -200,6 +200,31 @@ test("can bind function prop with bind suffix", async () => { expect(fixture.innerHTML).toBe("child"); }); +test("do not crash when binding anonymous function prop with bind suffix", async () => { + class Child extends Component { + static template = xml`child`; + setup() { + this.props.doSomething(123); + } + } + + let boundedThing: any = null; + + class Parent extends Component { + static template = xml``; + static components = { Child }; + + doSomething(val: number) { + expect(val).toBe(123); + boundedThing = this; + } + } + + const parent = await mount(Parent, fixture); + expect(boundedThing).toBe(parent); + expect(fixture.innerHTML).toBe("child"); +}); + test("bound functions is not referentially equal after update", async () => { let isEqual = false; class Child extends Component {