Merge pull request #33678 from microsoft/fix33617

Property handle recursive type references in type inference
This commit is contained in:
Anders Hejlsberg 2019-09-30 11:15:27 -07:00 committed by GitHub
commit 7ce793c5b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 687 additions and 3 deletions

View file

@ -17070,7 +17070,7 @@ namespace ts {
function couldContainTypeVariables(type: Type): boolean {
const objectFlags = getObjectFlags(type);
return !!(type.flags & TypeFlags.Instantiable ||
objectFlags & ObjectFlags.Reference && forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables) ||
objectFlags & ObjectFlags.Reference && ((<TypeReference>type).node || forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables)) ||
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
objectFlags & ObjectFlags.Mapped ||
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(<UnionOrIntersectionType>type));
@ -17367,7 +17367,8 @@ namespace ts {
}
}
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) {
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target)) &&
!((<TypeReference>source).node && (<TypeReference>target).node)) {
// If source and target are references to the same generic type, infer from type arguments
inferFromTypeArguments(getTypeArguments(<TypeReference>source), getTypeArguments(<TypeReference>target), getVariances((<TypeReference>source).target));
}
@ -17648,6 +17649,12 @@ namespace ts {
}
function inferFromObjectTypesWorker(source: Type, target: Type) {
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) {
// If source and target are references to the same generic type, infer from type arguments
inferFromTypeArguments(getTypeArguments(<TypeReference>source), getTypeArguments(<TypeReference>target), getVariances((<TypeReference>source).target));
return;
}
if (isGenericMappedType(source) && isGenericMappedType(target)) {
// The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer
// from S to T and from X to Y.

View file

@ -2,9 +2,18 @@ tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeRefe
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(60,7): error TS2322: Type 'number' is not assignable to type 'string | RecArray<string>'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(66,8): error TS2322: Type 'number' is not assignable to type 'string | string[]'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(72,8): error TS2322: Type 'number' is not assignable to type 'string | (string | string[])[]'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(102,10): error TS2304: Cannot find name 'html'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(104,12): error TS2304: Cannot find name 'html'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(105,7): error TS2304: Cannot find name 'html'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(106,52): error TS2304: Cannot find name 'frag'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(116,11): error TS2304: Cannot find name 'concat'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(116,24): error TS2304: Cannot find name 'concat'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(117,11): error TS2304: Cannot find name 'concat'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(122,11): error TS2304: Cannot find name 'concat'.
tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts(127,3): error TS2304: Cannot find name 'assert'.
==== tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts (4 errors) ====
==== tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeReferences1.ts (13 errors) ====
type ValueOrArray<T> = T | Array<ValueOrArray<T>>;
const a0: ValueOrArray<number> = 1;
@ -92,4 +101,72 @@ tests/cases/conformance/types/typeRelationships/recursiveTypes/recursiveTypeRefe
type T13 = T13[] | string;
type T14 = T14[] & { x: string };
type T15<X> = X extends string ? T15<X>[] : never;
type ValueOrArray1<T> = T | ValueOrArray1<T>[];
type ValueOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo1<T>(a: ValueOrArray1<T>): T;
declare let ra1: ValueOrArray2<string>;
let x1 = foo1(ra1); // Boom!
type NumberOrArray1<T> = T | ValueOrArray1<T>[];
type NumberOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo2<T>(a: ValueOrArray1<T>): T;
declare let ra2: ValueOrArray2<string>;
let x2 = foo2(ra2); // Boom!
// Repro from #33617 (errors are expected)
type Tree = [HTMLHeadingElement, Tree][];
function parse(node: Tree, index: number[] = []): HTMLUListElement {
return html('ul', node.map(([el, children], i) => {
~~~~
!!! error TS2304: Cannot find name 'html'.
const idx = [...index, i + 1];
return html('li', [
~~~~
!!! error TS2304: Cannot find name 'html'.
html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!),
~~~~
!!! error TS2304: Cannot find name 'html'.
children.length > 0 ? parse(children, idx) : frag()
~~~~
!!! error TS2304: Cannot find name 'frag'.
]);
}));
}
function cons(hs: HTMLHeadingElement[]): Tree {
return hs
.reduce<HTMLHeadingElement[][]>((hss, h) => {
const hs = hss.pop()!;
return hs.length === 0 || level(h) > level(hs[0])
? concat(hss, [concat(hs, [h])])
~~~~~~
!!! error TS2304: Cannot find name 'concat'.
~~~~~~
!!! error TS2304: Cannot find name 'concat'.
: concat(hss, [hs, [h]]);
~~~~~~
!!! error TS2304: Cannot find name 'concat'.
}, [[]])
.reduce<Tree>((node, hs) =>
hs.length === 0
? node
: concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]])
~~~~~~
!!! error TS2304: Cannot find name 'concat'.
, []);
}
function level(h: HTMLHeadingElement): number {
assert(isFinite(+h.tagName[1]));
~~~~~~
!!! error TS2304: Cannot find name 'assert'.
return +h.tagName[1];
}

