Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

incorrect arguments by default with this #1360

Open
a-x- opened this issue Feb 10, 2019 · 8 comments
Open

incorrect arguments by default with this #1360

a-x- opened this issue Feb 10, 2019 · 8 comments

Comments

@a-x-
Copy link

a-x- commented Feb 10, 2019

饾摥饾摦饾摤饾摢饾摨饾摨饾摦饾摬饾摲饾摢饾摻饾摦 is incorrectly transpiling my CoffeeScript input:

source

class Component extends React.PureComponent
  state: {intent: null, yearMonth: null}
  loadData: ({ intent = @state.intent, yearMonth = @state.yearMonth } = {}) =>
    @loadable.request =>
      Api.get '/admin/document_checks/stat_data', { yearMonth, intent }
        .then ({ stats, teams, operators }) => @setState { stats, teams, operators }

REPL

incorrect result (indentation issue is there too):

class Component extends React.PureComponent {
  // ...
  loadData({ intent = intent1, yearMonth = yearMonth1 } = {}) { // 馃槢 UNDEF
    this.state = state; // 馃槢 
    this.intent = intent1; // 馃槢
    this.state = state1; // 馃槢
    this.yearMonth = yearMonth1; // 馃槢
    return this.loadable.request(() => {
      return Api.get('/admin/document_checks/stat_data', { yearMonth, intent })
        .then(({ stats, teams, operators }) => this.setState({ stats, teams, operators }));
  });
  }

expected:

class Component extends React.PureComponent {
  // ...
  loadData({ intent = this.state.intent, yearMonth = this.state.yearMonth } = {}) {
    return this.loadable.request(() => {
      return Api.get('/admin/document_checks/stat_data', { yearMonth, intent })
        .then(({ stats, teams, operators }) => this.setState({ stats, teams, operators }));
    });
  }
@a-x-
Copy link
Author

a-x- commented Feb 10, 2019

It works good w/o the curly braces

loadData: (intent = @state.intent, yearMonth = @state.yearMonth) =>

REPL

@a-x-
Copy link
Author

a-x- commented Feb 10, 2019

Idea to workaround:

  1. grab one or more {...} with @ from function's braces
  2. put uniq special argument instead (_tmp_curly_args_hack_1)
  3. put {...} = _tmp_curly_args_hack_1 in the first line of body
  4. perform all the processing
  5. perform procession on {...}
  6. move processed {...} back and remove _tmp_curly_args_hack_1

@a-x-
Copy link
Author

a-x- commented Feb 10, 2019

Another bad cases:
repl

class Component
  foo: (a,{b=@b}, c) ->
    42
class Component {
  foo(a,{b=b1}, c) {
    this.b = b1;
    return 42;
  }
}

@eventualbuddha
Copy link
Collaborator

This definitely appears to be a bug. Here's a minimal reproduction:

({ a = @a }) ->
(function({ a = a1 }) {
  this.a = a1;
});

I think the problem is that it's inspecting the whole subtree of nodes for default values to assign, when it shouldn't be doing so with the right hand side of the assignment. I don't know that's the case, but that's what it feels like. I'd be happy to review a PR to fix this.

@a-x-
Copy link
Author

a-x- commented Feb 12, 2019

has you any beginner's contributor guide?
what tools use, docs read. how conceptually decaffeinate works and etc.

@a-x-
Copy link
Author

a-x- commented Feb 12, 2019

I tried to patch it and crashed into partially broken TS source maps in the node --inspector and long manual rebuilding (what about adding wath build? I tried, it's not so easy)

@eventualbuddha
Copy link
Collaborator

Have you looked at this? https://github.com/decaffeinate/decaffeinate/blob/master/docs/contribution-guide.md

@eventualbuddha
Copy link
Collaborator

I was able to fix this case, sort of, by using this:

diff --git a/src/stages/normalize/patchers/MemberAccessOpPatcher.ts b/src/stages/normalize/patchers/MemberAccessOpPatcher.ts
index ea944d0d..f1dccf3c 100644
--- a/src/stages/normalize/patchers/MemberAccessOpPatcher.ts
+++ b/src/stages/normalize/patchers/MemberAccessOpPatcher.ts
@@ -4,6 +4,7 @@ import PassthroughPatcher from '../../../patchers/PassthroughPatcher';
 import { PatcherContext } from '../../../patchers/types';
 import DefaultParamPatcher from './DefaultParamPatcher';
 import IdentifierPatcher from './IdentifierPatcher';
+import AssignOpPatcher from './AssignOpPatcher';
 
 export default class MemberAccessOpPatcher extends PassthroughPatcher {
   node: MemberAccessOp;
@@ -41,6 +42,9 @@ export default class MemberAccessOpPatcher extends PassthroughPatcher {
       if (patcher.parent instanceof DefaultParamPatcher && patcher.parent.value === patcher) {
         break;
       }
+      if (patcher.parent instanceof AssignOpPatcher && patcher.parent.expression === patcher) {
+        break;
+      }
       patcher = patcher.parent;
     }
     return null;

However, that breaks some other cases. We want both of these to work, but I'm not sure how to make that happen:

  it('handles destructured param with `this` member access default value (#1360)', () =>
    checkCS2(
      `
      ({ a = @a }) ->
    `,
      `
      (function({ a = this.a }) {});
    `
    ));

  it('handles destructured param with default value (#1360)', () =>
    checkCS2(
      `
      ({ a } = {}) ->`,
      `
      (function({ a } = {}) {});
      `
    ));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants