refactor(compiler-cli): visit inline declarations with implementations differently (#39267)

Some inline declarations are of the form:

```
exports.<name> = <implementation>;
```

In this case the declaration `node` is `exports.<name>`.
When interpreting such inline declarations we actually want
to visit the `implementation` expression rather than visiting
the declaration `node`.

This commit adds `implementation?: ts.Expression` to the
`InlineDeclaration` type and updates the interpreter to visit
these expressions as described above.

PR Close #39267
This commit is contained in:
Pete Bacon Darwin 2020-10-14 16:16:18 +01:00 committed by atscott
parent eb9eebbb45
commit ac0016cd82
2 changed files with 12 additions and 3 deletions

View File

@ -11,7 +11,7 @@ import * as ts from 'typescript';
import {Reference} from '../../imports'; import {Reference} from '../../imports';
import {OwningModule} from '../../imports/src/references'; import {OwningModule} from '../../imports/src/references';
import {DependencyTracker} from '../../incremental/api'; import {DependencyTracker} from '../../incremental/api';
import {Declaration, DeclarationNode, EnumMember, FunctionDefinition, isConcreteDeclaration, ReflectionHost, SpecialDeclarationKind} from '../../reflection'; import {Declaration, DeclarationKind, DeclarationNode, EnumMember, FunctionDefinition, isConcreteDeclaration, ReflectionHost, SpecialDeclarationKind} from '../../reflection';
import {isDeclaration} from '../../util/src/typescript'; import {isDeclaration} from '../../util/src/typescript';
import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn} from './builtin'; import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn} from './builtin';
@ -231,7 +231,7 @@ export class StaticInterpreter {
return this.getResolvedEnum(decl.node, decl.identity.enumMembers, context); return this.getResolvedEnum(decl.node, decl.identity.enumMembers, context);
} }
const declContext = {...context, ...joinModuleContext(context, node, decl)}; const declContext = {...context, ...joinModuleContext(context, node, decl)};
const result = this.visitDeclaration(decl.node, declContext); const result = this.visitAmbiguousDeclaration(decl, declContext);
if (result instanceof Reference) { if (result instanceof Reference) {
// Only record identifiers to non-synthetic references. Synthetic references may not have the // Only record identifiers to non-synthetic references. Synthetic references may not have the
// same value at runtime as they do at compile time, so it's not legal to refer to them by the // same value at runtime as they do at compile time, so it's not legal to refer to them by the
@ -337,10 +337,18 @@ export class StaticInterpreter {
}; };
// Visit both concrete and inline declarations. // Visit both concrete and inline declarations.
return this.visitDeclaration(decl.node, declContext); return this.visitAmbiguousDeclaration(decl, declContext);
}); });
} }
private visitAmbiguousDeclaration(decl: Declaration, declContext: Context) {
return decl.kind === DeclarationKind.Inline && decl.implementation !== undefined ?
// Inline declarations with an `implementation` should be visited as expressions
this.visitExpression(decl.implementation, declContext) :
// Otherwise just visit the declaration `node`
this.visitDeclaration(decl.node, declContext);
}
private accessHelper(node: ts.Node, lhs: ResolvedValue, rhs: string|number, context: Context): private accessHelper(node: ts.Node, lhs: ResolvedValue, rhs: string|number, context: Context):
ResolvedValue { ResolvedValue {
const strIndex = `${rhs}`; const strIndex = `${rhs}`;

View File

@ -625,6 +625,7 @@ export interface DownleveledEnum {
export interface InlineDeclaration extends export interface InlineDeclaration extends
BaseDeclaration<Exclude<DeclarationNode, ts.Declaration>> { BaseDeclaration<Exclude<DeclarationNode, ts.Declaration>> {
kind: DeclarationKind.Inline; kind: DeclarationKind.Inline;
implementation?: ts.Expression;
} }
/** /**