View file

@ -78,10 +78,67 @@ type T12 = (T12)[];
type T13 = T13[] | string;
type T14 = T14[] & { x: string };
type T15<X> = X extends string ? T15<X>[] : never;
type ValueOrArray1<T> = T | ValueOrArray1<T>[];
type ValueOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo1<T>(a: ValueOrArray1<T>): T;
declare let ra1: ValueOrArray2<string>;
let x1 = foo1(ra1); // Boom!
type NumberOrArray1<T> = T | ValueOrArray1<T>[];
type NumberOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo2<T>(a: ValueOrArray1<T>): T;
declare let ra2: ValueOrArray2<string>;
let x2 = foo2(ra2); // Boom!
// Repro from #33617 (errors are expected)
type Tree = [HTMLHeadingElement, Tree][];
function parse(node: Tree, index: number[] = []): HTMLUListElement {
return html('ul', node.map(([el, children], i) => {
const idx = [...index, i + 1];
return html('li', [
html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!),
children.length > 0 ? parse(children, idx) : frag()
]);
}));
}
function cons(hs: HTMLHeadingElement[]): Tree {
return hs
.reduce<HTMLHeadingElement[][]>((hss, h) => {
const hs = hss.pop()!;
return hs.length === 0 || level(h) > level(hs[0])
? concat(hss, [concat(hs, [h])])
: concat(hss, [hs, [h]]);
}, [[]])
.reduce<Tree>((node, hs) =>
hs.length === 0
? node
: concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]])
, []);
}
function level(h: HTMLHeadingElement): number {
assert(isFinite(+h.tagName[1]));
return +h.tagName[1];
}
//// [recursiveTypeReferences1.js]
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var a0 = 1;
var a1 = [1, [2, 3], [4, [5, [6, 7]]]];
var hypertextNode = ["div", { id: "parent" },
@ -124,6 +181,37 @@ flat2([[[0]]]); // number[]
flat2([1, 'a', [2]]); // (string | number)[]
flat2([1, [2, 'a']]); // (string | number)[]
flat2([1, ['a']]); // Error
var x1 = foo1(ra1); // Boom!
var x2 = foo2(ra2); // Boom!
function parse(node, index) {
if (index === void 0) { index = []; }
return html('ul', node.map(function (_a, i) {
var el = _a[0], children = _a[1];
var idx = __spreadArrays(index, [i + 1]);
return html('li', [
html('a', { href: "#" + el.id, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent),
children.length > 0 ? parse(children, idx) : frag()
]);
}));
}
function cons(hs) {
return hs
.reduce(function (hss, h) {
var hs = hss.pop();
return hs.length === 0 || level(h) > level(hs[0])
? concat(hss, [concat(hs, [h])])
: concat(hss, [hs, [h]]);
}, [[]])
.reduce(function (node, hs) {
return hs.length === 0
? node
: concat(node, [[hs.shift(), cons(hs)]]);
}, []);
}
function level(h) {
assert(isFinite(+h.tagName[1]));
return +h.tagName[1];
}
//// [recursiveTypeReferences1.d.ts]
@ -165,3 +253,17 @@ declare type T14 = T14[] & {
x: string;
};
declare type T15<X> = X extends string ? T15<X>[] : never;
declare type ValueOrArray1<T> = T | ValueOrArray1<T>[];
declare type ValueOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo1<T>(a: ValueOrArray1<T>): T;
declare let ra1: ValueOrArray2<string>;
declare let x1: string;
declare type NumberOrArray1<T> = T | ValueOrArray1<T>[];
declare type NumberOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo2<T>(a: ValueOrArray1<T>): T;
declare let ra2: ValueOrArray2<string>;
declare let x2: string;
declare type Tree = [HTMLHeadingElement, Tree][];
declare function parse(node: Tree, index?: number[]): HTMLUListElement;
declare function cons(hs: HTMLHeadingElement[]): Tree;
declare function level(h: HTMLHeadingElement): number;

View file

@ -275,3 +275,205 @@ type T15<X> = X extends string ? T15<X>[] : never;
>T15 : Symbol(T15, Decl(recursiveTypeReferences1.ts, 77, 33))
>X : Symbol(X, Decl(recursiveTypeReferences1.ts, 78, 9))
type ValueOrArray1<T> = T | ValueOrArray1<T>[];
>ValueOrArray1 : Symbol(ValueOrArray1, Decl(recursiveTypeReferences1.ts, 78, 50))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 80, 19))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 80, 19))
>ValueOrArray1 : Symbol(ValueOrArray1, Decl(recursiveTypeReferences1.ts, 78, 50))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 80, 19))
type ValueOrArray2<T> = T | ValueOrArray2<T>[];
>ValueOrArray2 : Symbol(ValueOrArray2, Decl(recursiveTypeReferences1.ts, 80, 47))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 81, 19))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 81, 19))
>ValueOrArray2 : Symbol(ValueOrArray2, Decl(recursiveTypeReferences1.ts, 80, 47))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 81, 19))
declare function foo1<T>(a: ValueOrArray1<T>): T;
>foo1 : Symbol(foo1, Decl(recursiveTypeReferences1.ts, 81, 47))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 83, 22))
>a : Symbol(a, Decl(recursiveTypeReferences1.ts, 83, 25))
>ValueOrArray1 : Symbol(ValueOrArray1, Decl(recursiveTypeReferences1.ts, 78, 50))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 83, 22))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 83, 22))
declare let ra1: ValueOrArray2<string>;
>ra1 : Symbol(ra1, Decl(recursiveTypeReferences1.ts, 84, 11))
>ValueOrArray2 : Symbol(ValueOrArray2, Decl(recursiveTypeReferences1.ts, 80, 47))
let x1 = foo1(ra1); // Boom!
>x1 : Symbol(x1, Decl(recursiveTypeReferences1.ts, 86, 3))
>foo1 : Symbol(foo1, Decl(recursiveTypeReferences1.ts, 81, 47))
>ra1 : Symbol(ra1, Decl(recursiveTypeReferences1.ts, 84, 11))
type NumberOrArray1<T> = T | ValueOrArray1<T>[];
>NumberOrArray1 : Symbol(NumberOrArray1, Decl(recursiveTypeReferences1.ts, 86, 19))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 88, 20))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 88, 20))
>ValueOrArray1 : Symbol(ValueOrArray1, Decl(recursiveTypeReferences1.ts, 78, 50))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 88, 20))
type NumberOrArray2<T> = T | ValueOrArray2<T>[];
>NumberOrArray2 : Symbol(NumberOrArray2, Decl(recursiveTypeReferences1.ts, 88, 48))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 89, 20))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 89, 20))
>ValueOrArray2 : Symbol(ValueOrArray2, Decl(recursiveTypeReferences1.ts, 80, 47))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 89, 20))
declare function foo2<T>(a: ValueOrArray1<T>): T;
>foo2 : Symbol(foo2, Decl(recursiveTypeReferences1.ts, 89, 48))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 91, 22))
>a : Symbol(a, Decl(recursiveTypeReferences1.ts, 91, 25))
>ValueOrArray1 : Symbol(ValueOrArray1, Decl(recursiveTypeReferences1.ts, 78, 50))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 91, 22))
>T : Symbol(T, Decl(recursiveTypeReferences1.ts, 91, 22))
declare let ra2: ValueOrArray2<string>;
>ra2 : Symbol(ra2, Decl(recursiveTypeReferences1.ts, 92, 11))
>ValueOrArray2 : Symbol(ValueOrArray2, Decl(recursiveTypeReferences1.ts, 80, 47))
let x2 = foo2(ra2); // Boom!
>x2 : Symbol(x2, Decl(recursiveTypeReferences1.ts, 94, 3))
>foo2 : Symbol(foo2, Decl(recursiveTypeReferences1.ts, 89, 48))
>ra2 : Symbol(ra2, Decl(recursiveTypeReferences1.ts, 92, 11))
// Repro from #33617 (errors are expected)
type Tree = [HTMLHeadingElement, Tree][];
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
>HTMLHeadingElement : Symbol(HTMLHeadingElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
function parse(node: Tree, index: number[] = []): HTMLUListElement {
>parse : Symbol(parse, Decl(recursiveTypeReferences1.ts, 98, 41))
>node : Symbol(node, Decl(recursiveTypeReferences1.ts, 100, 15))
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
>index : Symbol(index, Decl(recursiveTypeReferences1.ts, 100, 26))
>HTMLUListElement : Symbol(HTMLUListElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
return html('ul', node.map(([el, children], i) => {
>node.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
>node : Symbol(node, Decl(recursiveTypeReferences1.ts, 100, 15))
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
>el : Symbol(el, Decl(recursiveTypeReferences1.ts, 101, 31))
>children : Symbol(children, Decl(recursiveTypeReferences1.ts, 101, 34))
>i : Symbol(i, Decl(recursiveTypeReferences1.ts, 101, 45))
const idx = [...index, i + 1];
>idx : Symbol(idx, Decl(recursiveTypeReferences1.ts, 102, 9))
>index : Symbol(index, Decl(recursiveTypeReferences1.ts, 100, 26))
>i : Symbol(i, Decl(recursiveTypeReferences1.ts, 101, 45))
return html('li', [
html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!),
>href : Symbol(href, Decl(recursiveTypeReferences1.ts, 104, 17))
>el.id : Symbol(Element.id, Decl(lib.dom.d.ts, --, --))
>el : Symbol(el, Decl(recursiveTypeReferences1.ts, 101, 31))
>id : Symbol(Element.id, Decl(lib.dom.d.ts, --, --))
>rel : Symbol(rel, Decl(recursiveTypeReferences1.ts, 104, 36))
>'data-index' : Symbol('data-index', Decl(recursiveTypeReferences1.ts, 104, 53))
>idx.join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
>idx : Symbol(idx, Decl(recursiveTypeReferences1.ts, 102, 9))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
>el.textContent : Symbol(Node.textContent, Decl(lib.dom.d.ts, --, --))
>el : Symbol(el, Decl(recursiveTypeReferences1.ts, 101, 31))
>textContent : Symbol(Node.textContent, Decl(lib.dom.d.ts, --, --))
children.length > 0 ? parse(children, idx) : frag()
>children.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>children : Symbol(children, Decl(recursiveTypeReferences1.ts, 101, 34))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>parse : Symbol(parse, Decl(recursiveTypeReferences1.ts, 98, 41))
>children : Symbol(children, Decl(recursiveTypeReferences1.ts, 101, 34))
>idx : Symbol(idx, Decl(recursiveTypeReferences1.ts, 102, 9))
]);
}));
}
function cons(hs: HTMLHeadingElement[]): Tree {
>cons : Symbol(cons, Decl(recursiveTypeReferences1.ts, 108, 1))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 110, 14))
>HTMLHeadingElement : Symbol(HTMLHeadingElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
return hs
>hs .reduce<HTMLHeadingElement[][]>((hss, h) => { const hs = hss.pop()!; return hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]); }, [[]]) .reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>hs .reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 110, 14))
.reduce<HTMLHeadingElement[][]>((hss, h) => {
>reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>HTMLHeadingElement : Symbol(HTMLHeadingElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
>hss : Symbol(hss, Decl(recursiveTypeReferences1.ts, 112, 37))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 112, 41))
const hs = hss.pop()!;
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 113, 11))
>hss.pop : Symbol(Array.pop, Decl(lib.es5.d.ts, --, --))
>hss : Symbol(hss, Decl(recursiveTypeReferences1.ts, 112, 37))
>pop : Symbol(Array.pop, Decl(lib.es5.d.ts, --, --))
return hs.length === 0 || level(h) > level(hs[0])
>hs.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 113, 11))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>level : Symbol(level, Decl(recursiveTypeReferences1.ts, 123, 1))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 112, 41))
>level : Symbol(level, Decl(recursiveTypeReferences1.ts, 123, 1))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 113, 11))
? concat(hss, [concat(hs, [h])])
>hss : Symbol(hss, Decl(recursiveTypeReferences1.ts, 112, 37))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 113, 11))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 112, 41))
: concat(hss, [hs, [h]]);
>hss : Symbol(hss, Decl(recursiveTypeReferences1.ts, 112, 37))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 113, 11))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 112, 41))
}, [[]])
.reduce<Tree>((node, hs) =>
>reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
>node : Symbol(node, Decl(recursiveTypeReferences1.ts, 118, 19))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 118, 24))
hs.length === 0
>hs.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 118, 24))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
? node
>node : Symbol(node, Decl(recursiveTypeReferences1.ts, 118, 19))
: concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]])
>Tree : Symbol(Tree, Decl(recursiveTypeReferences1.ts, 94, 19))
>node : Symbol(node, Decl(recursiveTypeReferences1.ts, 118, 19))
>hs.shift : Symbol(Array.shift, Decl(lib.es5.d.ts, --, --))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 118, 24))
>shift : Symbol(Array.shift, Decl(lib.es5.d.ts, --, --))
>cons : Symbol(cons, Decl(recursiveTypeReferences1.ts, 108, 1))
>hs : Symbol(hs, Decl(recursiveTypeReferences1.ts, 118, 24))
, []);
}
function level(h: HTMLHeadingElement): number {
>level : Symbol(level, Decl(recursiveTypeReferences1.ts, 123, 1))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 125, 15))
>HTMLHeadingElement : Symbol(HTMLHeadingElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
assert(isFinite(+h.tagName[1]));
>isFinite : Symbol(isFinite, Decl(lib.es5.d.ts, --, --))
>h.tagName : Symbol(Element.tagName, Decl(lib.dom.d.ts, --, --))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 125, 15))
>tagName : Symbol(Element.tagName, Decl(lib.dom.d.ts, --, --))
return +h.tagName[1];
>h.tagName : Symbol(Element.tagName, Decl(lib.dom.d.ts, --, --))
>h : Symbol(h, Decl(recursiveTypeReferences1.ts, 125, 15))
>tagName : Symbol(Element.tagName, Decl(lib.dom.d.ts, --, --))
}

