mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Replace subtype check in derivedness check with flags and structure checks (#27403)
* Replace subtype check in derivedness check with flags and structure checks * Remove now extraneous clause
This commit is contained in:
@@ -10616,9 +10616,9 @@ namespace ts {
|
||||
function isTypeDerivedFrom(source: Type, target: Type): boolean {
|
||||
return source.flags & TypeFlags.Union ? every((<UnionType>source).types, t => isTypeDerivedFrom(t, target)) :
|
||||
target.flags & TypeFlags.Union ? some((<UnionType>target).types, t => isTypeDerivedFrom(source, t)) :
|
||||
source.flags & TypeFlags.Primitive && !(target.flags & TypeFlags.Primitive) ? false :
|
||||
source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) :
|
||||
target === globalObjectType || target === globalFunctionType ? isTypeSubtypeOf(source, target) :
|
||||
target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) :
|
||||
target === globalFunctionType ? isFunctionObjectType(source as ObjectType) :
|
||||
hasBaseType(source, getTargetType(target));
|
||||
}
|
||||
|
||||
@@ -15371,7 +15371,7 @@ namespace ts {
|
||||
|
||||
// Check that right operand is a function type with a prototype property
|
||||
const rightType = getTypeOfExpression(expr.right);
|
||||
if (!isTypeSubtypeOf(rightType, globalFunctionType)) {
|
||||
if (!isTypeDerivedFrom(rightType, globalFunctionType)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//// [controlFlowInstanceofExtendsFunction.ts]
|
||||
declare global {
|
||||
interface Function {
|
||||
now(): string;
|
||||
}
|
||||
}
|
||||
|
||||
Function.prototype.now = function () {
|
||||
return "now"
|
||||
}
|
||||
|
||||
class X {
|
||||
static now() {
|
||||
return {}
|
||||
}
|
||||
|
||||
why() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Y {
|
||||
|
||||
}
|
||||
|
||||
console.log(X.now()) // works as expected
|
||||
console.log(Y.now()) // works as expected
|
||||
|
||||
export const x: X | number = Math.random() > 0.5 ? new X() : 1
|
||||
|
||||
if (x instanceof X) {
|
||||
x.why() // should compile
|
||||
}
|
||||
|
||||
//// [controlFlowInstanceofExtendsFunction.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
Function.prototype.now = function () {
|
||||
return "now";
|
||||
};
|
||||
var X = /** @class */ (function () {
|
||||
function X() {
|
||||
}
|
||||
X.now = function () {
|
||||
return {};
|
||||
};
|
||||
X.prototype.why = function () {
|
||||
};
|
||||
return X;
|
||||
}());
|
||||
var Y = /** @class */ (function () {
|
||||
function Y() {
|
||||
}
|
||||
return Y;
|
||||
}());
|
||||
console.log(X.now()); // works as expected
|
||||
console.log(Y.now()); // works as expected
|
||||
exports.x = Math.random() > 0.5 ? new X() : 1;
|
||||
if (exports.x instanceof X) {
|
||||
exports.x.why(); // should compile
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowInstanceofExtendsFunction.ts ===
|
||||
declare global {
|
||||
>global : Symbol(global, Decl(controlFlowInstanceofExtendsFunction.ts, 0, 0))
|
||||
|
||||
interface Function {
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(controlFlowInstanceofExtendsFunction.ts, 0, 16))
|
||||
|
||||
now(): string;
|
||||
>now : Symbol(Function.now, Decl(controlFlowInstanceofExtendsFunction.ts, 1, 24))
|
||||
}
|
||||
}
|
||||
|
||||
Function.prototype.now = function () {
|
||||
>Function.prototype.now : Symbol(Function.now, Decl(controlFlowInstanceofExtendsFunction.ts, 1, 24))
|
||||
>Function.prototype : Symbol(FunctionConstructor.prototype, Decl(lib.es5.d.ts, --, --))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(controlFlowInstanceofExtendsFunction.ts, 0, 16))
|
||||
>prototype : Symbol(FunctionConstructor.prototype, Decl(lib.es5.d.ts, --, --))
|
||||
>now : Symbol(Function.now, Decl(controlFlowInstanceofExtendsFunction.ts, 1, 24))
|
||||
|
||||
return "now"
|
||||
}
|
||||
|
||||
class X {
|
||||
>X : Symbol(X, Decl(controlFlowInstanceofExtendsFunction.ts, 8, 1))
|
||||
|
||||
static now() {
|
||||
>now : Symbol(X.now, Decl(controlFlowInstanceofExtendsFunction.ts, 10, 9))
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
why() {
|
||||
>why : Symbol(X.why, Decl(controlFlowInstanceofExtendsFunction.ts, 13, 5))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Y {
|
||||
>Y : Symbol(Y, Decl(controlFlowInstanceofExtendsFunction.ts, 18, 1))
|
||||
|
||||
}
|
||||
|
||||
console.log(X.now()) // works as expected
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>X.now : Symbol(X.now, Decl(controlFlowInstanceofExtendsFunction.ts, 10, 9))
|
||||
>X : Symbol(X, Decl(controlFlowInstanceofExtendsFunction.ts, 8, 1))
|
||||
>now : Symbol(X.now, Decl(controlFlowInstanceofExtendsFunction.ts, 10, 9))
|
||||
|
||||
console.log(Y.now()) // works as expected
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>Y.now : Symbol(Function.now, Decl(controlFlowInstanceofExtendsFunction.ts, 1, 24))
|
||||
>Y : Symbol(Y, Decl(controlFlowInstanceofExtendsFunction.ts, 18, 1))
|
||||
>now : Symbol(Function.now, Decl(controlFlowInstanceofExtendsFunction.ts, 1, 24))
|
||||
|
||||
export const x: X | number = Math.random() > 0.5 ? new X() : 1
|
||||
>x : Symbol(x, Decl(controlFlowInstanceofExtendsFunction.ts, 27, 12))
|
||||
>X : Symbol(X, Decl(controlFlowInstanceofExtendsFunction.ts, 8, 1))
|
||||
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
>X : Symbol(X, Decl(controlFlowInstanceofExtendsFunction.ts, 8, 1))
|
||||
|
||||
if (x instanceof X) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceofExtendsFunction.ts, 27, 12))
|
||||
>X : Symbol(X, Decl(controlFlowInstanceofExtendsFunction.ts, 8, 1))
|
||||
|
||||
x.why() // should compile
|
||||
>x.why : Symbol(X.why, Decl(controlFlowInstanceofExtendsFunction.ts, 13, 5))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceofExtendsFunction.ts, 27, 12))
|
||||
>why : Symbol(X.why, Decl(controlFlowInstanceofExtendsFunction.ts, 13, 5))
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowInstanceofExtendsFunction.ts ===
|
||||
declare global {
|
||||
>global : any
|
||||
|
||||
interface Function {
|
||||
now(): string;
|
||||
>now : () => string
|
||||
}
|
||||
}
|
||||
|
||||
Function.prototype.now = function () {
|
||||
>Function.prototype.now = function () { return "now"} : () => string
|
||||
>Function.prototype.now : () => string
|
||||
>Function.prototype : Function
|
||||
>Function : FunctionConstructor
|
||||
>prototype : Function
|
||||
>now : () => string
|
||||
>function () { return "now"} : () => string
|
||||
|
||||
return "now"
|
||||
>"now" : "now"
|
||||
}
|
||||
|
||||
class X {
|
||||
>X : X
|
||||
|
||||
static now() {
|
||||
>now : () => {}
|
||||
|
||||
return {}
|
||||
>{} : {}
|
||||
}
|
||||
|
||||
why() {
|
||||
>why : () => void
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Y {
|
||||
>Y : Y
|
||||
|
||||
}
|
||||
|
||||
console.log(X.now()) // works as expected
|
||||
>console.log(X.now()) : void
|
||||
>console.log : (message?: any, ...optionalParams: any[]) => void
|
||||
>console : Console
|
||||
>log : (message?: any, ...optionalParams: any[]) => void
|
||||
>X.now() : {}
|
||||
>X.now : () => {}
|
||||
>X : typeof X
|
||||
>now : () => {}
|
||||
|
||||
console.log(Y.now()) // works as expected
|
||||
>console.log(Y.now()) : void
|
||||
>console.log : (message?: any, ...optionalParams: any[]) => void
|
||||
>console : Console
|
||||
>log : (message?: any, ...optionalParams: any[]) => void
|
||||
>Y.now() : string
|
||||
>Y.now : () => string
|
||||
>Y : typeof Y
|
||||
>now : () => string
|
||||
|
||||
export const x: X | number = Math.random() > 0.5 ? new X() : 1
|
||||
>x : number | X
|
||||
>Math.random() > 0.5 ? new X() : 1 : X | 1
|
||||
>Math.random() > 0.5 : boolean
|
||||
>Math.random() : number
|
||||
>Math.random : () => number
|
||||
>Math : Math
|
||||
>random : () => number
|
||||
>0.5 : 0.5
|
||||
>new X() : X
|
||||
>X : typeof X
|
||||
>1 : 1
|
||||
|
||||
if (x instanceof X) {
|
||||
>x instanceof X : boolean
|
||||
>x : number | X
|
||||
>X : typeof X
|
||||
|
||||
x.why() // should compile
|
||||
>x.why() : void
|
||||
>x.why : () => void
|
||||
>x : X
|
||||
>why : () => void
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
declare global {
|
||||
interface Function {
|
||||
now(): string;
|
||||
}
|
||||
}
|
||||
|
||||
Function.prototype.now = function () {
|
||||
return "now"
|
||||
}
|
||||
|
||||
class X {
|
||||
static now() {
|
||||
return {}
|
||||
}
|
||||
|
||||
why() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Y {
|
||||
|
||||
}
|
||||
|
||||
console.log(X.now()) // works as expected
|
||||
console.log(Y.now()) // works as expected
|
||||
|
||||
export const x: X | number = Math.random() > 0.5 ? new X() : 1
|
||||
|
||||
if (x instanceof X) {
|
||||
x.why() // should compile
|
||||
}
|
||||
Reference in New Issue
Block a user