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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline variable refactor #54281

Merged
merged 35 commits into from
Jun 13, 2023
Merged

Conversation

MariaSolOs
Copy link
Contributor

Fixes #18459

@typescript-bot typescript-bot added the For Milestone Bug PRs that fix a bug with a specific milestone label May 16, 2023
@typescript-bot
Copy link
Collaborator

The TypeScript team hasn't accepted the linked issue #18459. If you can get it accepted, this PR will have a better chance of being reviewed.

@MariaSolOs MariaSolOs marked this pull request as draft May 16, 2023 22:22
@typescript-bot
Copy link
Collaborator

The TypeScript team hasn't accepted the linked issue #18459. If you can get it accepted, this PR will have a better chance of being reviewed.

1 similar comment
@typescript-bot
Copy link
Collaborator

The TypeScript team hasn't accepted the linked issue #18459. If you can get it accepted, this PR will have a better chance of being reviewed.

@MariaSolOs MariaSolOs marked this pull request as ready for review May 22, 2023 18:52
Copy link
Contributor

@mjbvz mjbvz left a comment

Choose a reason for hiding this comment

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

Excited to test this out!

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

I think there are a couple other invalid inlinings to consider.

  1. Type queries:
    const Bar = class Bar {}
    type BarConstructor = typeof Bar;
    typeof can only take an identifier reference.
  2. Merged type/value meanings:
    const a = "hello";
    type a = any;
    type T = a;
    There’s one symbol for a with two declarations, so Find All References might return a in type T = a as a reference, even though you wouldn’t want to inline "hello" there. The real case for merging meanings is usually more like
    // Simulate type/value duality of real class declarations
    const SomeClass = mixin(OtherClass);
    type SomeClass = typeof SomeClass;
    and in those cases it seems undesirable to inline anyway. I think you can implement a simple rule that says if a symbol has more than one declaration, it can’t be inlined.

src/services/refactors/inlineVariable.ts Outdated Show resolved Hide resolved
Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

This is looking really good! The implementation is impressively small and readable and I like that each test is very focused.

Have you tried to beat this up on some more complicated real-world code? Do that if you haven’t already, and then I would also suggest having one or two kitchen-sink tests that exercise more complex cases with several references and complex expressions (multi-line function expression?)

tests/cases/fourslash/inlineVariableExportedVariable.ts Outdated Show resolved Hide resolved
@MariaSolOs
Copy link
Contributor Author

@andrewbranch I've added a couple more tests with more complex scenarios like call expressions. LMK what you think :)

@andrewbranch
Copy link
Member

I still think inlining a multi-line expression would be good to test:

function Component() {
  const onClick /*inline me*/ = () => {
    console.log("clicked");
  };
  return (
    <button onClick={onClick}>
      Do useful thing
    </button>
  );
}

@DanielRosenwasser
Copy link
Member

@typescript-bot pack this
@typescript-bot user test tsserver
@typescript-bot test tsserver top100

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

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

Looks good to me, nice job 👍

@DanielRosenwasser
Copy link
Member

I SAID

@typescript-bot pack this
@typescript-bot user test tsserver
@typescript-bot test tsserver top100

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 31, 2023

Heya @DanielRosenwasser, I've started to run the diff-based user code test suite (tsserver) on this PR at 2f97c5c. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 31, 2023

Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 2f97c5c. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 31, 2023

Heya @DanielRosenwasser, I've started to run the diff-based top-repos suite (tsserver) on this PR at 2f97c5c. You can monitor the build here.

Update: The results are in!

@DanielRosenwasser
Copy link
Member

That's what I thought.

@MariaSolOs
Copy link
Contributor Author

Also, I noticed that if I request an inline at the following position

let/**/ asdasd = 42;

let qwerty = asdasd;

the refactoring is made available, but not elsewhere on the let (e.g. l/**/et asdasd = ...).

I feel like it should either work solely on:

  1. The variable name
  2. The variable name or the variable statement keyword
  3. The entire variable statement

@DanielRosenwasser I believe we should stick with option 1, since there would be an ambiguity about what to inline in cases like let x = 0, y = 1 with the other 2 options.

However, if I change this bit to:

if (isIdentifier(token) && isInitializedVariable(parent) && isVariableDeclarationInVariableStatement(parent)) {

The refactor is still available in let/**/ foo = 0;, since I believe that's leading trivia that belongs to the identifier node. I think this should be fine...?

@DanielRosenwasser
Copy link
Member

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 12, 2023

Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 67a5880. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 12, 2023

Hey @DanielRosenwasser, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/155454/artifacts?artifactName=tgz&fileId=6087B18552E765F2B38E8662F37137B2540138A75BDE31954CDB44014CC8C60C02&fileName=/typescript-5.2.0-insiders.20230612.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

@MariaSolOs MariaSolOs merged commit 31936ea into microsoft:main Jun 13, 2023
@MariaSolOs MariaSolOs deleted the inline-variable branch June 13, 2023 07:27
@awerlogus
Copy link

Inlining variable data changes runtime behaviour. Is it bug or design limitation?

const data = new Map()

const getter = () => data.get('foo')

data.set('foo', 'bar')

console.log(getter())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Inline local refactoring
6 participants