Skip to content

Commit 1a5b421

Browse files
committed
Merge pull request #630 from Microsoft/truncateTypesInErrors
Truncate long types in error messages
2 parents 3e4c5d5 + e2c3b50 commit 1a5b421

File tree

7 files changed

+92
-25
lines changed

7 files changed

+92
-25
lines changed

src/compiler/checker.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ module ts {
3737

3838
var emptyArray: any[] = [];
3939
var emptySymbols: SymbolTable = {};
40-
40+
41+
var compilerOptions = program.getCompilerOptions();
42+
4143
var checker: TypeChecker = {
4244
getProgram: () => program,
4345
getDiagnostics: getDiagnostics,
@@ -943,20 +945,37 @@ module ts {
943945
writer.write(symbolToString(symbol, enclosingDeclaration, meaning));
944946
}
945947

946-
function createSingleLineTextWriter() {
948+
function createSingleLineTextWriter(maxLength?: number) {
947949
var result = "";
950+
var overflow = false;
951+
function write(s: string) {
952+
if (!overflow) {
953+
result += s;
954+
if (result.length > maxLength) {
955+
result = result.substr(0, maxLength - 3) + "...";
956+
overflow = true;
957+
}
958+
}
959+
}
948960
return {
949-
write(s: string) { result += s; },
950-
writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this); },
951-
writeLine() { result += " "; },
961+
write: write,
962+
writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
963+
writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this);
964+
},
965+
writeLine() {
966+
write(" ");
967+
},
952968
increaseIndent() { },
953969
decreaseIndent() { },
954-
getText() { return result; }
970+
getText() {
971+
return result;
972+
}
955973
};
956974
}
957975