View file

@ -362,3 +362,249 @@ type T14 = T14[] & { x: string };
type T15<X> = X extends string ? T15<X>[] : never;
>T15 : T15<X>
type ValueOrArray1<T> = T | ValueOrArray1<T>[];
>ValueOrArray1 : ValueOrArray1<T>
type ValueOrArray2<T> = T | ValueOrArray2<T>[];
>ValueOrArray2 : ValueOrArray2<T>
declare function foo1<T>(a: ValueOrArray1<T>): T;
>foo1 : <T>(a: ValueOrArray1<T>) => T
>a : ValueOrArray1<T>
declare let ra1: ValueOrArray2<string>;
>ra1 : ValueOrArray2<string>
let x1 = foo1(ra1); // Boom!
>x1 : string
>foo1(ra1) : string
>foo1 : <T>(a: ValueOrArray1<T>) => T
>ra1 : ValueOrArray2<string>
type NumberOrArray1<T> = T | ValueOrArray1<T>[];
>NumberOrArray1 : NumberOrArray1<T>
type NumberOrArray2<T> = T | ValueOrArray2<T>[];
>NumberOrArray2 : NumberOrArray2<T>
declare function foo2<T>(a: ValueOrArray1<T>): T;
>foo2 : <T>(a: ValueOrArray1<T>) => T
>a : ValueOrArray1<T>
declare let ra2: ValueOrArray2<string>;
>ra2 : ValueOrArray2<string>
let x2 = foo2(ra2); // Boom!
>x2 : string
>foo2(ra2) : string
>foo2 : <T>(a: ValueOrArray1<T>) => T
>ra2 : ValueOrArray2<string>
// Repro from #33617 (errors are expected)
type Tree = [HTMLHeadingElement, Tree][];
>Tree : Tree
function parse(node: Tree, index: number[] = []): HTMLUListElement {
>parse : (node: Tree, index?: number[]) => HTMLUListElement
>node : Tree
>index : number[]
>[] : never[]
return html('ul', node.map(([el, children], i) => {
>html('ul', node.map(([el, children], i) => { const idx = [...index, i + 1]; return html('li', [ html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!), children.length > 0 ? parse(children, idx) : frag() ]); })) : any
>html : any
>'ul' : "ul"
>node.map(([el, children], i) => { const idx = [...index, i + 1]; return html('li', [ html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!), children.length > 0 ? parse(children, idx) : frag() ]); }) : any[]
>node.map : <U>(callbackfn: (value: [HTMLHeadingElement, Tree], index: number, array: [HTMLHeadingElement, Tree][]) => U, thisArg?: any) => U[]
>node : Tree
>map : <U>(callbackfn: (value: [HTMLHeadingElement, Tree], index: number, array: [HTMLHeadingElement, Tree][]) => U, thisArg?: any) => U[]
>([el, children], i) => { const idx = [...index, i + 1]; return html('li', [ html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!), children.length > 0 ? parse(children, idx) : frag() ]); } : ([el, children]: [HTMLHeadingElement, Tree], i: number) => any
>el : HTMLHeadingElement
>children : Tree
>i : number
const idx = [...index, i + 1];
>idx : number[]
>[...index, i + 1] : number[]
>...index : number
>index : number[]
>i + 1 : number
>i : number
>1 : 1
return html('li', [
>html('li', [ html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!), children.length > 0 ? parse(children, idx) : frag() ]) : any
>html : any
>'li' : "li"
>[ html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!), children.length > 0 ? parse(children, idx) : frag() ] : any[]
html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!),
>html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!) : any
>html : any
>'a' : "a"
>{ href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') } : { href: string; rel: string; 'data-index': string; }
>href : string
>`#${el.id}` : string
>el.id : string
>el : HTMLHeadingElement
>id : string
>rel : string
>'noopener' : "noopener"
>'data-index' : string
>idx.join('.') : string
>idx.join : (separator?: string | undefined) => string
>idx : number[]
>join : (separator?: string | undefined) => string
>'.' : "."
>el.textContent! : string
>el.textContent : string | null
>el : HTMLHeadingElement
>textContent : string | null
children.length > 0 ? parse(children, idx) : frag()
>children.length > 0 ? parse(children, idx) : frag() : any
>children.length > 0 : boolean
>children.length : number
>children : Tree
>length : number
>0 : 0
>parse(children, idx) : HTMLUListElement
>parse : (node: Tree, index?: number[]) => HTMLUListElement
>children : Tree
>idx : number[]
>frag() : any
>frag : any
]);
}));
}
function cons(hs: HTMLHeadingElement[]): Tree {
>cons : (hs: HTMLHeadingElement[]) => Tree
>hs : HTMLHeadingElement[]
return hs
>hs .reduce<HTMLHeadingElement[][]>((hss, h) => { const hs = hss.pop()!; return hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]); }, [[]]) .reduce<Tree>((node, hs) => hs.length === 0 ? node : concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]]) , []) : Tree
>hs .reduce<HTMLHeadingElement[][]>((hss, h) => { const hs = hss.pop()!; return hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]); }, [[]]) .reduce : { (callbackfn: (previousValue: HTMLHeadingElement[], currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => HTMLHeadingElement[]): HTMLHeadingElement[]; (callbackfn: (previousValue: HTMLHeadingElement[], currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => HTMLHeadingElement[], initialValue: HTMLHeadingElement[]): HTMLHeadingElement[]; <U>(callbackfn: (previousValue: U, currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => U, initialValue: U): U; }
>hs .reduce<HTMLHeadingElement[][]>((hss, h) => { const hs = hss.pop()!; return hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]); }, [[]]) : HTMLHeadingElement[][]
>hs .reduce : { (callbackfn: (previousValue: HTMLHeadingElement, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => HTMLHeadingElement): HTMLHeadingElement; (callbackfn: (previousValue: HTMLHeadingElement, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => HTMLHeadingElement, initialValue: HTMLHeadingElement): HTMLHeadingElement; <U>(callbackfn: (previousValue: U, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => U, initialValue: U): U; }
>hs : HTMLHeadingElement[]
.reduce<HTMLHeadingElement[][]>((hss, h) => {
>reduce : { (callbackfn: (previousValue: HTMLHeadingElement, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => HTMLHeadingElement): HTMLHeadingElement; (callbackfn: (previousValue: HTMLHeadingElement, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => HTMLHeadingElement, initialValue: HTMLHeadingElement): HTMLHeadingElement; <U>(callbackfn: (previousValue: U, currentValue: HTMLHeadingElement, currentIndex: number, array: HTMLHeadingElement[]) => U, initialValue: U): U; }
>(hss, h) => { const hs = hss.pop()!; return hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]); } : (hss: HTMLHeadingElement[][], h: HTMLHeadingElement) => any
>hss : HTMLHeadingElement[][]
>h : HTMLHeadingElement
const hs = hss.pop()!;
>hs : HTMLHeadingElement[]
>hss.pop()! : HTMLHeadingElement[]
>hss.pop() : HTMLHeadingElement[] | undefined
>hss.pop : () => HTMLHeadingElement[] | undefined
>hss : HTMLHeadingElement[][]
>pop : () => HTMLHeadingElement[] | undefined
return hs.length === 0 || level(h) > level(hs[0])
>hs.length === 0 || level(h) > level(hs[0]) ? concat(hss, [concat(hs, [h])]) : concat(hss, [hs, [h]]) : any
>hs.length === 0 || level(h) > level(hs[0]) : boolean
>hs.length === 0 : boolean
>hs.length : number
>hs : HTMLHeadingElement[]
>length : number
>0 : 0
>level(h) > level(hs[0]) : boolean
>level(h) : number
>level : (h: HTMLHeadingElement) => number
>h : HTMLHeadingElement
>level(hs[0]) : number
>level : (h: HTMLHeadingElement) => number
>hs[0] : HTMLHeadingElement
>hs : HTMLHeadingElement[]
>0 : 0
? concat(hss, [concat(hs, [h])])
>concat(hss, [concat(hs, [h])]) : any
>concat : any
>hss : HTMLHeadingElement[][]
>[concat(hs, [h])] : any[]
>concat(hs, [h]) : any
>concat : any
>hs : HTMLHeadingElement[]
>[h] : HTMLHeadingElement[]
>h : HTMLHeadingElement
: concat(hss, [hs, [h]]);
>concat(hss, [hs, [h]]) : any
>concat : any
>hss : HTMLHeadingElement[][]
>[hs, [h]] : HTMLHeadingElement[][]
>hs : HTMLHeadingElement[]
>[h] : HTMLHeadingElement[]
>h : HTMLHeadingElement
}, [[]])
>[[]] : never[][]
>[] : never[]
.reduce<Tree>((node, hs) =>
>reduce : { (callbackfn: (previousValue: HTMLHeadingElement[], currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => HTMLHeadingElement[]): HTMLHeadingElement[]; (callbackfn: (previousValue: HTMLHeadingElement[], currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => HTMLHeadingElement[], initialValue: HTMLHeadingElement[]): HTMLHeadingElement[]; <U>(callbackfn: (previousValue: U, currentValue: HTMLHeadingElement[], currentIndex: number, array: HTMLHeadingElement[][]) => U, initialValue: U): U; }
>(node, hs) => hs.length === 0 ? node : concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]]) : (node: Tree, hs: HTMLHeadingElement[]) => any
>node : Tree
>hs : HTMLHeadingElement[]
hs.length === 0
>hs.length === 0 ? node : concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]]) : any
>hs.length === 0 : boolean
>hs.length : number
>hs : HTMLHeadingElement[]
>length : number
>0 : 0
? node
>node : Tree
: concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]])
>concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]]) : any
>concat : any
>node : Tree
>[[hs.shift()!, cons(hs)]] : (HTMLHeadingElement | Tree)[][]
>[hs.shift()!, cons(hs)] : (HTMLHeadingElement | Tree)[]
>hs.shift()! : HTMLHeadingElement
>hs.shift() : HTMLHeadingElement | undefined
>hs.shift : () => HTMLHeadingElement | undefined
>hs : HTMLHeadingElement[]
>shift : () => HTMLHeadingElement | undefined
>cons(hs) : Tree
>cons : (hs: HTMLHeadingElement[]) => Tree
>hs : HTMLHeadingElement[]
, []);
>[] : never[]
}
function level(h: HTMLHeadingElement): number {
>level : (h: HTMLHeadingElement) => number
>h : HTMLHeadingElement
assert(isFinite(+h.tagName[1]));
>assert(isFinite(+h.tagName[1])) : any
>assert : any
>isFinite(+h.tagName[1]) : boolean
>isFinite : (number: number) => boolean
>+h.tagName[1] : number
>h.tagName[1] : string
>h.tagName : string
>h : HTMLHeadingElement
>tagName : string
>1 : 1
return +h.tagName[1];
>+h.tagName[1] : number
>h.tagName[1] : string
>h.tagName : string
>h : HTMLHeadingElement
>tagName : string
>1 : 1
}

