diff --git a/compiler_expr.go b/compiler_expr.go index f060c395..80282175 100644 --- a/compiler_expr.go +++ b/compiler_expr.go @@ -2015,6 +2015,8 @@ func (c *compiler) emitCallee(callee compiledExpr) (calleeName unistring.String) c.endOptChain() case *compiledOptional: c.emitCallee(callee.expr) + c.block.conts = append(c.block.conts, len(c.p.code)) + c.emit(nil) default: c.emit(loadUndef) callee.emitGetter(true) @@ -2458,6 +2460,9 @@ func (c *compiler) endOptChain() { for _, item := range c.block.breaks { c.p.code[item] = jopt(lbl - item) } + for _, item := range c.block.conts { + c.p.code[item] = joptc(lbl - item) + } c.block = c.block.outer } diff --git a/compiler_test.go b/compiler_test.go index 85206c64..72963af0 100644 --- a/compiler_test.go +++ b/compiler_test.go @@ -4716,6 +4716,19 @@ func TestAssignBeforeInit(t *testing.T) { testScriptWithTestLib(SCRIPT, _undefined, t) } +func TestOptChainCallee(t *testing.T) { + const SCRIPT = ` + var a; + assert.sameValue(a?.(true), undefined); + a = null; + assert.sameValue(a?.(), undefined); + var o = {n: null}; + assert.sameValue(o.m?.(true), undefined); + assert.sameValue(o.n?.(true), undefined); + ` + testScriptWithTestLib(SCRIPT, _undefined, t) +} + /* func TestBabel(t *testing.T) { src, err := ioutil.ReadFile("babel7.js") diff --git a/vm.go b/vm.go index 87b22216..4e332ff1 100644 --- a/vm.go +++ b/vm.go @@ -3376,6 +3376,19 @@ func (j jopt) exec(vm *vm) { } } +type joptc int32 + +func (j joptc) exec(vm *vm) { + switch vm.stack[vm.sp-1].(type) { + case valueNull, valueUndefined, memberUnresolved: + vm.sp-- + vm.stack[vm.sp-1] = _undefined + vm.pc += int(j) + default: + vm.pc++ + } +} + type jcoalesc int32 func (j jcoalesc) exec(vm *vm) {