Skip to content

Commit e0e05c6

Browse files
committed
fixed #288
1 parent c0d175d commit e0e05c6

3 files changed

Lines changed: 23 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
`Number.MAX_SAFE_INTEGER`) are now automatically promoted to `BigInt` to
1212
maintain exact results.
1313

14+
### Symbols
15+
16+
- **[\#288](https://github.com/cortex-js/compute-engine/issues/288) Allow
17+
reassigning a symbol from operator to value**: `ce.assign()` no longer throws
18+
when assigning a plain value to a symbol that was previously declared as a
19+
function. Existing expressions using the symbol as a function head will
20+
produce a type error at evaluation time if the new value is not callable.
21+
1422
### Evaluation
1523

1624
- **Fixed scope leaks**: Ensured that evaluation contexts are correctly popped

src/compute-engine/engine-declarations.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -295,18 +295,19 @@ export function assignFn(
295295

296296
if (isOperatorDef(def)) {
297297
const value = assignValueAsValue(ce, arg2);
298-
if (value) throw Error(`Cannot change the operator "${id}" to a value`);
298+
if (value !== undefined) {
299+
// Allow converting an operator to a value.
300+
// Existing expressions using this symbol as a function head (e.g.
301+
// ["g", 2]) will produce a type error at evaluation time if the
302+
// new value is not callable — which is the correct semantic.
303+
updateDef(ce, id, def, { value });
304+
ce._setSymbolValue(id, value);
305+
return ce;
306+
}
299307

300308
// Update the operator definition.
301-
// Note: this is a potentially dangerous operation, since the
302-
// operator may be used in other expressions that are not
303-
// re-canonicalized. However, it might be desirable to override the
304-
// evaluation of an operator in a specific context, even a system
305-
// operator.
306-
// However, it is preferable to use `ce.declare()` to create a new
307-
// operator.
308309
const fnDef = assignValueAsOperatorDef(ce, arg2);
309-
if (!fnDef) throw Error(`Cannot change the operator "${id}" to a value`);
310+
if (!fnDef) throw Error(`Invalid definition for symbol "${id}"`);
310311
updateDef(ce, id, def, fnDef);
311312
return ce;
312313
}

test/compute-engine/functions.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,12 @@ describe('Changing type from function to non-function', () => {
223223
engine.pushScope();
224224
engine.declare('f20', 'any');
225225
engine.assign('f20', ['Function', ['Multiply', 'x', 2], 'x']);
226-
expect(() => engine.assign('f20', 42)).toThrow();
226+
expect(engine.box(['f20', 3]).evaluate().re).toEqual(6);
227+
228+
// Reassigning from operator to value is allowed (#288)
229+
engine.assign('f20', 42);
230+
expect(engine.box('f20').evaluate().re).toEqual(42);
227231

228-
// expect(engine.box('f20').re).toEqual(42);
229232
engine.popScope();
230233
});
231234
});

0 commit comments

Comments
 (0)