Commit graph

385 commits

Author SHA1 Message Date
Dunqing
7cd53f3897 refactor(semantic): var hoisting (#4379)
close: #4323

This PR refactors the var hoisting logic to avoid inserting the same symbol into every scope that can be hosted.
2024-07-25 00:55:02 +00:00
DonIsaac
871b3d6135 docs(semantic): add doc comments for SymbolTester and SemanticTester (#4433) 2024-07-24 16:58:13 +00:00
DonIsaac
ac08de817e fix(linter/react_perf): allow new objects, array, fns, etc in top scope (#4395)
Consider the following code:
```tsx
import { FC } from 'react'
import { SvgIcon } from '@mui/material'

const StyledIcon = <SvgIcon sx={{ padding: 1, color: '#ff0000' }} />
//          reported violation  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
export const MyComponent: FC = () => {
    return (
        <div>
            {StyledIcon}
            {/* ... */}
        </div>
    )
}
```

This should not be a violation since the JSX is pre-computed and re-used, which
does not break React's `Object.is()` checks.
2024-07-23 01:39:07 +00:00
Dunqing
85a7cea9d1 refactor(semantic)!: remove name from reference (#4329)
related to: https://github.com/oxc-project/backlog/issues/32
2024-07-22 15:59:23 +00:00
Dunqing
1b51511bb6 perf(semantic): use Atom instead of CompactStr for UnresolvedReferencesStack (#4401)
related: #4394

The `UnresolvedReferencesStack` is only used for resolving references, and the `Atom` clone is cheap, So we can safely change `CompactStr`to `Atom`
2024-07-22 12:18:37 +00:00
overlookmotel
bc8d4e5876 fix(semantic): correct comment (#4410)
Correct a code comment.
2024-07-22 12:14:33 +00:00
Dunqing
40f93564ac perf(semantic): calculate number of nodes, scopes, symbols, references before visiting AST (#4367)
context: #4328
2024-07-22 10:47:54 +00:00
overlookmotel
da13d9338f perf(semantic): remove bounds checks on unresolved references stack (#4390)
`SemanticBuilder` keeps a stack of hashmaps to track unresolved references. This stack only grows, never shrinks. Use that invariant to remove bounds checks.
2024-07-21 15:49:52 +00:00
overlookmotel
e70c67b2e2 perf(semantic): remove a branch from add_scope (#4384)
Similar to #4361.

`ScopeTree::add_scope` had a branch specifically to handle `Program`. Remove that by inlining the special logic for `Program` into `visit_program`.

Probably won't have much effect on benchmarks as the branch is easy to predict, but still removes a few instructions and makes `add_scope` easier for compiler to inline.
2024-07-21 12:43:34 +00:00
overlookmotel
402006f28d perf(semantic): simplify logic in enter_scope + leave_scope (#4383)
`SemanticBuilder::enter_scope` contained multiple checks purely to handle when called for `Program` scope (where scope has no parent). This is a very uncommon case as `Program` is visited only once, but these checks run for every scope.

So don't call `enter_scope` from `visit_program`, and inline the special logic for root scope there instead, to simplify `enter_scope`.

A branch in `leave_scope` also gets more predictable (always taken).
2024-07-21 12:33:24 +00:00
DonIsaac
a207923af1 perf: replace some CompactStr usages with Cows (#4377)
Reduce memory allocations in semantic and linter by using `Cow<'a, str>` over `CompactStr`
2024-07-20 19:19:55 +00:00
overlookmotel
5d77b36f24 refactor(semantic): visit_program visit hashbang field (#4370)
The visit was missing previously, though it didn't matter, because semantic doesn't do anything with `Hashbang` anyway. But is needed for #4367.
2024-07-19 16:32:32 +00:00
overlookmotel
f7b9ada372 refactor(semantic): Program visitor leave scope before node (#4369)
Bring the order of calls in `SemanticBuilder::visit_program` into line with `Visit`'s `walk_program`.
2024-07-19 16:32:27 +00:00
Dunqing
6ffce865d1 fix(semantic): align visit_arrow_function_expression field visit order with ast (#4366)
related: #4364
2024-07-19 14:51:59 +00:00
overlookmotel
7469e018b0 perf(semantic): remove branch from Nodes::add_node (#4361)
`AstNodes::add_node` had a branch specifically to handle `Program`. Remove that by inlining the special logic for `Program` into `visit_program`.

Probably won't have much effect on benchmarks as the branch is easy to predict, but still removes a few instructions and makes `add_node` easier for compiler to inline.
2024-07-19 11:34:03 +00:00
overlookmotel
729b288c5d refactor(semantic): shorten code (#4358)
Code style: Remove unnecessary assignments to `_`.
2024-07-19 10:29:27 +00:00
Dunqing
58f6ec21f3 refactor(ast): enter node before scope (#4347)
close: #4276
2024-07-18 19:18:01 +00:00
Dunqing
f8565ae3cd fix(transformer/typescript): unexpectedly removed class binding from ExportNamedDeclaration (#4351)
The original `SymbolFlags` methods were a bit confusing I renamed and re-implemented them.
2024-07-18 16:44:38 +00:00
DonIsaac
21d0eee182 refactor(semantic): use error codes for ts diagnostics (#4336)
Part of #4333
2024-07-18 16:09:28 +00:00
Dunqing
9badac030d fix(semantic): avoid var hosting insert the var variable to the CatchClause scope (#4337)
related: #4192 #4323

I will figure it out #4323 later
2024-07-18 02:52:14 +00:00
Dunqing
95e15b6dc5 fix(semantic): incorrect resolve references for ExportSpecifier (#4320)
```ts
type A = any;
const B = 0;
export { A, B }
       ^^^^^^^^ ExportSpecifiers

export { A }
       ^^^^^ type-only ExportSpecifiers

```

non-type-only `ExportSpecifier` can reference value and type symbols. but currently, `IdentifierReference` in ExportSpecifier only has a `ReferenceFlags::Read`
2024-07-17 09:52:58 +00:00
Dunqing
a88d588a07 feat(semantic): add ReferenceFlags::TSTypeQuery to indicate referenced by TSTypeQuery (#4317)
`ReferenceFlags::TSTypeQuery` can be used to help us insist on whether the reference is referenced by the type or not.
2024-07-17 09:52:57 +00:00
Dunqing
c362bf7edf fix(semantic): incorrect resolve references for TSInterfaceHeritage (#4311)
related issue: https://github.com/oxc-project/oxc/issues/3963
fixes: https://github.com/oxc-project/monitor-oxc/actions/runs/9960183591/job/27518854841
2024-07-17 03:33:02 +00:00
Dunqing
351ecf2707 fix(semantic): incorrect resolve references for TSTypeQuery (#4310)
```ts
type A = typeof Foo
                ^^^ Only allow reference to value symbol
```

I have verified the changed snapshot. That's correct
2024-07-17 03:33:00 +00:00
Dunqing
48724a0d44 chore(semantic): copy tests from typescript-eslint’s scope-manager (#3990)
close:  #2947

These fixtures were copied from a5b652da1e/packages/scope-manager/tests/fixtures. We used them to test out semantic `ScopeTree` and `SymbolTable`
2024-07-17 02:50:50 +00:00
Dunqing
1108f2a700 fix(semantic): resolve references to the incorrect symbol (#4280)
close: #3799
related: #3863
2024-07-17 02:50:48 +00:00
rzvxa
fc0b17d5a0 refactor(syntax): turn the AstNodeId::dummy into a constant field. (#4308) 2024-07-16 22:43:21 +00:00
overlookmotel
c5731a5431 refactor(semantic): remove defunct code setting ScopeFlags twice (#4286)
Scope flags for functions is set when the scope is created. Remove redundant code that sets them again.
2024-07-16 07:32:36 +00:00
overlookmotel
2c7bb9f6c8 refactor(ast): pass final ScopeFlags into visit_function (#4283)
We have a strange workaround for `visit_function` where we pass in `ScopeFlags`, to support creating the scope inside `Function`, but setting different flags for `MethodDefinition`s.

Previously `visit_function` took `Option<ScopeFlags>` and then did `flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function` to it. Personally, I found this confusing. When I was looking at `MethodDefinition`, I was wondering "It's a function, why doesn't it set Function flag too?"

This changes makes it more explicit and clear what `ScopeFlags` everything has.
2024-07-16 07:22:07 +00:00
overlookmotel
16698bc191 refactor(semantic): move function/class-specific code into specific visitors (#4278)
Instead of calling `bind_function_or_class_expression` for every scope, and then branching on the AST node kind, insert the relevant code into the visitors for functions and classes. This reduces work on all other kinds of scopes e.g. block statements.
2024-07-15 18:36:20 +00:00
overlookmotel
ee16668168 refactor(semantic): rename function param (#4277)
Small style nit. It's nicer to have Rust Analyser's param name hint show `builder` rather than `_builder`.
2024-07-15 15:06:59 +00:00
overlookmotel
25f0771185 refactor(semantic): alter syntax of control_flow! macro (#4275)
Previously:

```rs
let ix = control_flow!(|self, cfg| cfg.current_node_ix);
```

after this PR:

```rs
let ix = control_flow!(self, |cfg| cfg.current_node_ix);
```

It expands to:

```rs
let ix = if let Some(ref mut cfg) = self.cfg {
    cfg.current_node_ix
} else {
    Default::default()
};
```

So rationale for this change is that it makes it clearer that `self` is passed *in* and `cfg` comes *out* into the "closure".
2024-07-15 14:31:04 +00:00
overlookmotel
639fd48227 refactor(semantic): comment why extra CFG enabled check (#4274)
Add a comment referencing conclusions of #4273.
2024-07-15 12:11:04 +00:00
overlookmotel
f9d3f2ef55 perf(semantic): inline ast record functions (#4272)
Inline these functions so that when CFG is disabled, it doesn't cost a function call just for the trivial `if self.cfg.is_some()` check.

Based on @rzvxa's suggestion in https://github.com/oxc-project/oxc/pull/4263#pullrequestreview-2176762670.
2024-07-15 11:43:48 +00:00
overlookmotel
23743dbd59 perf(semantic): do not record ast nodes for cfg if cfg disabled (#4263)
Control flow graph builder records AST node IDs in a temp structure `ast_node_records`. Disable this if CFG is disabled.
2024-07-15 04:31:47 +00:00
overlookmotel
da69076c98 perf(semantic): reduce overhead of cfg recording ast nodes (#4262)
Control flow graph builder records AST node IDs in a temp structure `ast_nodes_records`. Only the first AST node ID inserted into the `Vec` is ever used, so turn it into just a single value.

Using `AstNodeId::dummy()` as sentinel for "not set" instead of using `Option<AstNodeId>` to reduce size of the records stack. `Option<AstNodeId>` is 16 bytes.
2024-07-15 04:31:43 +00:00
Dunqing
c418bf53ce refactor(semantic): directly record current_node_id when adding a scope (#4265)
close: #4234
2024-07-15 03:02:18 +00:00
Dunqing
ace4f1ff77 refactor(semantic): update the order of visit_function and Visit fields in the builder to be consistent (#4248)
Same as #4195
2024-07-14 11:39:15 +00:00
Dunqing
8bfeabfe6a refactor(semantic): simplify adding SymbolFlags::Export (#4249)
```ts
export default class Binding {}
//                   ^^^^^^^ SymbolFlags::Export

export default function Binding () {}
//                      ^^^^^^^ SymbolFlags::Export

// No binding, so we should not have SymbolFlags::Export
export default function() {}
export default class {}

```
2024-07-14 11:39:13 +00:00
Dunqing
3e099febf6 refactor(ast): move enter_scope after visit_binding_identifier (#4246)
This is now consistent with other ASTs that require bind

2019043e72/crates/oxc_ast/src/ast/ts.rs (L814-L815)
2024-07-14 04:06:02 +00:00
Dunqing
dc2b3c44fb refactor(semantic): add strict mode in scope flags for class definitions (#4156)
related: https://github.com/oxc-project/oxc/issues/4142#issuecomment-2219125356

Although we called `enter_node(Class)`, that doesn't mean we're in the `class` scope. It causes our must to visit decorators before `enter_node`.

Let's look at this case. It causes a syntax error if we don't visit decorators before `enter_node`
```js
// This file was procedurally generated from the following sources:
// - src/decorator/decorator-call-expr-identifier-reference-yield.case
// - src/decorator/syntax/valid/cls-expr-decorators-valid-syntax.template
/*---
description: Decorator @ DecoratorCallExpression (Valid syntax for decorator on class expression)
esid: prod-ClassExpression
features: [class, decorators]
flags: [generated, noStrict]
info: |
    ClassExpression[Yield, Await] :
      DecoratorList[?Yield, ?Await]opt class BindingIdentifier[?Yield, ?Await]opt ClassTail[?Yield, ?Await]

    DecoratorList[Yield, Await] :
      DecoratorList[?Yield, ?Await]opt Decorator[?Yield, ?Await]

    Decorator[Yield, Await] :
      @ DecoratorMemberExpression[?Yield, ?Await]
      @ DecoratorParenthesizedExpression[?Yield, ?Await]
      @ DecoratorCallExpression[?Yield, ?Await]

    ...

    DecoratorCallExpression[Yield, Await] :
      DecoratorMemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await]

    DecoratorMemberExpression[Yield, Await] :
      IdentifierReference[?Yield, ?Await]
      DecoratorMemberExpression[?Yield, ?Await] . IdentifierName
      DecoratorMemberExpression[?Yield, ?Await] . PrivateIdentifier

    IdentifierReference[Yield, Await] :
      [~Yield] yield
      ...

---*/
function decorator() {
  return () => {};
}
var yield = decorator;

var C = @yield() class {};

```
Errors:
```shell
  × The keyword 'yield' is reserved
    ╭─[language/statements/class/decorator/syntax/valid/decorator-call-expr-identifier-reference-yield.js:45:2]
 44 │
 45 │ @yield() class C {}
    ·  ─────
    ╰────
```

The changed code makes more sense. Only if we call `enter_scope` for class, the flags will contain `StrictMode`. Also, we can get the exact `flags` of the `scope` in the `class` at the transformer

For example:

```
class A {
   B() {
       // Before: flags is `Function`
      //  After: flags is `Function | StrictMode`
   }
}
```

The regression tests will be fixed in follow-up PRs
2024-07-14 03:35:12 +00:00
Dunqing
20cdb1fe0a feat(semantic): align class scope with typescript (#4195)
```ts
class Klass <T>   extends Root       <R>                   {}
//    ^^^^^ ^^^           ^^^^       ^^^                   ^^
//    id type_paramter super_class super_type_parameters  body
```
I reorder fields according to the order above

The class scope is not defined in the spec. But we need to create a scope for `class` to store `TypeParamters`
2024-07-14 03:19:30 +00:00
overlookmotel
22d56bdcac fix(semantic): do not resolve references after FormalParameters in TS type (#4241)
Semantic resolves references when exiting `FormalParameters` to ensure references in param initializers don't get bound to bindings inside the function body.

However, it shouldn't do this for `FormalParameters` in TS types e.g. `TSTypeAnnotation` because they don't have their own scopes.
2024-07-13 02:43:01 +00:00
lucab
d7ab0b8413 refactor(semantic)!: simplify node creation (#4226)
This tweaks AST node creation and tree manipulation, directly
building new nodes with a valid node ID.
2024-07-13 02:19:02 +00:00
lucab
81ed5885a8 refactor(semantic): convert scope fields to IndexVecs (#4208)
Closes: https://github.com/oxc-project/backlog/issues/10
2024-07-12 09:43:58 +00:00
Dunqing
92ee77487f feat(semantic): add ScopeFlags::CatchClause for use in CatchClause (#4205) 2024-07-12 03:47:07 +00:00
rzvxa
aab7aaaa06 refactor(ast/visit): fire node events as the outermost one. (#4203)
I'm going to be AFK today(till about 9 PM UTC). Meanwhile, I Didn't want to be a blocker so here we go.
It would fix the #4200 merge if you guys find it in the correct order otherwise feel free to close it.
2024-07-12 03:27:59 +00:00
overlookmotel
cb15303644 perf(semantic): reduce memory copies (#4216)
Reduce memory copies when resolving references in `Semantic`.

If parent scope has no unresolved references for `name`, there is no need to generate a new `Vec<ReferenceId>` for `name` and copy in contents from current scope. Just move the existing `Vec` to the parent.
2024-07-12 02:05:22 +00:00
overlookmotel
ef4c1f4e32 perf(semantic): reduce lookups (#4214)
Small performance optimization (I hope) to resolving references in `Semantic`. Look up current bindings once rather than on every turn of the loop.
2024-07-12 01:41:28 +00:00
overlookmotel
f23e54f97b perf(semantic): recycle unresolved references hash maps (#4213)
Closes #4169.

Reduce allocations while building `Semantic` by recycling hash maps used for tracking unresolved references, rather than creating a new one for every scope.
2024-07-12 01:41:27 +00:00