From 3f7a9a906b91660afd655976064ea4ac4b1f3294 Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Thu, 27 Dec 2018 13:45:13 -1000
Subject: [PATCH 1/4] Type parameter defaults can only reference previously
 declared type parameters

---
 src/compiler/checker.ts              | 32 ++++++++++++++++++++--------
 src/compiler/diagnosticMessages.json |  4 ++++
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 23c5568f2e5f4..c63a5dce46f80 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -7928,22 +7928,17 @@ namespace ts {
             const numTypeArguments = length(typeArguments);
             if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) {
                 const result = typeArguments ? typeArguments.slice() : [];
-
-                // Map an unsatisfied type parameter with a default type.
-                // If a type parameter does not have a default type, or if the default type
-                // is a forward reference, the empty object type is used.
-                const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
-                const circularityMapper = createTypeMapper(typeParameters!, map(typeParameters!, () => baseDefaultType));
+                // Map invalid forward references in default types to the error type
                 for (let i = numTypeArguments; i < numTypeParameters; i++) {
-                    result[i] = instantiateType(getConstraintFromTypeParameter(typeParameters![i]) || baseDefaultType, circularityMapper);
+                    result[i] = errorType;
                 }
+                const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
                 for (let i = numTypeArguments; i < numTypeParameters; i++) {
-                    const mapper = createTypeMapper(typeParameters!, result);
                     let defaultType = getDefaultFromTypeParameter(typeParameters![i]);
                     if (isJavaScriptImplicitAny && defaultType && isTypeIdenticalTo(defaultType, emptyObjectType)) {
                         defaultType = anyType;
                     }
-                    result[i] = defaultType ? instantiateType(defaultType, mapper) : baseDefaultType;
+                    result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType;
                 }
                 result.length = typeParameters!.length;
                 return result;
@@ -26465,6 +26460,7 @@ namespace ts {
                     if (produceDiagnostics) {
                         if (node.default) {
                             seenDefault = true;
+                            checkTypeParametersNotReferenced(node.default, typeParameterDeclarations, i);
                         }
                         else if (seenDefault) {
                             error(node, Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters);
@@ -26479,6 +26475,24 @@ namespace ts {
             }
         }
 
+        /** Check that type parameter defaults only reference previously declared type parameters */
+        function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: ReadonlyArray<TypeParameterDeclaration>, index: number) {
+            visit(root);
+            function visit(node: Node) {
+                if (node.kind === SyntaxKind.TypeReference) {
+                    const type = getTypeFromTypeReference(<TypeReferenceNode>node);
+                    if (type.flags & TypeFlags.TypeParameter) {
+                        for (let i = index; i < typeParameters.length; i++) {
+                            if (type.symbol === getSymbolOfNode(typeParameters[i])) {
+                                error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters);
+                            }
+                        }
+                    }
+                }
+                forEachChild(node, visit);
+            }
+        }
+
         /** Check that type parameter lists are identical across multiple declarations */
         function checkTypeParameterListsIdentical(symbol: Symbol) {
             if (symbol.declarations.length === 1) {
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index b0dfb85ce6d25..57f4c4c561117 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2537,6 +2537,10 @@
         "category": "Error",
         "code": 2743
     },
+    "Type parameter defaults can only reference previously declared type parameters.": {
+        "category": "Error",
+        "code": 2744
+    },
 
     "Import declaration '{0}' is using private name '{1}'.": {
         "category": "Error",

From 5e1d490e589d8f06c1dd9e9bd079db0c50bddc28 Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Thu, 27 Dec 2018 14:00:00 -1000
Subject: [PATCH 2/4] Accept new baselines

---
 .../reference/genericDefaults.errors.txt      | 528 ++++++++++++++++++
 tests/baselines/reference/genericDefaults.js  |   4 +-
 .../baselines/reference/genericDefaults.types |  54 +-
 .../subclassThisTypeAssignable.errors.txt     |  34 ++
 .../subclassThisTypeAssignable.types          |   4 +-
 ...UsesConstraintOnCircularDefault.errors.txt |  15 +-
 ...faultUsesConstraintOnCircularDefault.types |   4 +-
 7 files changed, 602 insertions(+), 41 deletions(-)
 create mode 100644 tests/baselines/reference/genericDefaults.errors.txt
 create mode 100644 tests/baselines/reference/subclassThisTypeAssignable.errors.txt

diff --git a/tests/baselines/reference/genericDefaults.errors.txt b/tests/baselines/reference/genericDefaults.errors.txt
new file mode 100644
index 0000000000000..0c7d9ccb21d63
--- /dev/null
+++ b/tests/baselines/reference/genericDefaults.errors.txt
@@ -0,0 +1,528 @@
+tests/cases/compiler/genericDefaults.ts(44,26): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(237,26): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(254,29): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(277,26): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(292,29): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(314,26): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(332,29): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(357,26): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(375,29): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(423,19): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/genericDefaults.ts(427,19): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+
+
+==== tests/cases/compiler/genericDefaults.ts (11 errors) ====
+    interface A { a: number; }
+    interface B { b: number; }
+    interface C { c: number; }
+    interface D { d: number; }
+    interface AB { a: number; b: number; }
+    interface BC { b: number; c: number; }
+    
+    declare const a: A;
+    declare const b: B;
+    declare const c: C;
+    declare const d: D;
+    declare const ab: AB;
+    declare const bc: BC;
+    declare const x: any;
+    
+    // function without type parameters
+    declare function f00(a?: A): A;
+    // no inference
+    f00();
+    f00(a);
+    
+    // function with a type parameter without a default
+    declare function f01<T>(a?: T): T;
+    // inference
+    f01();
+    f01(a);
+    // no inference, fully supplied
+    f01<A>();
+    f01<A>(a);
+    
+    // function with a type paramter with a default
+    declare function f02<T = A>(a?: T): T;
+    // inference
+    f02();
+    f02(a);
+    f02(b);
+    // no inference, fully supplied
+    f02<A>();
+    f02<A>(a);
+    f02<B>();
+    f02<B>(b);
+    
+    // function with a type parameter with a default that refers to itself
+    declare function f03<T = T>(a?: T): T;
+                             ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f03();
+    f03(a);
+    f03(b);
+    // no inference, fully supplied
+    f03<A>();
+    f03<A>(a);
+    f03<B>();
+    f03<B>(b);
+    
+    // function with a type paramter without a default and a type parameter with a default
+    declare function f04<T, U = B>(a?: T, b?: U): [T, U];
+    // inference
+    f04();
+    f04(a);
+    f04(a, b);
+    f04(a, c);
+    // no inference, partially supplied
+    f04<A>();
+    f04<A>(a);
+    f04<A>(a, b);
+    // no inference, fully supplied
+    f04<A, B>();
+    f04<A, B>(a);
+    f04<A, B>(a, b);
+    f04<A, C>();
+    f04<A, C>(a);
+    f04<A, C>(a, c);
+    
+    // function with a type parameter without a default and a type parameter with a default that refers to an earlier type parameter
+    declare function f05<T, U = T>(a?: T, b?: U): [T, U];
+    // inference
+    f05();
+    f05(a);
+    f05(a, a);
+    f05(a, b);
+    // no inference, partially supplied
+    f05<A>();
+    f05<A>(a);
+    f05<A>(a, a);
+    // no inference, fully supplied
+    f05<A, B>();
+    f05<A, B>(a);
+    f05<A, B>(a, b);
+    
+    // function with a type parameter with a default that refers to an earlier type parameter with a default
+    declare function f06<T = A, U = T>(a?: T, b?: U): [T, U];
+    // inference
+    f06();
+    f06(a);
+    f06(a, a);
+    f06(a, b);
+    f06(b, a);
+    f06(b, b);
+    // no inference, partially supplied
+    f06<A>();
+    f06<A>(a);
+    f06<A>(a, a);
+    f06<B>();
+    f06<B>(b);
+    f06<B>(b, b);
+    // no inference, fully supplied
+    f06<A, B>();
+    f06<A, B>(a);
+    f06<A, B>(a, b);
+    f06<B, C>();
+    f06<B, C>(b);
+    f06<B, C>(b, c);
+    
+    // function with a type parameter without a default and a type parameter with a default that refers to an earlier type parameter with a default
+    declare function f07<T, U = B, V = U>(a?: T, b?: U, c?: V): [T, U, V];
+    // inference
+    f07();
+    f07(a, b);
+    f07(a, c);
+    f07(a, b, b);
+    f07(a, b, c);
+    f07(a, c, b);
+    f07(a, c, c);
+    // no inference, partially supplied
+    f07<A>();
+    f07<A>(a);
+    f07<A>(a, b);
+    f07<A>(a, b, b);
+    f07<A, B>();
+    f07<A, B>(a);
+    f07<A, B>(a, b);
+    f07<A, B>(a, b, b);
+    f07<A, C>();
+    f07<A, C>(a);
+    f07<A, C>(a, c);
+    f07<A, C>(a, c, c);
+    // no inference, fully supplied
+    f07<A, B, C>();
+    f07<A, B, C>(a);
+    f07<A, B, C>(a, b);
+    f07<A, B, C>(a, b, c);
+    f07<A, C, A>();
+    f07<A, C, A>(a);
+    f07<A, C, D>(a, c);
+    f07<A, C, D>(a, c, d);
+    
+    // function with a type parameter with a default that refers to an earlier type parameter with a constraint
+    declare function f08<T extends A, U = T>(a?: T, b?: U): [T, U];
+    // inference
+    f08();
+    f08(a);
+    f08(a, a);
+    f08(a, b);
+    // no inference, partially supplied
+    f08<A>();
+    f08<A>(a);
+    f08<A>(a, a);
+    // no inference, fully supplied
+    f08<A, B>();
+    f08<A, B>(a);
+    f08<A, B>(a, b);
+    
+    // function with a type parameter with a constraint and a default that refers to an earlier type parameter
+    declare function f09<T, U extends T = T>(a?: T, b?: U): [T, U];
+    // inference
+    f09();
+    f09(a);
+    f09(a, a);
+    f09(a, ab);
+    // no inference, partially supplied
+    f09<A>();
+    f09<A>(a);
+    f09<A>(a, a);
+    f09<A>(a, ab);
+    // no inference, fully supplied
+    f09<A, AB>();
+    f09<A, AB>(a);
+    f09<A, AB>(a, ab);
+    
+    // function with a type parameter with a constraint and a default that refers to an earlier type parameter with a constraint
+    declare function f10<T extends A, U extends T = T>(a?: T, b?: U): [T, U];
+    // inference
+    f10();
+    f10(a);
+    f10(a, a);
+    f10(a, ab);
+    // no inference, partially supplied
+    f10<A>();
+    f10<A>(a);
+    f10<A>(a, a);
+    f10<A>(a, ab);
+    // no inference, fully supplied
+    f10<A, A>();
+    f10<A, A>(a);
+    f10<A, A>(a, a);
+    f10<A, A>(a, ab);
+    f10<A, AB>();
+    f10<A, AB>(a);
+    f10<A, AB>(a, ab);
+    
+    // function with a type parameter with a default that refers to an earier type parameter in a union
+    declare function f11<T, U = T | B>(a?: T, b?: U): [T, U];
+    // inference
+    f11();
+    f11(a);
+    f11(a, a);
+    f11(a, b);
+    f11(a, c);
+    // no inference, partially supplied
+    f11<A>();
+    f11<A>(a);
+    f11<A>(a, a);
+    f11<A>(a, b);
+    // no inference, fully supplied
+    f11<A, C>();
+    f11<A, C>(a);
+    f11<A, C>(a, c);
+    
+    // function with a type parameter with a default that refers to an earlier type parameter in an intersection
+    declare function f12<T, U = T & B>(a?: T, b?: U): [T, U];
+    // inference
+    f12();
+    f12(a);
+    f12(a, a);
+    f12(a, b);
+    f12(a, c);
+    // no inference, partially supplied
+    f12<A>();
+    f12<A>(a);
+    f12<A>(a, ab);
+    // no inference, fully supplied
+    f12<A, C>();
+    f12<A, C>(a);
+    f12<A, C>(a, c);
+    
+    // function with a type parameter with a default that refers to a later type parameter with a default
+    declare function f13<T = U, U = B>(a?: T, b?: U): [T, U];
+                             ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f13();
+    f13(a);
+    f13(a, b);
+    f13(a, c);
+    // no inference, partially supplied
+    f13<A>();
+    f13<A>(a);
+    f13<A>(a, b);
+    // no inference, fully supplied
+    f13<A, C>();
+    f13<A, C>(a);
+    f13<A, C>(a, c);
+    f13<A, C>(a, c);
+    
+    // function with a type parameter without a default and a type parameter with a default that refers to a later type parameter with a default
+    declare function f14<T, U = V, V = C>(a?: T, b?: U, c?: V): [T, U, V];
+                                ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f14();
+    f14(a);
+    f14(a, b);
+    f14(a, b, c);
+    f14(a, b, d);
+    // no inference, partially supplied
+    f14<A>();
+    f14<A>(a);
+    f14<A>(a, b);
+    f14<A>(a, b, c);
+    f14<A, B>();
+    f14<A, B>(a);
+    f14<A, B>(a, b);
+    f14<A, B>(a, b, c);
+    // no inference fully supplied
+    f14<A, B, D>();
+    f14<A, B, D>(a);
+    f14<A, B, D>(a, b);
+    f14<A, B, D>(a, b, d);
+    
+    // function with two type parameters with defaults that mutually refer to each other
+    declare function f15<T = U, U = T>(a?: T, b?: U): [T, U];
+                             ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f15();
+    f15(a);
+    f15(a, b);
+    // no inference, partially supplied
+    f15<A>();
+    f15<A>(a);
+    f15<A>(a, a);
+    // no inference, fully supplied
+    f15<A, B>();
+    f15<A, B>(a);
+    f15<A, B>(a, b);
+    
+    // function with a type parameter without a default and two type parameters with defaults that mutually refer to each other
+    declare function f16<T, U = V, V = U>(a?: T, b?: U, c?: V): [T, U, V];
+                                ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // no inference
+    f16();
+    f16(a);
+    f16(a, b);
+    f16(a, b, b);
+    // no inference, partially supplied
+    f16<A>();
+    f16<A>(a);
+    f16<A>(a, b);
+    f16<A>(a, b, b);
+    f16<A, B>();
+    f16<A, B>(a);
+    f16<A, B>(a, b);
+    f16<A, B>(a, b, b);
+    // no inference, fully supplied
+    f16<A, B, D>();
+    f16<A, B, D>(a);
+    f16<A, B, D>(a, b);
+    f16<A, B, D>(a, b, d);
+    
+    // function with a type parameter with a default that refers to a later type parameter with a default that refers to an earlier type parameter in a union
+    declare function f17<T = U, U = T | B>(a?: T, b?: U): [T, U];
+                             ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f17();
+    f17(a);
+    f17(a, a);
+    f17(a, b);
+    f17(a, c);
+    // no inference, partially supplied
+    f17<A>();
+    f17<A>(a);
+    f17<A>(a, a);
+    f17<A>(a, b);
+    // no inference, fully supplied
+    f17<A, C>();
+    f17<A, C>(a);
+    f17<A, C>(a, c);
+    
+    // function with a type parameter without a default and a type parameter with a default that refers to a later type parameter with a default that refers to an earlier type parameter in a union
+    declare function f18<T, U = V, V = U | C>(a?: T, b?: U, c?: V): [T, U, V];
+                                ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f18();
+    f18(a);
+    f18(a, b);
+    f18(a, b, b);
+    f18(a, b, c);
+    // no inference, partially supplied
+    f18<A>();
+    f18<A>(a);
+    f18<A>(a, b);
+    f18<A>(a, b, b);
+    f18<A>(a, b, c);
+    f18<A, B>();
+    f18<A, B>(a);
+    f18<A, B>(a, b);
+    f18<A, B>(a, b, b);
+    f18<A, B>(a, b, c);
+    // no inference, fully supplied
+    f18<A, B, D>();
+    f18<A, B, D>(a);
+    f18<A, B, D>(a, b);
+    f18<A, B, D>(a, b, d);
+    
+    // function with a type parameter with a default that refers to a later type parameter with a default that refers to an earlier type parameter in an intersection
+    declare function f19<T = U, U = T & B>(a?: T, b?: U): [T, U];
+                             ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f19();
+    f19(a);
+    f19(a, a);
+    f19(a, b);
+    f19(a, ab);
+    f19(a, c);
+    // no inference, partially supplied
+    f19<A>();
+    f19<A>(a);
+    f19<A>(a, ab);
+    // no inference, fully supplied
+    f19<A, C>();
+    f19<A, C>(a);
+    f19<A, C>(a, c);
+    
+    // function with a type parameter without a default and a type parameter with a default that refers to a later type parameter with a default that refers to an earlier type parameter in an intersection
+    declare function f20<T, U = V, V = U & C>(a?: T, b?: U, c?: V): [T, U, V];
+                                ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    // inference
+    f20();
+    f20(a);
+    f20(a, b);
+    f20(a, b, c);
+    // no inference, partially supplied
+    f20<A>();
+    f20<A>(a);
+    f20<A>(a, b);
+    f20<A>(a, b, bc);
+    f20<A, B>();
+    f20<A, B>(a);
+    f20<A, B>(a, b);
+    f20<A, B>(a, b, bc);
+    // no inference, fully supplied
+    f20<A, B, D>();
+    f20<A, B, D>(a);
+    f20<A, B, D>(a, b);
+    f20<A, B, D>(a, b, d);
+    
+    interface i00<T = number> { a: T; }
+    const i00c00 = (<i00>x).a;
+    const i00c01 = (<i00<number>>x).a;
+    
+    interface i01<T, U = T> { a: [T, U]; }
+    const i01c00 = (<i01<number>>x).a;
+    const i01c01 = (<i01<number, string>>x).a;
+    
+    interface i02<T extends number, U = T> { a: [T, U]; }
+    const i02c00 = (<i02<number>>x).a;
+    const i02c01 = (<i02<1>>x).a;
+    const i02c02 = (<i02<number, number>>x).a;
+    const i02c03 = (<i02<1, number>>x).a;
+    const i02c04 = (<i02<number, 1>>x).a;
+    
+    interface i03<T extends number, U extends T = T> { a: [T, U]; }
+    const i03c00 = (<i03<number>>x).a;
+    const i03c01 = (<i03<1>>x).a;
+    const i03c02 = (<i03<number, number>>x).a;
+    const i03c03 = (<i03<1, 1>>x).a;
+    const i03c04 = (<i03<number, 1>>x).a;
+    
+    interface i04 {}
+    interface i04<T> {}
+    interface i04<T = number> {}
+    interface i04<T = number, U = string> {}
+    
+    interface i05<T = T> { a: T; }
+                      ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    const i05c00 = (<i05>x).a;
+    const i05c01 = (<i05<number>>x).a;
+    
+    interface i06<T = U, U = T> { a: [T, U]; }
+                      ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    const i06c00 = (<i06>x).a;
+    const i06c01 = (<i06<number>>x).a;
+    const i06c02 = (<i06<number, string>>x).a;
+    
+    interface i07 { a: A; }
+    interface i07<A = number> { b: A; }
+    const i07c00 = (<i07>x).a;
+    const i07c01 = (<i07>x).b;
+    const i07c02 = (<i07<B>>x).a;
+    const i07c03 = (<i07<B>>x).b;
+    
+    interface Base01<T> { a: T; }
+    interface Base01Constructor { new <T = number>(a?: T): Base01<T>; }
+    
+    declare const Base01: Base01Constructor;
+    const Base01c00 = new Base01();
+    const Base01c01 = new Base01(1);
+    const Base01c02 = new Base01<number>();
+    const Base01c03 = new Base01<number>(1);
+    
+    declare class Derived01<T> extends Base01<T> { }
+    const Derived01c00 = new Derived01();
+    const Derived01c01 = new Derived01(1);
+    const Derived01c02 = new Derived01<number>();
+    const Derived01c03 = new Derived01<number>(1);
+    
+    declare class Derived02<T = string> extends Base01<T> { }
+    const Derived02c00 = new Derived02();
+    const Derived02c01 = new Derived02(1);
+    const Derived02c02 = new Derived02<number>();
+    const Derived02c03 = new Derived02<number>(1);
+    
+    // https://github.com/Microsoft/TypeScript/issues/16211
+    interface Base02 {}
+    interface Base02Constructor { new <T = A>(a: T): Base02 & T; }
+    declare const Base02: Base02Constructor;
+    declare class Derived03 extends Base02 {}
+    const Derived03c00 = new Derived03(ab);
+    const Derived03c01 = Derived03c00.a;
+    type DerivedProps = keyof Derived03;
+    
+    type t00<T = number> = { a: T; }
+    const t00c00 = (<t00>x).a;
+    const t00c01 = (<t00<number>>x).a;
+    
+    type t01<T, U = T> = { a: [T, U]; }
+    const t01c00 = (<t01<number>>x).a;
+    const t01c01 = (<t01<number, string>>x).a;
+    
+    type t02<T extends number, U = T> = { a: [T, U]; }
+    const t02c00 = (<t02<number>>x).a;
+    const t02c01 = (<t02<1>>x).a;
+    const t02c02 = (<t02<number, number>>x).a;
+    const t02c03 = (<t02<1, number>>x).a;
+    const t02c04 = (<t02<number, 1>>x).a;
+    
+    type t03<T extends number, U extends T = T> = { a: [T, U]; }
+    const t03c00 = (<t03<number>>x).a;
+    const t03c01 = (<t03<1>>x).a;
+    const t03c02 = (<t03<number, number>>x).a;
+    const t03c03 = (<t03<1, 1>>x).a;
+    const t03c04 = (<t03<number, 1>>x).a;
+    
+    // https://github.com/Microsoft/TypeScript/issues/16221
+    interface SelfReference<T = SelfReference<string>> {}
\ No newline at end of file
diff --git a/tests/baselines/reference/genericDefaults.js b/tests/baselines/reference/genericDefaults.js
index be6b76ea43cdb..4cd1127724f11 100644
--- a/tests/baselines/reference/genericDefaults.js
+++ b/tests/baselines/reference/genericDefaults.js
@@ -949,12 +949,12 @@ interface i04<T = number, U = string> {
 interface i05<T = T> {
     a: T;
 }
-declare const i05c00: {};
+declare const i05c00: any;
 declare const i05c01: number;
 interface i06<T = U, U = T> {
     a: [T, U];
 }
-declare const i06c00: [{}, {}];
+declare const i06c00: [any, any];
 declare const i06c01: [number, number];
 declare const i06c02: [number, string];
 interface i07 {
diff --git a/tests/baselines/reference/genericDefaults.types b/tests/baselines/reference/genericDefaults.types
index 839994cc96532..c439d96a08b44 100644
--- a/tests/baselines/reference/genericDefaults.types
+++ b/tests/baselines/reference/genericDefaults.types
@@ -1015,22 +1015,22 @@ f14(a, b, d);
 
 // no inference, partially supplied
 f14<A>();
->f14<A>() : [A, {}, C]
+>f14<A>() : [A, any, C]
 >f14 : <T, U = V, V = C>(a?: T, b?: U, c?: V) => [T, U, V]
 
 f14<A>(a);
->f14<A>(a) : [A, {}, C]
+>f14<A>(a) : [A, any, C]
 >f14 : <T, U = V, V = C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 
 f14<A>(a, b);
->f14<A>(a, b) : [A, {}, C]
+>f14<A>(a, b) : [A, any, C]
 >f14 : <T, U = V, V = C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
 
 f14<A>(a, b, c);
->f14<A>(a, b, c) : [A, {}, C]
+>f14<A>(a, b, c) : [A, any, C]
 >f14 : <T, U = V, V = C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
@@ -1167,22 +1167,22 @@ f16(a, b, b);
 
 // no inference, partially supplied
 f16<A>();
->f16<A>() : [A, {}, {}]
+>f16<A>() : [A, any, any]
 >f16 : <T, U = V, V = U>(a?: T, b?: U, c?: V) => [T, U, V]
 
 f16<A>(a);
->f16<A>(a) : [A, {}, {}]
+>f16<A>(a) : [A, any, any]
 >f16 : <T, U = V, V = U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 
 f16<A>(a, b);
->f16<A>(a, b) : [A, {}, {}]
+>f16<A>(a, b) : [A, any, any]
 >f16 : <T, U = V, V = U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
 
 f16<A>(a, b, b);
->f16<A>(a, b, b) : [A, {}, {}]
+>f16<A>(a, b, b) : [A, any, any]
 >f16 : <T, U = V, V = U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
@@ -1344,29 +1344,29 @@ f18(a, b, c);
 
 // no inference, partially supplied
 f18<A>();
->f18<A>() : [A, {}, {} | C]
+>f18<A>() : [A, any, any]
 >f18 : <T, U = V, V = C | U>(a?: T, b?: U, c?: V) => [T, U, V]
 
 f18<A>(a);
->f18<A>(a) : [A, {}, {} | C]
+>f18<A>(a) : [A, any, any]
 >f18 : <T, U = V, V = C | U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 
 f18<A>(a, b);
->f18<A>(a, b) : [A, {}, {} | C]
+>f18<A>(a, b) : [A, any, any]
 >f18 : <T, U = V, V = C | U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
 
 f18<A>(a, b, b);
->f18<A>(a, b, b) : [A, {}, {} | C]
+>f18<A>(a, b, b) : [A, any, any]
 >f18 : <T, U = V, V = C | U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
 >b : B
 
 f18<A>(a, b, c);
->f18<A>(a, b, c) : [A, {}, {} | C]
+>f18<A>(a, b, c) : [A, any, any]
 >f18 : <T, U = V, V = C | U>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
@@ -1528,22 +1528,22 @@ f20(a, b, c);
 
 // no inference, partially supplied
 f20<A>();
->f20<A>() : [A, {}, C]
+>f20<A>() : [A, any, any]
 >f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
 
 f20<A>(a);
->f20<A>(a) : [A, {}, C]
+>f20<A>(a) : [A, any, any]
 >f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 
 f20<A>(a, b);
->f20<A>(a, b) : [A, {}, C]
+>f20<A>(a, b) : [A, any, any]
 >f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
 
 f20<A>(a, b, bc);
->f20<A>(a, b, bc) : [A, {}, C]
+>f20<A>(a, b, bc) : [A, any, any]
 >f20 : <T, U = V, V = U & C>(a?: T, b?: U, c?: V) => [T, U, V]
 >a : A
 >b : B
@@ -1727,12 +1727,12 @@ interface i05<T = T> { a: T; }
 >a : T
 
 const i05c00 = (<i05>x).a;
->i05c00 : {}
->(<i05>x).a : {}
->(<i05>x) : i05<{}>
-><i05>x : i05<{}>
+>i05c00 : any
+>(<i05>x).a : any
+>(<i05>x) : i05<any>
+><i05>x : i05<any>
 >x : any
->a : {}
+>a : any
 
 const i05c01 = (<i05<number>>x).a;
 >i05c01 : number
@@ -1746,12 +1746,12 @@ interface i06<T = U, U = T> { a: [T, U]; }
 >a : [T, U]
 
 const i06c00 = (<i06>x).a;
->i06c00 : [{}, {}]
->(<i06>x).a : [{}, {}]
->(<i06>x) : i06<{}, {}>
-><i06>x : i06<{}, {}>
+>i06c00 : [any, any]
+>(<i06>x).a : [any, any]
+>(<i06>x) : i06<any, any>
+><i06>x : i06<any, any>
 >x : any
->a : [{}, {}]
+>a : [any, any]
 
 const i06c01 = (<i06<number>>x).a;
 >i06c01 : [number, number]
diff --git a/tests/baselines/reference/subclassThisTypeAssignable.errors.txt b/tests/baselines/reference/subclassThisTypeAssignable.errors.txt
new file mode 100644
index 0000000000000..f1d661695d1e3
--- /dev/null
+++ b/tests/baselines/reference/subclassThisTypeAssignable.errors.txt
@@ -0,0 +1,34 @@
+tests/cases/compiler/tile1.ts(6,81): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+
+
+==== tests/cases/compiler/tile1.ts (1 errors) ====
+    interface Lifecycle<Attrs, State> {
+    	oninit?(vnode: Vnode<Attrs, State>): number;
+    	[_: number]: any;
+    }
+    
+    interface Vnode<Attrs, State extends Lifecycle<Attrs, State> = Lifecycle<Attrs, State>> {
+                                                                                    ~~~~~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
+    	tag: Component<Attrs, State>;
+    }
+    
+    interface Component<Attrs, State> {
+    	view(this: State, vnode: Vnode<Attrs, State>): number;
+    }
+    
+    interface ClassComponent<A> extends Lifecycle<A, ClassComponent<A>> {
+    	oninit?(vnode: Vnode<A, this>): number;
+    	view(vnode: Vnode<A, this>): number;
+    }
+    
+    interface MyAttrs { id: number }
+    class C implements ClassComponent<MyAttrs> {
+    	view(v: Vnode<MyAttrs>) { return 0; }
+    }
+    
+    const test8: ClassComponent<any> = new C();
+==== tests/cases/compiler/file1.js (0 errors) ====
+    /** @type {ClassComponent<any>} */
+    const test9 = new C();
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/subclassThisTypeAssignable.types b/tests/baselines/reference/subclassThisTypeAssignable.types
index 711b0056277f8..9608613f1ffb1 100644
--- a/tests/baselines/reference/subclassThisTypeAssignable.types
+++ b/tests/baselines/reference/subclassThisTypeAssignable.types
@@ -37,8 +37,8 @@ class C implements ClassComponent<MyAttrs> {
 >C : C
 
 	view(v: Vnode<MyAttrs>) { return 0; }
->view : (v: Vnode<MyAttrs, Lifecycle<MyAttrs, Lifecycle<{}, {}>>>) => number
->v : Vnode<MyAttrs, Lifecycle<MyAttrs, Lifecycle<{}, {}>>>
+>view : (v: Vnode<MyAttrs, Lifecycle<MyAttrs, any>>) => number
+>v : Vnode<MyAttrs, Lifecycle<MyAttrs, any>>
 >0 : 0
 }
 
diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
index 71e3ef046277a..a886b48d5a2e1 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
@@ -1,18 +1,17 @@
-tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(3,18): error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<string>'.
-  Object literal may only specify known properties, and 'foo' does not exist in type 'Test<string>'.
-tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(5,19): error TS2322: Type '{}' is not assignable to type 'string'.
+tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(1,30): error TS2744: Type parameter defaults can only reference previously declared type parameters.
+tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(3,18): error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<any>'.
+  Object literal may only specify known properties, and 'foo' does not exist in type 'Test<any>'.
 
 
 ==== tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts (2 errors) ====
     type Test<T extends string = T> = { value: T };
+                                 ~
+!!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
     
     let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
                      ~~~~~~~~~~
-!!! error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<string>'.
-!!! error TS2322:   Object literal may only specify known properties, and 'foo' does not exist in type 'Test<string>'.
+!!! error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<any>'.
+!!! error TS2322:   Object literal may only specify known properties, and 'foo' does not exist in type 'Test<any>'.
     
     let zzy: Test = { value: {} };  // should error
-                      ~~~~~
-!!! error TS2322: Type '{}' is not assignable to type 'string'.
-!!! related TS6500 tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts:1:37: The expected type comes from property 'value' which is declared here on type 'Test<string>'
     
\ No newline at end of file
diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
index 7c0d469da4619..46477c7ffb363 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
@@ -4,13 +4,13 @@ type Test<T extends string = T> = { value: T };
 >value : T
 
 let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
->zz : Test<string>
+>zz : Test<any>
 >{ foo: "abc" } : { foo: string; }
 >foo : string
 >"abc" : "abc"
 
 let zzy: Test = { value: {} };  // should error
->zzy : Test<string>
+>zzy : Test<any>
 >{ value: {} } : { value: {}; }
 >value : {}
 >{} : {}

From a400a8afecca46517e728ec0fba672372248280c Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Thu, 27 Dec 2018 14:05:14 -1000
Subject: [PATCH 3/4] Add regression test

---
 ...peArgumentDefaultUsesConstraintOnCircularDefault.ts | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts b/tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts
index b8361ea571496..ca5a270f6e78a 100644
--- a/tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts
+++ b/tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts
@@ -1,5 +1,11 @@
-type Test<T extends string = T> = { value: T };
+type Test<T extends string = T> = { value: T };  // Error
 
 let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
 
-let zzy: Test = { value: {} };  // should error
+let zzy: Test = { value: {} };
+
+// Simplified repro from #28873
+
+class C1<T extends C1 = any> {}
+
+class C2<T extends C2<any> = any> {}

From 8a72a19b7ae9fd0429dd837df9b7d2eeb550926a Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Thu, 27 Dec 2018 14:05:24 -1000
Subject: [PATCH 4/4] Accept new baselines

---
 ...UsesConstraintOnCircularDefault.errors.txt | 10 ++++++--
 ...tDefaultUsesConstraintOnCircularDefault.js | 23 ++++++++++++++++---
 ...ultUsesConstraintOnCircularDefault.symbols | 16 +++++++++++--
 ...faultUsesConstraintOnCircularDefault.types | 12 ++++++++--
 4 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
index a886b48d5a2e1..756c1f9da3eba 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.errors.txt
@@ -4,7 +4,7 @@ tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(3,18)
 
 
 ==== tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts (2 errors) ====
-    type Test<T extends string = T> = { value: T };
+    type Test<T extends string = T> = { value: T };  // Error
                                  ~
 !!! error TS2744: Type parameter defaults can only reference previously declared type parameters.
     
@@ -13,5 +13,11 @@ tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts(3,18)
 !!! error TS2322: Type '{ foo: string; }' is not assignable to type 'Test<any>'.
 !!! error TS2322:   Object literal may only specify known properties, and 'foo' does not exist in type 'Test<any>'.
     
-    let zzy: Test = { value: {} };  // should error
+    let zzy: Test = { value: {} };
+    
+    // Simplified repro from #28873
+    
+    class C1<T extends C1 = any> {}
+    
+    class C2<T extends C2<any> = any> {}
     
\ No newline at end of file
diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.js b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.js
index 296a0063fe270..a50e7cab397b4 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.js
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.js
@@ -1,11 +1,28 @@
 //// [typeArgumentDefaultUsesConstraintOnCircularDefault.ts]
-type Test<T extends string = T> = { value: T };
+type Test<T extends string = T> = { value: T };  // Error
 
 let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
 
-let zzy: Test = { value: {} };  // should error
+let zzy: Test = { value: {} };
+
+// Simplified repro from #28873
+
+class C1<T extends C1 = any> {}
+
+class C2<T extends C2<any> = any> {}
 
 
 //// [typeArgumentDefaultUsesConstraintOnCircularDefault.js]
 var zz = { foo: "abc" }; // should error on comparison with Test<string>
-var zzy = { value: {} }; // should error
+var zzy = { value: {} };
+// Simplified repro from #28873
+var C1 = /** @class */ (function () {
+    function C1() {
+    }
+    return C1;
+}());
+var C2 = /** @class */ (function () {
+    function C2() {
+    }
+    return C2;
+}());
diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.symbols b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.symbols
index 2181e34188964..4c227899de9f1 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.symbols
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.symbols
@@ -1,5 +1,5 @@
 === tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts ===
-type Test<T extends string = T> = { value: T };
+type Test<T extends string = T> = { value: T };  // Error
 >Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
 >T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 10))
 >T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 10))
@@ -11,8 +11,20 @@ let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
 >Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
 >foo : Symbol(foo, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 2, 16))
 
