Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Cache widened types #31586

Merged
merged 2 commits into from May 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/compiler/checker.ts
Expand Up @@ -14679,26 +14679,34 @@ namespace ts {

function getWidenedTypeWithContext(type: Type, context: WideningContext | undefined): Type {
if (getObjectFlags(type) & ObjectFlags.RequiresWidening) {
if (context === undefined && type.widened) {
return type.widened;
}
let result: Type | undefined;
if (type.flags & TypeFlags.Nullable) {
return anyType;
result = anyType;
}
if (isObjectLiteralType(type)) {
return getWidenedTypeOfObjectLiteral(type, context);
else if (isObjectLiteralType(type)) {
result = getWidenedTypeOfObjectLiteral(type, context);
}
if (type.flags & TypeFlags.Union) {
else if (type.flags & TypeFlags.Union) {
const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (<UnionType>type).types);
const widenedTypes = sameMap((<UnionType>type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext));
// Widening an empty object literal transitions from a highly restrictive type to
// a highly inclusive one. For that reason we perform subtype reduction here if the
// union includes empty object types (e.g. reducing {} | string to just {}).
return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
}
else if (type.flags & TypeFlags.Intersection) {
result = getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
else if (isArrayType(type) || isTupleType(type)) {
result = createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
}
if (isArrayType(type) || isTupleType(type)) {
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
if (result && context === undefined) {
type.widened = result;
}
return result || type;
}
return type;
}
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Expand Up @@ -4010,6 +4010,8 @@ namespace ts {
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
/* @internal */
immediateBaseConstraint?: Type; // Immediate base constraint cache
/* @internal */
widened?: Type; // Cached widened form of the type
}

/* @internal */
Expand Down
115 changes: 115 additions & 0 deletions tests/baselines/reference/noImplicitThisBigThis.js
@@ -0,0 +1,115 @@
//// [noImplicitThisBigThis.ts]
// https://github.com/microsoft/TypeScript/issues/29902

function createObj() {
return {
func1() {
return this;
},
func2() {
return this;
},
func3() {
return this;
}
};
}

function createObjNoCrash() {
return {
func1() {
return this;
},
func2() {
return this;
},
func3() {
return this;
},
func4() {
return this;
},
func5() {
return this;
},
func6() {
return this;
},
func7() {
return this;
},
func8() {
return this;
},
func9() {
return this;
}
};
}


//// [noImplicitThisBigThis.js]
// https://github.com/microsoft/TypeScript/issues/29902
function createObj() {
return {
func1: function () {
return this;
},
func2: function () {
return this;
},
func3: function () {
return this;
}
};
}
function createObjNoCrash() {
return {
func1: function () {
return this;
},
func2: function () {
return this;
},
func3: function () {
return this;
},
func4: function () {
return this;
},
func5: function () {
return this;
},
func6: function () {
return this;
},
func7: function () {
return this;
},
func8: function () {
return this;
},
func9: function () {
return this;
}
};
}


//// [noImplicitThisBigThis.d.ts]
declare function createObj(): {
func1(): any;
func2(): any;
func3(): any;
};
declare function createObjNoCrash(): {
func1(): any;
func2(): any;
func3(): any;
func4(): any;
func5(): any;
func6(): any;
func7(): any;
func8(): any;
func9(): any;
};
99 changes: 99 additions & 0 deletions tests/baselines/reference/noImplicitThisBigThis.symbols
@@ -0,0 +1,99 @@
=== tests/cases/compiler/noImplicitThisBigThis.ts ===
// https://github.com/microsoft/TypeScript/issues/29902

function createObj() {
>createObj : Symbol(createObj, Decl(noImplicitThisBigThis.ts, 0, 0))

return {
func1() {
>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 3, 12))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))

},
func2() {
>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 6, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))

},
func3() {
>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 9, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))
}
};
}

function createObjNoCrash() {
>createObjNoCrash : Symbol(createObjNoCrash, Decl(noImplicitThisBigThis.ts, 14, 1))

return {
func1() {
>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 17, 12))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func2() {
>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 20, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func3() {
>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 23, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func4() {
>func4 : Symbol(func4, Decl(noImplicitThisBigThis.ts, 26, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func5() {
>func5 : Symbol(func5, Decl(noImplicitThisBigThis.ts, 29, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func6() {
>func6 : Symbol(func6, Decl(noImplicitThisBigThis.ts, 32, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func7() {
>func7 : Symbol(func7, Decl(noImplicitThisBigThis.ts, 35, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func8() {
>func8 : Symbol(func8, Decl(noImplicitThisBigThis.ts, 38, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))

},
func9() {
>func9 : Symbol(func9, Decl(noImplicitThisBigThis.ts, 41, 10))

return this;
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
}
};
}