mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Merge remote-tracking branch 'origin/master' into go_to_implementation_pr
This commit is contained in:
commit
4eef417f4c
@ -7603,16 +7603,24 @@ namespace ts {
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Find each target constituent type that has an identically matching source
|
||||
// constituent type, and for each such target constituent type infer from the type to
|
||||
// itself. When inferring from a type to itself we effectively find all type parameter
|
||||
// occurrences within that type and infer themselves as their type arguments.
|
||||
// Find each source constituent type that has an identically matching target constituent
|
||||
// type, and for each such type infer from the type to itself. When inferring from a
|
||||
// type to itself we effectively find all type parameter occurrences within that type
|
||||
// and infer themselves as their type arguments. We have special handling for numeric
|
||||
// and string literals because the number and string types are not represented as unions
|
||||
// of all their possible values.
|
||||
let matchingTypes: Type[];
|
||||
for (const t of (<UnionOrIntersectionType>target).types) {
|
||||
if (typeIdenticalToSomeType(t, (<UnionOrIntersectionType>source).types)) {
|
||||
for (const t of (<UnionOrIntersectionType>source).types) {
|
||||
if (typeIdenticalToSomeType(t, (<UnionOrIntersectionType>target).types)) {
|
||||
(matchingTypes || (matchingTypes = [])).push(t);
|
||||
inferFromTypes(t, t);
|
||||
}
|
||||
else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) {
|
||||
const b = getBaseTypeOfLiteralType(t);
|
||||
if (typeIdenticalToSomeType(b, (<UnionOrIntersectionType>target).types)) {
|
||||
(matchingTypes || (matchingTypes = [])).push(t, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next, to improve the quality of inferences, reduce the source and target types by
|
||||
// removing the identically matched constituents. For example, when inferring from
|
||||
|
||||
@ -10,6 +10,7 @@ namespace ts {
|
||||
/** Enables substitutions for block-scoped bindings. */
|
||||
BlockScopedBindings = 1 << 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* If loop contains block scoped binding captured in some function then loop body is converted to a function.
|
||||
* Lexical bindings declared in loop initializer will be passed into the loop body function as parameters,
|
||||
@ -166,6 +167,9 @@ namespace ts {
|
||||
let enclosingBlockScopeContainerParent: Node;
|
||||
let containingNonArrowFunction: FunctionLikeDeclaration | ClassElement;
|
||||
|
||||
/** Tracks the container that determines whether `super.x` is a static. */
|
||||
let superScopeContainer: FunctionLikeDeclaration | ClassElement;
|
||||
|
||||
/**
|
||||
* Used to track if we are emitting body of the converted loop
|
||||
*/
|
||||
@ -203,6 +207,7 @@ namespace ts {
|
||||
|
||||
function saveStateAndInvoke<T>(node: Node, f: (node: Node) => T): T {
|
||||
const savedContainingNonArrowFunction = containingNonArrowFunction;
|
||||
const savedSuperScopeContainer = superScopeContainer;
|
||||
const savedCurrentParent = currentParent;
|
||||
const savedCurrentNode = currentNode;
|
||||
const savedEnclosingBlockScopeContainer = enclosingBlockScopeContainer;
|
||||
@ -219,6 +224,7 @@ namespace ts {
|
||||
|
||||
convertedLoopState = savedConvertedLoopState;
|
||||
containingNonArrowFunction = savedContainingNonArrowFunction;
|
||||
superScopeContainer = savedSuperScopeContainer;
|
||||
currentParent = savedCurrentParent;
|
||||
currentNode = savedCurrentNode;
|
||||
enclosingBlockScopeContainer = savedEnclosingBlockScopeContainer;
|
||||
@ -414,13 +420,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
switch (currentParent.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
containingNonArrowFunction = <FunctionLikeDeclaration>currentParent;
|
||||
if (!(containingNonArrowFunction.emitFlags & NodeEmitFlags.AsyncFunctionBody)) {
|
||||
superScopeContainer = containingNonArrowFunction;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2820,9 +2829,9 @@ namespace ts {
|
||||
* Visits the `super` keyword
|
||||
*/
|
||||
function visitSuperKeyword(node: PrimaryExpression): LeftHandSideExpression {
|
||||
return containingNonArrowFunction
|
||||
&& isClassElement(containingNonArrowFunction)
|
||||
&& !hasModifier(containingNonArrowFunction, ModifierFlags.Static)
|
||||
return superScopeContainer
|
||||
&& isClassElement(superScopeContainer)
|
||||
&& !hasModifier(superScopeContainer, ModifierFlags.Static)
|
||||
&& currentParent.kind !== SyntaxKind.CallExpression
|
||||
? createPropertyAccess(createIdentifier("_super"), "prototype")
|
||||
: createIdentifier("_super");
|
||||
|
||||
@ -69,11 +69,11 @@ var B = (function (_super) {
|
||||
var a, b;
|
||||
return __generator(this, function (_a) {
|
||||
// call with property access
|
||||
_super.x.call(this);
|
||||
_super.prototype.x.call(this);
|
||||
// call with element access
|
||||
_super["x"].call(this);
|
||||
a = _super.x;
|
||||
b = _super["x"];
|
||||
_super.prototype["x"].call(this);
|
||||
a = _super.prototype.x;
|
||||
b = _super.prototype["x"];
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
@ -85,15 +85,15 @@ var B = (function (_super) {
|
||||
return __generator(this, function (_c) {
|
||||
f = function () { };
|
||||
// call with property access
|
||||
_super.x.call(this);
|
||||
_super.prototype.x.call(this);
|
||||
// call with element access
|
||||
_super["x"].call(this);
|
||||
a = _super.x;
|
||||
b = _super["x"];
|
||||
_super.prototype["x"].call(this);
|
||||
a = _super.prototype.x;
|
||||
b = _super.prototype["x"];
|
||||
// property access (assign)
|
||||
_super.x = f;
|
||||
_super.prototype.x = f;
|
||||
// element access (assign)
|
||||
_super["x"] = f;
|
||||
_super.prototype["x"] = f;
|
||||
// destructuring assign with property access
|
||||
(_a = { f: f }, super.x = _a.f, _a);
|
||||
// destructuring assign with element access
|
||||
|
||||
59
tests/baselines/reference/typeInferenceLiteralUnion.js
Normal file
59
tests/baselines/reference/typeInferenceLiteralUnion.js
Normal file
@ -0,0 +1,59 @@
|
||||
//// [typeInferenceLiteralUnion.ts]
|
||||
// Repro from #10901
|
||||
/**
|
||||
* Administrivia: JavaScript primitive types and Date
|
||||
*/
|
||||
export type Primitive = number | string | boolean | Date;
|
||||
|
||||
/**
|
||||
* Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations
|
||||
*/
|
||||
interface Numeric {
|
||||
valueOf(): number;
|
||||
}
|
||||
|
||||
// Not very useful, but meets Numeric
|
||||
class NumCoercible {
|
||||
public a: number;
|
||||
|
||||
constructor(a: number) {
|
||||
this.a = a;
|
||||
}
|
||||
public valueOf() {
|
||||
return this.a;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the min and max simultaneously.
|
||||
*/
|
||||
export function extent<T extends Numeric>(array: Array<T | Primitive>): [T | Primitive, T | Primitive] | [undefined, undefined] {
|
||||
return [undefined, undefined];
|
||||
}
|
||||
|
||||
|
||||
let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined];
|
||||
extentMixed = extent([new NumCoercible(10), 13, '12', true]);
|
||||
|
||||
|
||||
//// [typeInferenceLiteralUnion.js]
|
||||
"use strict";
|
||||
// Not very useful, but meets Numeric
|
||||
var NumCoercible = (function () {
|
||||
function NumCoercible(a) {
|
||||
this.a = a;
|
||||
}
|
||||
NumCoercible.prototype.valueOf = function () {
|
||||
return this.a;
|
||||
};
|
||||
return NumCoercible;
|
||||
}());
|
||||
/**
|
||||
* Return the min and max simultaneously.
|
||||
*/
|
||||
function extent(array) {
|
||||
return [undefined, undefined];
|
||||
}
|
||||
exports.extent = extent;
|
||||
var extentMixed;
|
||||
extentMixed = extent([new NumCoercible(10), 13, '12', true]);
|
||||
79
tests/baselines/reference/typeInferenceLiteralUnion.symbols
Normal file
79
tests/baselines/reference/typeInferenceLiteralUnion.symbols
Normal file
@ -0,0 +1,79 @@
|
||||
=== tests/cases/compiler/typeInferenceLiteralUnion.ts ===
|
||||
// Repro from #10901
|
||||
/**
|
||||
* Administrivia: JavaScript primitive types and Date
|
||||
*/
|
||||
export type Primitive = number | string | boolean | Date;
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
>Date : Symbol(Date, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
|
||||
/**
|
||||
* Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations
|
||||
*/
|
||||
interface Numeric {
|
||||
>Numeric : Symbol(Numeric, Decl(typeInferenceLiteralUnion.ts, 4, 57))
|
||||
|
||||
valueOf(): number;
|
||||
>valueOf : Symbol(Numeric.valueOf, Decl(typeInferenceLiteralUnion.ts, 9, 19))
|
||||
}
|
||||
|
||||
// Not very useful, but meets Numeric
|
||||
class NumCoercible {
|
||||
>NumCoercible : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
|
||||
public a: number;
|
||||
>a : Symbol(NumCoercible.a, Decl(typeInferenceLiteralUnion.ts, 14, 20))
|
||||
|
||||
constructor(a: number) {
|
||||
>a : Symbol(a, Decl(typeInferenceLiteralUnion.ts, 17, 16))
|
||||
|
||||
this.a = a;
|
||||
>this.a : Symbol(NumCoercible.a, Decl(typeInferenceLiteralUnion.ts, 14, 20))
|
||||
>this : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
>a : Symbol(NumCoercible.a, Decl(typeInferenceLiteralUnion.ts, 14, 20))
|
||||
>a : Symbol(a, Decl(typeInferenceLiteralUnion.ts, 17, 16))
|
||||
}
|
||||
public valueOf() {
|
||||
>valueOf : Symbol(NumCoercible.valueOf, Decl(typeInferenceLiteralUnion.ts, 19, 5))
|
||||
|
||||
return this.a;
|
||||
>this.a : Symbol(NumCoercible.a, Decl(typeInferenceLiteralUnion.ts, 14, 20))
|
||||
>this : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
>a : Symbol(NumCoercible.a, Decl(typeInferenceLiteralUnion.ts, 14, 20))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the min and max simultaneously.
|
||||
*/
|
||||
export function extent<T extends Numeric>(array: Array<T | Primitive>): [T | Primitive, T | Primitive] | [undefined, undefined] {
|
||||
>extent : Symbol(extent, Decl(typeInferenceLiteralUnion.ts, 23, 1))
|
||||
>T : Symbol(T, Decl(typeInferenceLiteralUnion.ts, 28, 23))
|
||||
>Numeric : Symbol(Numeric, Decl(typeInferenceLiteralUnion.ts, 4, 57))
|
||||
>array : Symbol(array, Decl(typeInferenceLiteralUnion.ts, 28, 42))
|
||||
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(typeInferenceLiteralUnion.ts, 28, 23))
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(typeInferenceLiteralUnion.ts, 28, 23))
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(typeInferenceLiteralUnion.ts, 28, 23))
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
|
||||
return [undefined, undefined];
|
||||
>undefined : Symbol(undefined)
|
||||
>undefined : Symbol(undefined)
|
||||
}
|
||||
|
||||
|
||||
let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined];
|
||||
>extentMixed : Symbol(extentMixed, Decl(typeInferenceLiteralUnion.ts, 33, 3))
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
>NumCoercible : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
>Primitive : Symbol(Primitive, Decl(typeInferenceLiteralUnion.ts, 0, 0))
|
||||
>NumCoercible : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
|
||||
extentMixed = extent([new NumCoercible(10), 13, '12', true]);
|
||||
>extentMixed : Symbol(extentMixed, Decl(typeInferenceLiteralUnion.ts, 33, 3))
|
||||
>extent : Symbol(extent, Decl(typeInferenceLiteralUnion.ts, 23, 1))
|
||||
>NumCoercible : Symbol(NumCoercible, Decl(typeInferenceLiteralUnion.ts, 11, 1))
|
||||
|
||||
89
tests/baselines/reference/typeInferenceLiteralUnion.types
Normal file
89
tests/baselines/reference/typeInferenceLiteralUnion.types
Normal file
@ -0,0 +1,89 @@
|
||||
=== tests/cases/compiler/typeInferenceLiteralUnion.ts ===
|
||||
// Repro from #10901
|
||||
/**
|
||||
* Administrivia: JavaScript primitive types and Date
|
||||
*/
|
||||
export type Primitive = number | string | boolean | Date;
|
||||
>Primitive : Primitive
|
||||
>Date : Date
|
||||
|
||||
/**
|
||||
* Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations
|
||||
*/
|
||||
interface Numeric {
|
||||
>Numeric : Numeric
|
||||
|
||||
valueOf(): number;
|
||||
>valueOf : () => number
|
||||
}
|
||||
|
||||
// Not very useful, but meets Numeric
|
||||
class NumCoercible {
|
||||
>NumCoercible : NumCoercible
|
||||
|
||||
public a: number;
|
||||
>a : number
|
||||
|
||||
constructor(a: number) {
|
||||
>a : number
|
||||
|
||||
this.a = a;
|
||||
>this.a = a : number
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
>a : number
|
||||
}
|
||||
public valueOf() {
|
||||
>valueOf : () => number
|
||||
|
||||
return this.a;
|
||||
>this.a : number
|
||||
>this : this
|
||||
>a : number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the min and max simultaneously.
|
||||
*/
|
||||
export function extent<T extends Numeric>(array: Array<T | Primitive>): [T | Primitive, T | Primitive] | [undefined, undefined] {
|
||||
>extent : <T extends Numeric>(array: (string | number | boolean | Date | T)[]) => [string | number | boolean | Date | T, string | number | boolean | Date | T] | [undefined, undefined]
|
||||
>T : T
|
||||
>Numeric : Numeric
|
||||
>array : (string | number | boolean | Date | T)[]
|
||||
>Array : T[]
|
||||
>T : T
|
||||
>Primitive : Primitive
|
||||
>T : T
|
||||
>Primitive : Primitive
|
||||
>T : T
|
||||
>Primitive : Primitive
|
||||
|
||||
return [undefined, undefined];
|
||||
>[undefined, undefined] : [undefined, undefined]
|
||||
>undefined : undefined
|
||||
>undefined : undefined
|
||||
}
|
||||
|
||||
|
||||
let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined];
|
||||
>extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible]
|
||||
>Primitive : Primitive
|
||||
>NumCoercible : NumCoercible
|
||||
>Primitive : Primitive
|
||||
>NumCoercible : NumCoercible
|
||||
|
||||
extentMixed = extent([new NumCoercible(10), 13, '12', true]);
|
||||
>extentMixed = extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible]
|
||||
>extentMixed : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible]
|
||||
>extent([new NumCoercible(10), 13, '12', true]) : [undefined, undefined] | [string | number | boolean | Date | NumCoercible, string | number | boolean | Date | NumCoercible]
|
||||
>extent : <T extends Numeric>(array: (string | number | boolean | Date | T)[]) => [string | number | boolean | Date | T, string | number | boolean | Date | T] | [undefined, undefined]
|
||||
>[new NumCoercible(10), 13, '12', true] : (true | NumCoercible | 13 | "12")[]
|
||||
>new NumCoercible(10) : NumCoercible
|
||||
>NumCoercible : typeof NumCoercible
|
||||
>10 : 10
|
||||
>13 : 13
|
||||
>'12' : "12"
|
||||
>true : true
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(9,15): error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
|
||||
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,15): error TS2345: Argument of type 'number | "hello"' is not assignable to parameter of type 'string | 1'.
|
||||
Type 'number' is not assignable to type 'string | 1'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ====
|
||||
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (1 errors) ====
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
|
||||
@ -19,9 +17,6 @@ tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference
|
||||
var a2 = f(1, "hello");
|
||||
var a3: number;
|
||||
var a3 = f(1, a1 || "hello");
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type 'number | "hello"' is not assignable to parameter of type 'string | 1'.
|
||||
!!! error TS2345: Type 'number' is not assignable to type 'string | 1'.
|
||||
var a4: any;
|
||||
var a4 = f(undefined, "abc");
|
||||
|
||||
|
||||
35
tests/cases/compiler/typeInferenceLiteralUnion.ts
Normal file
35
tests/cases/compiler/typeInferenceLiteralUnion.ts
Normal file
@ -0,0 +1,35 @@
|
||||
// Repro from #10901
|
||||
/**
|
||||
* Administrivia: JavaScript primitive types and Date
|
||||
*/
|
||||
export type Primitive = number | string | boolean | Date;
|
||||
|
||||
/**
|
||||
* Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations
|
||||
*/
|
||||
interface Numeric {
|
||||
valueOf(): number;
|
||||
}
|
||||
|
||||
// Not very useful, but meets Numeric
|
||||
class NumCoercible {
|
||||
public a: number;
|
||||
|
||||
constructor(a: number) {
|
||||
this.a = a;
|
||||
}
|
||||
public valueOf() {
|
||||
return this.a;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the min and max simultaneously.
|
||||
*/
|
||||
export function extent<T extends Numeric>(array: Array<T | Primitive>): [T | Primitive, T | Primitive] | [undefined, undefined] {
|
||||
return [undefined, undefined];
|
||||
}
|
||||
|
||||
|
||||
let extentMixed: [Primitive | NumCoercible, Primitive | NumCoercible] | [undefined, undefined];
|
||||
extentMixed = extent([new NumCoercible(10), 13, '12', true]);
|
||||
Loading…
x
Reference in New Issue
Block a user