Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14198,11 +14198,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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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))
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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))
}
Original file line number Diff line number Diff line change
@@ -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
}
16 changes: 16 additions & 0 deletions tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck.ts
Original file line number Diff line number Diff line change
@@ -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;
}
16 changes: 16 additions & 0 deletions tests/cases/compiler/trivialSubtypeReductionNoStructuralCheck2.ts
Original file line number Diff line number Diff line change
@@ -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;
}