From a56042020acda99d794fc6b955a9b65a958f0331 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 28 Jun 2018 11:33:40 -0700 Subject: [PATCH 1/2] Introduce more caching and deferral into jsx checking --- src/compiler/checker.ts | 48 ++++++++++++++----- src/compiler/types.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 1 + 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3a0fee79b3e7..f1e857d0b762e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16365,14 +16365,18 @@ namespace ts { type.flags & TypeFlags.UnionOrIntersection && every((type).types, isValidSpreadType)); } - function checkJsxSelfClosingElement(node: JsxSelfClosingElement, checkMode: CheckMode | undefined): Type { - checkJsxOpeningLikeElementOrOpeningFragment(node, checkMode); + function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { + checkJsxOpeningLikeElementOrOpeningFragment(node, CheckMode.Normal); + } + + function checkJsxSelfClosingElement(node: JsxSelfClosingElement, _checkMode: CheckMode | undefined): Type { + checkNodeDeferred(node); return getJsxElementTypeAt(node) || anyType; } - function checkJsxElement(node: JsxElement, checkMode: CheckMode | undefined): Type { + function checkJsxElementDeferred(node: JsxElement) { // Check attributes - checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement, checkMode); + checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement, CheckMode.Normal); // Perform resolution on the closing tag so that rename/go to definition/etc work if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) { @@ -16381,6 +16385,10 @@ namespace ts { else { checkExpression(node.closingElement.tagName); } + } + + function checkJsxElement(node: JsxElement, _checkMode: CheckMode | undefined): Type { + checkNodeDeferred(node); return getJsxElementTypeAt(node) || anyType; } @@ -16661,12 +16669,24 @@ namespace ts { } function getJsxNamespaceAt(location: Node | undefined): Symbol { - const namespaceName = getJsxNamespace(location); - const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); - if (resolvedNamespace) { - const candidate = getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace); - if (candidate) { - return candidate; + const links = location && getNodeLinks(location); + if (links && links.jsxNamespace) { + return links.jsxNamespace; + } + if (!links || links.jsxNamespace !== false) { + const namespaceName = getJsxNamespace(location); + const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); + if (resolvedNamespace) { + const candidate = getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace); + if (candidate) { + if (links) { + links.jsxNamespace = candidate; + } + return candidate; + } + if (links) { + links.jsxNamespace = false; + } } } // JSX global fallback @@ -17146,7 +17166,7 @@ namespace ts { // sourceAttributesType is a type of an attributes properties. // i.e
// attr1 and attr2 are treated as JSXAttributes attached in the JsxOpeningLikeElement as "attributes". - const sourceAttributesType = createJsxAttributesTypeFromAttributesProperty(openingLikeElement, checkMode); + const sourceAttributesType = checkExpressionCached(openingLikeElement.attributes, checkMode); // Check if sourceAttributesType assignable to targetAttributesType though this check will allow excess properties const isSourceAttributeTypeAssignableToTarget = isTypeAssignableTo(sourceAttributesType, targetAttributesType); @@ -26090,6 +26110,12 @@ namespace ts { case SyntaxKind.ClassExpression: checkClassExpressionDeferred(node); break; + case SyntaxKind.JsxSelfClosingElement: + checkJsxSelfClosingElementDeferred(node); + break; + case SyntaxKind.JsxElement: + checkJsxElementDeferred(node); + break; } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 55e2b1d24adee..4f0227ff252ea 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3658,6 +3658,7 @@ namespace ts { hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt. superCall?: SuperCall; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing switchTypes?: Type[]; // Cached array of switch case expression types + jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node } export const enum TypeFlags { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 89214bdb96c2c..b0227ba6b00a3 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3196,6 +3196,7 @@ declare namespace ts { hasSuperCall?: boolean; superCall?: SuperCall; switchTypes?: Type[]; + jsxNamespace?: Symbol | false; } enum TypeFlags { Any = 1, From fe10aaf9f92967d2d891030974cfe1e28d656635 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 28 Jun 2018 12:57:52 -0700 Subject: [PATCH 2/2] Accept baseline with removed duplicated error --- .../inlineJsxFactoryDeclarationsLocalTypes.errors.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt index b4f6fcd9157b7..40cc18accd81a 100644 --- a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt @@ -6,7 +6,6 @@ tests/cases/conformance/jsx/inline/index.tsx(21,22): error TS2322: Type '{ child Types of property 'children' are incompatible. Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element[]' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element[]'. Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'. -tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. Property '__domBrand' is missing in type 'MyClass'. tests/cases/conformance/jsx/inline/index.tsx(21,63): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. @@ -77,7 +76,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,23): error TS2322: Type '{ child export default -==== tests/cases/conformance/jsx/inline/index.tsx (7 errors) ==== +==== tests/cases/conformance/jsx/inline/index.tsx (6 errors) ==== /** @jsx dom */ import { dom } from "./renderer" import prerendered, {MySFC, MyClass, tree} from "./component"; @@ -111,8 +110,6 @@ tests/cases/conformance/jsx/inline/index.tsx(24,23): error TS2322: Type '{ child !!! error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element[]' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element[]'. !!! error TS2322: Type 'import("tests/cases/conformance/jsx/inline/renderer").dom.JSX.Element' is not assignable to type 'import("tests/cases/conformance/jsx/inline/renderer2").predom.JSX.Element'. ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. - ~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. !!! error TS2605: Property '__domBrand' is missing in type 'MyClass'. ~~~~~~~~~~~~~~~~~~~~~~~