Skip to content

Commit 11aecee

Browse files
committed
Switch to assignability check and fix compiler bugs found by check
1 parent cd0d3ba commit 11aecee

File tree

9 files changed

+81
-45
lines changed

9 files changed

+81
-45
lines changed

src/compiler/checker.ts

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,15 +1966,12 @@ namespace ts {
19661966
}
19671967

19681968
return _displayBuilder || (_displayBuilder = {
1969-
symbolToString: symbolToString,
1970-
typeToString: typeToString,
19711969
buildSymbolDisplay: buildSymbolDisplay,
19721970
buildTypeDisplay: buildTypeDisplay,
19731971
buildTypeParameterDisplay: buildTypeParameterDisplay,
19741972
buildParameterDisplay: buildParameterDisplay,
19751973
buildDisplayForParametersAndDelimiters: buildDisplayForParametersAndDelimiters,
19761974
buildDisplayForTypeParametersAndDelimiters: buildDisplayForTypeParametersAndDelimiters,
1977-
buildDisplayForTypeArgumentsAndDelimiters: buildDisplayForTypeArgumentsAndDelimiters,
19781975
buildTypeParameterDisplayFromSymbol: buildTypeParameterDisplayFromSymbol,
19791976
buildSignatureDisplay: buildSignatureDisplay,
19801977
buildReturnTypeDisplay: buildReturnTypeDisplay
@@ -4480,6 +4477,16 @@ namespace ts {
44804477
errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2);
44814478
}
44824479

4480+
function reportRelationError(message: DiagnosticMessage, source: Type, target: Type) {
4481+
let sourceType = typeToString(source);
4482+
let targetType = typeToString(target);
4483+
if (sourceType === targetType) {
4484+
sourceType = typeToString(source, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
4485+
targetType = typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
4486+
}
4487+
reportError(message || Diagnostics.Type_0_is_not_assignable_to_type_1, sourceType, targetType);
4488+
}
4489+
44834490
// Compare two types and return
44844491
// Ternary.True if they are related with no assumptions,
44854492
// Ternary.Maybe if they are related with assumptions of other relationships, or
@@ -4499,7 +4506,19 @@ namespace ts {
44994506
if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True;
45004507
}
45014508
}
4509+
4510+
if (relation === assignableRelation && source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshObjectLiteral) {
4511+
if (hasExcessProperties(<ObjectType>source, target, reportErrors)) {
4512+
if (reportErrors) {
4513+
reportRelationError(headMessage, source, target);
4514+
}
4515+
return Ternary.False;
4516+
}
4517+
source = getRegularTypeOfObjectLiteral(source);
4518+
}
4519+
45024520
let saveErrorInfo = errorInfo;
4521+
45034522
if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
45044523
// We have type references to same target type, see if relationship holds for all type arguments
45054524
if (result = typesRelatedTo((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, reportErrors)) {
@@ -4576,18 +4595,28 @@ namespace ts {
45764595
}
45774596

45784597
if (reportErrors) {
4579-
headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1;
4580-
let sourceType = typeToString(source);
4581-
let targetType = typeToString(target);
4582-
if (sourceType === targetType) {
4583-
sourceType = typeToString(source, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
4584-
targetType = typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
4585-
}
4586-
reportError(headMessage, sourceType, targetType);
4598+
reportRelationError(headMessage, source, target);
45874599
}
45884600
return Ternary.False;
45894601
}
45904602

4603+
function hasExcessProperties(source: ObjectType, target: Type, reportErrors: boolean): boolean {
4604+
if (target.flags & TypeFlags.ObjectType) {
4605+
var resolved = resolveStructuredTypeMembers(target);
4606+
if (resolved.properties.length > 0 && !resolved.stringIndexType && !resolved.numberIndexType) {
4607+
for (let prop of getPropertiesOfObjectType(source)) {
4608+
if (!getPropertyOfType(target, prop.name)) {
4609+
if (reportErrors) {
4610+
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(target));
4611+
}
4612+
return true;
4613+
}
4614+
}
4615+
}
4616+
}
4617+
return false;
4618+
}
4619+
45914620
function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary {
45924621
let result = Ternary.True;
45934622
let sourceTypes = source.types;
@@ -5255,6 +5284,24 @@ namespace ts {
52555284
return (type.flags & TypeFlags.Tuple) && !!(<TupleType>type).elementTypes;
52565285
}
52575286

5287+
function getRegularTypeOfObjectLiteral(type: Type): Type {
5288+
if (type.flags & TypeFlags.FreshObjectLiteral) {
5289+
let regularType = (<FreshObjectLiteralType>type).regularType;
5290+
if (!regularType) {
5291+
regularType = <ResolvedType>createType((<ResolvedType>type).flags & ~TypeFlags.FreshObjectLiteral);
5292+
regularType.symbol = (<ResolvedType>type).symbol;
5293+
regularType.members = (<ResolvedType>type).members;
5294+
regularType.properties = (<ResolvedType>type).properties;
5295+
regularType.callSignatures = (<ResolvedType>type).callSignatures;
5296+
regularType.constructSignatures = (<ResolvedType>type).constructSignatures;
5297+
regularType.stringIndexType = (<ResolvedType>type).stringIndexType;
5298+
regularType.numberIndexType = (<ResolvedType>type).numberIndexType;
5299+
}
5300+
return regularType;
5301+
}
5302+
return type;
5303+
}
5304+
52585305
function getWidenedTypeOfObjectLiteral(type: Type): Type {
52595306
let properties = getPropertiesOfObjectType(type);
52605307
let members: SymbolTable = {};
@@ -6830,18 +6877,6 @@ namespace ts {
68306877
return links.resolvedType;
68316878
}
68326879

6833-
function isPermittedProperty(contextualType: Type, propName: string): boolean {
6834-
if (contextualType.flags & TypeFlags.ObjectType) {
6835-
let resolved = resolveStructuredTypeMembers(<ObjectType>contextualType);
6836-
return !!(resolved.properties.length === 0 || resolved.stringIndexType ||
6837-
resolved.numberIndexType || getPropertyOfObjectType(contextualType, propName));
6838-
}
6839-
if (contextualType.flags & TypeFlags.UnionOrIntersection) {
6840-
return !forEach((<UnionOrIntersectionType>contextualType).types, type => !isPermittedProperty(type, propName));
6841-
}
6842-
return true;
6843-
}
6844-
68456880
function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type {
68466881
// Grammar checking
68476882
checkGrammarObjectLiteralExpression(node);
@@ -6891,17 +6926,14 @@ namespace ts {
68916926

68926927
if (!hasDynamicName(memberDecl)) {
68936928
propertiesTable[member.name] = member;
6894-
if (contextualType && !isPermittedProperty(contextualType, member.name)) {
6895-
error(memberDecl.name, Diagnostics.Property_0_does_not_exist_in_contextual_type_1, member.name, typeToString(contextualType));
6896-
}
68976929
}
68986930
propertiesArray.push(member);
68996931
}
69006932

69016933
let stringIndexType = getIndexType(IndexKind.String);
69026934
let numberIndexType = getIndexType(IndexKind.Number);
69036935
let result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType);
6904-
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull);
6936+
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.FreshObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull);
69056937
return result;
69066938

69076939
function getIndexType(kind: IndexKind) {
@@ -8782,7 +8814,7 @@ namespace ts {
87828814
}
87838815

87848816
function checkAssertion(node: AssertionExpression) {
8785-
let exprType = checkExpression(node.expression);
8817+
let exprType = getRegularTypeOfObjectLiteral(checkExpression(node.expression));
87868818
let targetType = getTypeFromTypeNode(node.type);
87878819
if (produceDiagnostics && targetType !== unknownType) {
87888820
let widenedType = getWidenedType(exprType);
@@ -9559,7 +9591,7 @@ namespace ts {
95599591
return getUnionType([leftType, rightType]);
95609592
case SyntaxKind.EqualsToken:
95619593
checkAssignmentOperator(rightType);
9562-
return rightType;
9594+
return getRegularTypeOfObjectLiteral(rightType);
95639595
case SyntaxKind.CommaToken:
95649596
return rightType;
95659597
}

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,6 @@ namespace ts {
414414
The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." },
415415
yield_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2523, category: DiagnosticCategory.Error, key: "'yield' expressions cannot be used in a parameter initializer." },
416416
await_expressions_cannot_be_used_in_a_parameter_initializer: { code: 2524, category: DiagnosticCategory.Error, key: "'await' expressions cannot be used in a parameter initializer." },
417-
Property_0_does_not_exist_in_contextual_type_1: { code: 2525, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist in contextual type '{1}'." },
418417
JSX_element_attributes_type_0_must_be_an_object_type: { code: 2600, category: DiagnosticCategory.Error, key: "JSX element attributes type '{0}' must be an object type." },
419418
The_return_type_of_a_JSX_element_constructor_must_return_an_object_type: { code: 2601, category: DiagnosticCategory.Error, key: "The return type of a JSX element constructor must return an object type." },
420419
JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist: { code: 2602, category: DiagnosticCategory.Error, key: "JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist." },

src/compiler/diagnosticMessages.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,10 +1645,6 @@
16451645
"category": "Error",
16461646
"code": 2524
16471647
},
1648-
"Property '{0}' does not exist in contextual type '{1}'.": {
1649-
"category": "Error",
1650-
"code": 2525
1651-
},
16521648
"JSX element attributes type '{0}' must be an object type.": {
16531649
"category": "Error",
16541650
"code": 2600

src/compiler/types.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,10 +1743,12 @@ namespace ts {
17431743
FromSignature = 0x00040000, // Created for signature assignment check
17441744
ObjectLiteral = 0x00080000, // Originates in an object literal
17451745
/* @internal */
1746-
ContainsUndefinedOrNull = 0x00100000, // Type is or contains Undefined or Null type
1746+
FreshObjectLiteral = 0x00100000, // Fresh object literal type
17471747
/* @internal */
1748-
ContainsObjectLiteral = 0x00200000, // Type is or contains object literal type
1749-
ESSymbol = 0x00400000, // Type of symbol primitive introduced in ES6
1748+
ContainsUndefinedOrNull = 0x00200000, // Type is or contains Undefined or Null type
1749+
/* @internal */
1750+
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
1751+
ESSymbol = 0x00800000, // Type of symbol primitive introduced in ES6
17501752

17511753
/* @internal */
17521754
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
@@ -1839,6 +1841,11 @@ namespace ts {
18391841
numberIndexType?: Type; // Numeric index type
18401842
}
18411843

1844+
/* @internal */
1845+
export interface FreshObjectLiteralType extends ResolvedType {
1846+
regularType: ResolvedType; // Regular version of fresh type
1847+
}
1848+
18421849
// Just a place to cache element types of iterables and iterators
18431850
/* @internal */
18441851
export interface IterableOrIteratorType extends ObjectType, UnionType {
@@ -2189,6 +2196,7 @@ namespace ts {
21892196

21902197
export interface CompilerHost {
21912198
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
2199+
getCancellationToken?(): CancellationToken;
21922200
getDefaultLibFileName(options: CompilerOptions): string;
21932201
writeFile: WriteFileCallback;
21942202
getCurrentDirectory(): string;

src/harness/fourslash.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ module FourSlash {
2626
export interface FourSlashFile {
2727
// The contents of the file (with markers, etc stripped out)
2828
content: string;
29-
3029
fileName: string;
31-
30+
version: number;
3231
// File-specific options (name/value pairs)
3332
fileOptions: { [index: string]: string; };
3433
}

src/harness/loggedIO.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface FindFileResult {
1212
}
1313

1414
interface IOLog {
15+
timestamp: string;
1516
arguments: string[];
1617
executingPath: string;
1718
currentDirectory: string;

src/server/client.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,7 @@ namespace ts.server {
202202
return {
203203
isMemberCompletion: false,
204204
isNewIdentifierLocation: false,
205-
entries: response.body,
206-
fileName: fileName,
207-
position: position
205+
entries: response.body
208206
};
209207
}
210208

src/services/services.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,7 @@ namespace ts {
11021102
}
11031103

11041104
export interface HighlightSpan {
1105+
fileName?: string;
11051106
textSpan: TextSpan;
11061107
kind: string;
11071108
}
@@ -1408,7 +1409,9 @@ namespace ts {
14081409
* @param fileName The name of the file to be released
14091410
* @param compilationSettings The compilation settings used to acquire the file
14101411
*/
1411-
releaseDocument(fileName: string, compilationSettings: CompilerOptions): void
1412+
releaseDocument(fileName: string, compilationSettings: CompilerOptions): void;
1413+
1414+
reportStats(): string;
14121415
}
14131416

14141417
// TODO: move these to enums

src/services/shims.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,11 @@ namespace ts {
428428
}
429429
}
430430

431-
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; } []{
431+
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number; } []{
432432
return diagnostics.map(d => realizeDiagnostic(d, newLine));
433433
}
434434

435-
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } {
435+
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number; } {
436436
return {
437437
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
438438
start: diagnostic.start,

0 commit comments

Comments
 (0)