From 1b613c3ebf0deccd471c9597998c38a6823a83f6 Mon Sep 17 00:00:00 2001 From: JoostK Date: Thu, 2 May 2019 22:58:07 +0200 Subject: [PATCH] fix(ivy): evaluate external declaration usages as dynamic (#30247) Previously, ngtsc would fail to evaluate expressions that access properties from e.g. the `window` object. This resulted in hard to debug error messages as no indication on where the problem originated was present in the output. This commit cleans up the handling of unknown property accesses, such that evaluating such expressions no longer fail but instead result in a `DynamicValue`. Fixes #30226 PR Close #30247 --- .../src/ngtsc/partial_evaluator/src/dynamic.ts | 3 ++- .../src/ngtsc/partial_evaluator/src/interpreter.ts | 8 ++++++-- .../ngtsc/partial_evaluator/test/evaluator_spec.ts | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts index a0553d2b78..85880d8e74 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts @@ -32,7 +32,8 @@ export const enum DynamicValueReason { /** * An external reference could not be resolved to a value which can be evaluated. - * (E.g. a call expression for a function declared in `.d.ts`.) + * For example a call expression for a function declared in `.d.ts`, or accessing native globals + * such as `window`. */ EXTERNAL_REFERENCE, diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index 80005e48a0..56b9ac70c0 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -11,6 +11,7 @@ import * as ts from 'typescript'; import {Reference} from '../../imports'; import {OwningModule} from '../../imports/src/references'; import {Declaration, ReflectionHost} from '../../reflection'; +import {isDeclaration} from '../../util/src/typescript'; import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn} from './builtin'; import {DynamicValue} from './dynamic'; @@ -361,12 +362,15 @@ export class StaticInterpreter { } } return value; + } else if (isDeclaration(ref)) { + return DynamicValue.fromDynamicInput( + node, DynamicValue.fromExternalReference(ref, lhs as Reference)); } } else if (lhs instanceof DynamicValue) { return DynamicValue.fromDynamicInput(node, lhs); - } else { - throw new Error(`Invalid dot property access: ${lhs} dot ${rhs}`); } + + return DynamicValue.fromUnknown(node); } private visitCallExpression(node: ts.CallExpression, context: Context): ResolvedValue { diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index a4a1d5523a..4cf93ea800 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -122,6 +122,20 @@ describe('ngtsc metadata', () => { expect(evaluate(`const x = 3;`, '!!x')).toEqual(true); }); + it('resolves access from external variable declarations as dynamic value', () => { + const value = evaluate('declare const window: any;', 'window.location'); + if (!(value instanceof DynamicValue)) { + return fail(`Should have resolved to a DynamicValue`); + } + expect(value.isFromDynamicInput()).toEqual(true); + expect(value.node.getText()).toEqual('window.location'); + if (!(value.reason instanceof DynamicValue)) { + return fail(`Should have a DynamicValue as reason`); + } + expect(value.reason.isFromExternalReference()).toEqual(true); + expect(value.reason.node.getText()).toEqual('window: any'); + }); + it('imports work', () => { const {program} = makeProgram([ {name: 'second.ts', contents: 'export function foo(bar) { return bar; }'},