Skip to content

Fix LuaTable#702

Merged
Perryvw merged 13 commits intoTypeScriptToLua:masterfrom
hazzard993:luatable-fixes
Aug 26, 2019
Merged

Fix LuaTable#702
Perryvw merged 13 commits intoTypeScriptToLua:masterfrom
hazzard993:luatable-fixes

Conversation

@hazzard993
Copy link
Copy Markdown
Contributor

Closes #699

Also added a rule preventing LuaTables from being accessed via ElementAccessExpressions.

  /** @LuaTable */
  declare class LuaTable<K extends {} = {}, V = any> {
    readonly length: number;
    set(key: K, value: V): void;
    get(key: K): V;
  }
  
  const k = "k"
  const t = { data: new LuaTable() }
+ const v = t.data.get(k) // --> local v = t.data[k]
+ t.data.set(k,v) // --> t.data[k] = v
+ const v2 = t.data.get(k).x; // --> local v2 = t.data[k].x
- const v3 = t.data["get"](k)
- t.data["set"](k, v)

Removed a lot of casting to track down the bug.

);
}
if (!isWithinExpressionStatement) {
if (expression.parent.kind !== ts.SyntaxKind.ExpressionStatement) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That won't work if it's gone through transformExpressionStatement as an expression

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like that would cause a bug but I can't seem to create some code to break this. What kind of code would do you think would break this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just like above, anything that calls transformExpressionStatement directly with an expression

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks it is working as expected. It doesn't break when it goes through transformExpressionStatement as an Expression and will throw the Exception appropriately

/** @LuaTable */
declare class LuaTable<K extends {} = {}, V = any> {
  readonly length: number;
  set(key: K, value: V): number;
  get(key: K): V;
}
let y;
let t = new LuaTable();
for (let x = 0; x < 10; t.set("x", 4)) {} // ❌
for (let x = 0; x < 10; x = t.set("x", 4)) {} // ❌
let x = 4 + (y = t.set('', 2)); // ❌
let xx = 4 + t.set('', 2); // ❌
let xxx = t.set('', 2); // ❌
let y = 4 + (y = t.get('')); // ✔
let yy = 4 + t.get(''); // ✔
let yyy = t.get(''); // ✔

transformExpressionStatement is only called with an ExpressionStatement from transformStatement and this would be the only case where luaTable.set would be allowed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't throw in these cases. The whole point of passing an expression to transformExpressionStatement is to assume that this expression is used in statement context, even if it's not a part of ExpressionStatement.

protected transformLuaTableProperty(node: ts.PropertyAccessExpression): tstl.Expression {
switch (node.name.text) {
case "set":
return this.transformExpression(node.expression);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, took me some time to understand how it works and I don't like how transformation flows there. In general, property access isn't equivalent to it's root node, so returning it there isn't correct.

Maybe something like const [luaTable, methodName] = this.parseLuaTableExpression(expression.expression);?


if (decorators.has(DecoratorKind.LuaTable)) {
return this.transformLuaTableProperty(expression);
const [luaTable] = this.parseLuaTableExpression(expression);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not what I meant. table.get shouldn't be transformed just to table, because these aren't interchangeable in isolation. transformLuaTableProperty should allow only length property.
What I meant is that getLuaTablePropertyName can be renamed to parseLuaTableExpression and would split lua table reference and it's method name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification, looks like it neatened up nicely

@Perryvw Perryvw merged commit 1ab86da into TypeScriptToLua:master Aug 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LuaTable as object member

3 participants