Bail on 0- and 1-length lists in removeSubtypes to avoid spurious circularity problems (#46981)

* Creates a reasonable workaround for #46939

* Remove unrelated newline

* Do the cheap length check ahead of the cache check

* Actually do it.
This commit is contained in:
Ryan Cavanaugh
2022-03-08 08:50:07 -08:00
committed by GitHub
parent d8b21a8d6c
commit af027f34fa
10 changed files with 265 additions and 0 deletions
+6
View File
@@ -14393,11 +14393,17 @@ namespace ts {
}
function removeSubtypes(types: Type[], hasObjectTypes: boolean): Type[] | undefined {
// [] and [T] immediately reduce to [] and [T] respectively
if (types.length < 2) {
return types;
}
const id = getTypeListId(types);
const match = subtypeReductionCache.get(id);
if (match) {
return match;
}
// We assume that redundant primitive types have already been removed from the types array and that there
// are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty
// object types, and if none of those are present we can exclude primitive types from the subtype check.
@@ -0,0 +1,19 @@
tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck.ts(3,7): error TS7023: 'steps' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
==== tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck.ts (1 errors) ====
declare const props: WizardStepProps;
export class Wizard {
get steps() {
~~~~~
!!! error TS7023: 'steps' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
return {
wizard: this,
...props,
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
}
@@ -0,0 +1,43 @@
//// [trivialSubtypeReductionNoStructuralCheck.ts]
declare const props: WizardStepProps;
export class Wizard {
get steps() {
return {
wizard: this,
...props,
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
}
//// [trivialSubtypeReductionNoStructuralCheck.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Wizard = void 0;
var Wizard = /** @class */ (function () {
function Wizard() {
}
Object.defineProperty(Wizard.prototype, "steps", {
get: function () {
return __assign({ wizard: this }, props);
},
enumerable: false,
configurable: true
});
return Wizard;
}());
exports.Wizard = Wizard;
@@ -0,0 +1,31 @@
=== tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck.ts ===
declare const props: WizardStepProps;
>props : Symbol(props, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 0, 13))
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 8, 1))
export class Wizard {
>Wizard : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 0, 37))
get steps() {
>steps : Symbol(Wizard.steps, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 1, 21))
return {
wizard: this,
>wizard : Symbol(wizard, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 3, 12))
>this : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 0, 37))
...props,
>props : Symbol(props, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 0, 13))
} as WizardStepProps;
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 8, 1))
}
}
export interface WizardStepProps {
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 8, 1))
wizard?: Wizard;
>wizard : Symbol(WizardStepProps.wizard, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 10, 34))
>Wizard : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck.ts, 0, 37))
}
@@ -0,0 +1,29 @@
=== tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck.ts ===
declare const props: WizardStepProps;
>props : WizardStepProps
export class Wizard {
>Wizard : Wizard
get steps() {
>steps : any
return {
>{ wizard: this, ...props, } as WizardStepProps : WizardStepProps
>{ wizard: this, ...props, } : { wizard: Wizard; }
wizard: this,
>wizard : this
>this : this
...props,
>props : WizardStepProps
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
>wizard : Wizard | undefined
}
@@ -0,0 +1,43 @@
//// [trivialSubtypeReductionNoStructuralCheck2.ts]
declare const props: WizardStepProps;
export class Wizard {
get steps() {
return {
wizard: this as Wizard,
...props,
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
}
//// [trivialSubtypeReductionNoStructuralCheck2.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Wizard = void 0;
var Wizard = /** @class */ (function () {
function Wizard() {
}
Object.defineProperty(Wizard.prototype, "steps", {
get: function () {
return __assign({ wizard: this }, props);
},
enumerable: false,
configurable: true
});
return Wizard;
}());
exports.Wizard = Wizard;
@@ -0,0 +1,32 @@
=== tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck2.ts ===
declare const props: WizardStepProps;
>props : Symbol(props, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 13))
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 8, 1))
export class Wizard {
>Wizard : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 37))
get steps() {
>steps : Symbol(Wizard.steps, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 1, 21))
return {
wizard: this as Wizard,
>wizard : Symbol(wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 3, 12))
>this : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 37))
>Wizard : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 37))
...props,
>props : Symbol(props, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 13))
} as WizardStepProps;
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 8, 1))
}
}
export interface WizardStepProps {
>WizardStepProps : Symbol(WizardStepProps, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 8, 1))
wizard?: Wizard;
>wizard : Symbol(WizardStepProps.wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 10, 34))
>Wizard : Symbol(Wizard, Decl(trivialSubtypeReductionNoStructuralCheck2.ts, 0, 37))
}
@@ -0,0 +1,30 @@
=== tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck2.ts ===
declare const props: WizardStepProps;
>props : WizardStepProps
export class Wizard {
>Wizard : Wizard
get steps() {
>steps : WizardStepProps
return {
>{ wizard: this as Wizard, ...props, } as WizardStepProps : WizardStepProps
>{ wizard: this as Wizard, ...props, } : { wizard: Wizard; }
wizard: this as Wizard,
>wizard : Wizard
>this as Wizard : Wizard
>this : this
...props,
>props : WizardStepProps
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
>wizard : Wizard | undefined
}
@@ -0,0 +1,16 @@
// @strict: true
// @target: es5
declare const props: WizardStepProps;
export class Wizard {
get steps() {
return {
wizard: this,
...props,
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
}
@@ -0,0 +1,16 @@
// @strict: true
// @target: es5
declare const props: WizardStepProps;
export class Wizard {
get steps() {
return {
wizard: this as Wizard,
...props,
} as WizardStepProps;
}
}
export interface WizardStepProps {
wizard?: Wizard;
}