958976
function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
959-
var stringWriter = createSingleLineTextWriter();
977+
var maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100;
978+
var stringWriter = createSingleLineTextWriter(maxLength);
960979
// TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration
961980
writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter);
962981
return stringWriter.getText();
@@ -1348,7 +1367,7 @@ module ts {
13481367
return type;
13491368

13501369
function checkImplicitAny(type: Type) {
1351-
if (!fullTypeCheck || !program.getCompilerOptions().noImplicitAny) {
1370+
if (!fullTypeCheck || !compilerOptions.noImplicitAny) {
13521371
return;
13531372
}
13541373
// We need to have ended up with 'any', 'any[]', 'any[][]', etc.
@@ -1451,7 +1470,7 @@ module ts {
14511470
}
14521471
// Otherwise, fall back to 'any'.
14531472
else {
1454-
if (program.getCompilerOptions().noImplicitAny) {
1473+
if (compilerOptions.noImplicitAny) {
14551474
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name);
14561475
}
14571476

@@ -3971,7 +3990,7 @@ module ts {
39713990
}
39723991

39733992
// Fall back to any.
3974-
if (program.getCompilerOptions().noImplicitAny && objectType !== anyType) {
3993+
if (compilerOptions.noImplicitAny && objectType !== anyType) {
39753994
error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
39763995
}
39773996

@@ -4316,7 +4335,7 @@ module ts {
43164335
var declaration = signature.declaration;
43174336
if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature)) {
43184337
// When resolved signature is a call signature (and not a construct signature) the result type is any
4319-
if (program.getCompilerOptions().noImplicitAny) {
4338+
if (compilerOptions.noImplicitAny) {
43204339
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
43214340
}
43224341
return anyType;
@@ -4362,7 +4381,7 @@ module ts {
43624381
var unwidenedType = checkAndMarkExpression(func.body, contextualMapper);
43634382
var widenedType = getWidenedType(unwidenedType);
43644383

4365-
if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
4384+
if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
43664385
error(func, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeToString(widenedType));
43674386
}
43684387

@@ -4384,7 +4403,7 @@ module ts {
43844403
var widenedType = getWidenedType(commonType);
43854404

43864405
// Check and report for noImplicitAny if the best common type implicitly gets widened to an 'any'/arrays-of-'any' type.
4387-
if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
4406+
if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
43884407
var typeName = typeToString(widenedType);
43894408

43904409
if (func.name) {
@@ -4960,7 +4979,7 @@ module ts {
49604979
checkCollisionWithCapturedThisVariable(node, node.name);
49614980
checkCollistionWithRequireExportsInGeneratedCode(node, node.name);
49624981
checkCollisionWithArgumentsInGeneratedCode(node);
4963-
if (program.getCompilerOptions().noImplicitAny && !node.type) {
4982+
if (compilerOptions.noImplicitAny && !node.type) {
49644983
switch (node.kind) {
49654984
case SyntaxKind.ConstructSignature:
49664985
error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type);
@@ -5516,7 +5535,7 @@ module ts {
55165535
}
55175536

55185537
// If there is no body and no explicit return type, then report an error.
5519-
if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && !node.body && !node.type) {
5538+
if (fullTypeCheck && compilerOptions.noImplicitAny && !node.body && !node.type) {
55205539
// Ignore privates within ambient contexts; they exist purely for documentative purposes to avoid name clashing.
55215540
// (e.g. privates within .d.ts files do not expose type information)
55225541
if (!isPrivateWithinAmbient(node)) {
@@ -7161,7 +7180,7 @@ module ts {
71617180
function shouldEmitDeclarations() {
71627181
// If the declaration emit and there are no errors being reported in program or by checker
71637182
// declarations can be emitted
7164-
return program.getCompilerOptions().declaration &&
7183+
return compilerOptions.declaration &&
71657184
!program.getDiagnostics().length &&
71667185
!getDiagnostics().length;
71677186
}

src/compiler/types.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -631,12 +631,10 @@ module ts {
631631
}
632632

633633
export enum TypeFormatFlags {
634-
None = 0x00000000,
635-
636-
/** writes Array<T> instead T[] */
637-
WriteArrayAsGenericType = 0x00000001, // Declarations
638-
639-
UseTypeOfFunction = 0x00000002, // instead of writing signature type of function use typeof
634+
None = 0x00000000,
635+
WriteArrayAsGenericType = 0x00000001, // Write Array<T> instead T[]
636+
UseTypeOfFunction = 0x00000002, // Write typeof instead of function type literal
637+
NoTruncation = 0x00000004, // Don't truncate typeToString result
640638
}
641639

642640
export enum SymbolAccessibility {
@@ -957,6 +955,7 @@ module ts {
957955
locale?: string;
958956
mapRoot?: string;
959957
module?: ModuleKind;
958+
noErrorTruncation?: boolean;
960959
noImplicitAny?: boolean;
961960
noLib?: boolean;
962961
noLibCheck?: boolean;
@@ -969,7 +968,6 @@ module ts {
969968
target?: ScriptTarget;
970969
version?: boolean;
971970
watch?: boolean;
972-
973971
[option: string]: any;
974972
}
975973

src/harness/harness.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ module Harness {
622622
options = options || { noResolve: false };
623623
options.target = options.target || ts.ScriptTarget.ES3;
624624
options.module = options.module || ts.ModuleKind.None;
625+
options.noErrorTruncation = true;
625626

626627
if (settingsCallback) {
627628
settingsCallback(null);
@@ -725,6 +726,10 @@ module Harness {
725726
options.emitBOM = !!setting.value;
726727
break;
727728

729+
case 'errortruncation':
730+
options.noErrorTruncation = setting.value === 'false';
731+
break;
732+
728733
default:
729734
throw new Error('Unsupported compiler setting ' + setting.flag);
730735
}
@@ -1030,7 +1035,7 @@ module Harness {
10301035
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
10311036

10321037
// List of allowed metadata names
1033-
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom"];
1038+
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation"];
10341039

10351040
function extractCompilerSettings(content: string): CompilerSetting[] {
10361041

src/harness/typeWriter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class TypeWriterWalker {
8686
column: lineAndCharacter.character,
8787
syntaxKind: ts.SyntaxKind[node.kind],
8888
sourceText: sourceText,
89-
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.None)
89+
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation)
9090
});
9191
}
9292

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
==== tests/cases/compiler/errorWithTruncatedType.ts (1 errors) ====
2+
3+
var x: {
4+
propertyWithAnExceedinglyLongName1: string;
5+
propertyWithAnExceedinglyLongName2: string;
6+
propertyWithAnExceedinglyLongName3: string;
7+
propertyWithAnExceedinglyLongName4: string;
8+
propertyWithAnExceedinglyLongName5: string;
9+
};
10+
11+
// String representation of type of 'x' should be truncated in error message
12+
var s: string = x;
13+
~
14+
!!! Type '{ propertyWithAnExceedinglyLongName1: string; propertyWithAnExceedinglyLongName2: string; propert...' is not assignable to type 'string'.
15+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [errorWithTruncatedType.ts]
2+
3+
var x: {
4+
propertyWithAnExceedinglyLongName1: string;
5+
propertyWithAnExceedinglyLongName2: string;
6+
propertyWithAnExceedinglyLongName3: string;
7+
propertyWithAnExceedinglyLongName4: string;
8+
propertyWithAnExceedinglyLongName5: string;
9+
};
10+
11+
// String representation of type of 'x' should be truncated in error message
12+
var s: string = x;
13+
14+
15+
//// [errorWithTruncatedType.js]
16+
var x;
17+
// String representation of type of 'x' should be truncated in error message
18+
var s = x;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @errortruncation: true
2+
3+
var x: {
4+
propertyWithAnExceedinglyLongName1: string;
5+
propertyWithAnExceedinglyLongName2: string;
6+
propertyWithAnExceedinglyLongName3: string;
7+
propertyWithAnExceedinglyLongName4: string;
8+
propertyWithAnExceedinglyLongName5: string;
9+
};
10+
11+
// String representation of type of 'x' should be truncated in error message
12+
var s: string = x;

0 commit comments

Comments
 (0)