View file

@ -80,3 +80,53 @@ type T12 = (T12)[];
type T13 = T13[] | string;
type T14 = T14[] & { x: string };
type T15<X> = X extends string ? T15<X>[] : never;
type ValueOrArray1<T> = T | ValueOrArray1<T>[];
type ValueOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo1<T>(a: ValueOrArray1<T>): T;
declare let ra1: ValueOrArray2<string>;
let x1 = foo1(ra1); // Boom!
type NumberOrArray1<T> = T | ValueOrArray1<T>[];
type NumberOrArray2<T> = T | ValueOrArray2<T>[];
declare function foo2<T>(a: ValueOrArray1<T>): T;
declare let ra2: ValueOrArray2<string>;
let x2 = foo2(ra2); // Boom!
// Repro from #33617 (errors are expected)
type Tree = [HTMLHeadingElement, Tree][];
function parse(node: Tree, index: number[] = []): HTMLUListElement {
return html('ul', node.map(([el, children], i) => {
const idx = [...index, i + 1];
return html('li', [
html('a', { href: `#${el.id}`, rel: 'noopener', 'data-index': idx.join('.') }, el.textContent!),
children.length > 0 ? parse(children, idx) : frag()
]);
}));
}
function cons(hs: HTMLHeadingElement[]): Tree {
return hs
.reduce<HTMLHeadingElement[][]>((hss, h) => {
const hs = hss.pop()!;
return hs.length === 0 || level(h) > level(hs[0])
? concat(hss, [concat(hs, [h])])
: concat(hss, [hs, [h]]);
}, [[]])
.reduce<Tree>((node, hs) =>
hs.length === 0
? node
: concat<Tree[number]>(node, [[hs.shift()!, cons(hs)]])
, []);
}
function level(h: HTMLHeadingElement): number {
assert(isFinite(+h.tagName[1]));
return +h.tagName[1];
}