-let zzy: Test = { value: {} };  // should error
+let zzy: Test = { value: {} };
 >zzy : Symbol(zzy, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 3))
 >Test : Symbol(Test, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 0, 0))
 >value : Symbol(value, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 17))
 
+// Simplified repro from #28873
+
+class C1<T extends C1 = any> {}
+>C1 : Symbol(C1, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 30))
+>T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 8, 9))
+>C1 : Symbol(C1, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 4, 30))
+
+class C2<T extends C2<any> = any> {}
+>C2 : Symbol(C2, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 8, 31))
+>T : Symbol(T, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 10, 9))
+>C2 : Symbol(C2, Decl(typeArgumentDefaultUsesConstraintOnCircularDefault.ts, 8, 31))
+
diff --git a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
index 46477c7ffb363..91078dad88432 100644
--- a/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
+++ b/tests/baselines/reference/typeArgumentDefaultUsesConstraintOnCircularDefault.types
@@ -1,5 +1,5 @@
 === tests/cases/compiler/typeArgumentDefaultUsesConstraintOnCircularDefault.ts ===
-type Test<T extends string = T> = { value: T };
+type Test<T extends string = T> = { value: T };  // Error
 >Test : Test<T>
 >value : T
 
@@ -9,9 +9,17 @@ let zz: Test = { foo: "abc" };  // should error on comparison with Test<string>
 >foo : string
 >"abc" : "abc"
 
-let zzy: Test = { value: {} };  // should error
+let zzy: Test = { value: {} };
 >zzy : Test<any>
 >{ value: {} } : { value: {}; }
 >value : {}
 >{} : {}
 
+// Simplified repro from #28873
+
+class C1<T extends C1 = any> {}
+>C1 : C1<T>
+
+class C2<T extends C2<any> = any> {}
+>C2 : C2<T>
+