Skip to content

Commit

Permalink
Introduce more caching and deferral into jsx checking (#25302)
Browse files Browse the repository at this point in the history
* Introduce more caching and deferral into jsx checking

* Accept baseline with removed duplicated error
  • Loading branch information
weswigham authored Jun 28, 2018
1 parent 53e163d commit 2a19580
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 15 deletions.
48 changes: 37 additions & 11 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16365,14 +16365,18 @@ namespace ts {
type.flags & TypeFlags.UnionOrIntersection && every((<UnionOrIntersectionType>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)) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -17146,7 +17166,7 @@ namespace ts {
// sourceAttributesType is a type of an attributes properties.
// i.e <div attr1={10} attr2="string" />
// 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);
Expand Down Expand Up @@ -26115,6 +26135,12 @@ namespace ts {
case SyntaxKind.ClassExpression:
checkClassExpressionDeferred(<ClassExpression>node);
break;
case SyntaxKind.JsxSelfClosingElement:
checkJsxSelfClosingElementDeferred(<JsxSelfClosingElement>node);
break;
case SyntaxKind.JsxElement:
checkJsxElementDeferred(<JsxElement>node);
break;
}
});
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3196,6 +3196,7 @@ declare namespace ts {
hasSuperCall?: boolean;
superCall?: SuperCall;
switchTypes?: Type[];
jsxNamespace?: Symbol | false;
}
enum TypeFlags {
Any = 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -77,7 +76,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,23): error TS2322: Type '{ child

export default <h></h>

==== 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";
Expand Down Expand Up @@ -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'.
~~~~~~~~~~~~~~~~~~~~~~~
Expand Down

0 comments on commit 2a19580

Please sign in to comment.