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

Allows type guards with switch statement (need help..) #2229

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4853,6 +4853,13 @@ module ts {
narrowedType = narrowType(type, (<ConditionalExpression>node).condition, /*assumeTrue*/ child === (<ConditionalExpression>node).whenTrue);
}
break;
case SyntaxKind.CaseClause:
// In a case clause of a switch statement using typeof
var parent = (<CaseClause>node).parent;
if((<SwitchStatement>parent).expression.kind === SyntaxKind.TypeOfExpression){
narrowedType = checkExpression((<TypeOfExpression>(<CaseClause>node).expression).text);
}
break;
case SyntaxKind.BinaryExpression:
// In the right operand of an && or ||, narrow based on left operand
if (child === (<BinaryExpression>node).right) {
Expand Down Expand Up @@ -8605,7 +8612,7 @@ module ts {
// since LHS will be block scoped name instead of function scoped
if (!namesShareScope) {
var name = symbolToString(localDeclarationSymbol);
error(getErrorSpanForNode(node), Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name);
error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name);
}
}
}
Expand Down Expand Up @@ -11817,19 +11824,11 @@ module ts {
return sourceFile.parseDiagnostics.length > 0;
}

function scanToken(scanner: Scanner, pos: number) {
scanner.setTextPos(pos);
scanner.scan();
var start = scanner.getTokenPos();
return start;
}

function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
var sourceFile = getSourceFileOfNode(node);
if (!hasParseDiagnostics(sourceFile)) {
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
var start = scanToken(scanner, node.pos);
diagnostics.add(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2));
var span = getSpanOfTokenAtPosition(sourceFile, node.pos);
diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2));
return true;
}
}
Expand All @@ -11844,9 +11843,7 @@ module ts {
function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
var sourceFile = getSourceFileOfNode(node);
if (!hasParseDiagnostics(sourceFile)) {
var span = getErrorSpanForNode(node);
var start = span.end > span.pos ? skipTrivia(sourceFile.text, span.pos) : span.pos;
diagnostics.add(createFileDiagnostic(sourceFile, start, span.end - start, message, arg0, arg1, arg2));
diagnostics.add(createDiagnosticForNode(node, message, arg0, arg1, arg2));
return true;
}
}
Expand Down Expand Up @@ -11983,9 +11980,8 @@ module ts {
function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
var sourceFile = getSourceFileOfNode(node);
if (!hasParseDiagnostics(sourceFile)) {
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text);
scanToken(scanner, node.pos);
diagnostics.add(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2));
var span = getSpanOfTokenAtPosition(sourceFile, node.pos);
diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2));
return true;
}
}
Expand Down
14 changes: 6 additions & 8 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,21 +423,19 @@ module ts {
return;
}

var firstExternalModule = forEach(files, f => isExternalModule(f) ? f : undefined);
if (firstExternalModule && !options.module) {
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
var externalModuleErrorSpan = getErrorSpanForNode(firstExternalModule.externalModuleIndicator);
var errorStart = skipTrivia(firstExternalModule.text, externalModuleErrorSpan.pos);
var errorLength = externalModuleErrorSpan.end - errorStart;
diagnostics.add(createFileDiagnostic(firstExternalModule, errorStart, errorLength, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided));
var firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined);
if (firstExternalModuleSourceFile && !options.module) {
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
var span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided));
}

// there has to be common source directory if user specified --outdir || --sourcRoot
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
if (options.outDir || // there is --outDir specified
options.sourceRoot || // there is --sourceRoot specified
(options.mapRoot && // there is --mapRoot Specified and there would be multiple js files generated
(!options.out || firstExternalModule !== undefined))) {
(!options.out || firstExternalModuleSourceFile !== undefined))) {

var commonPathComponents: string[];
forEach(files, sourceFile => {
Expand Down
56 changes: 33 additions & 23 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,32 +218,35 @@ module ts {
}

export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic {
node = getErrorSpanForNode(node);
var file = getSourceFileOfNode(node);

var start = getTokenPosOfNode(node, file);
var length = node.end - start;

return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
var sourceFile = getSourceFileOfNode(node);
var span = getErrorSpanForNode(sourceFile, node);
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2);
}

export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic {
node = getErrorSpanForNode(node);
var file = getSourceFileOfNode(node);
var start = skipTrivia(file.text, node.pos);
var length = node.end - start;
var sourceFile = getSourceFileOfNode(node);
var span = getErrorSpanForNode(sourceFile, node);
return {
file,
start,
length,
file: sourceFile,
start: span.start,
length: span.length,
code: messageChain.code,
category: messageChain.category,
messageText: messageChain.next ? messageChain : messageChain.messageText
};
}

export function getErrorSpanForNode(node: Node): Node {
var errorSpan: Node;
/* @internal */
export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan {
var scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.text);
scanner.setTextPos(pos);
scanner.scan();
var start = scanner.getTokenPos();
return createTextSpanFromBounds(start, scanner.getTextPos());
}

export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpan {
var errorNode = node;
switch (node.kind) {
// This list is a work in progress. Add missing node kinds to improve their error
// spans.
Expand All @@ -254,16 +257,23 @@ module ts {
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumMember:
errorSpan = (<Declaration>node).name;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
errorNode = (<Declaration>node).name;
break;
}

if (errorNode === undefined) {
// If we don't have a better node, then just set the error on the first token of
// construct.
return getSpanOfTokenAtPosition(sourceFile, node.pos);
}

var pos = nodeIsMissing(errorNode)
? errorNode.pos
: skipTrivia(sourceFile.text, errorNode.pos);

// We now have the ideal error span, but it may be a node that is optional and absent
// (e.g. the name of a function expression), in which case errorSpan will be undefined.
// Alternatively, it might be required and missing (e.g. the name of a module), in which
// case its pos will equal its end (length 0). In either of these cases, we should fall
// back to the original node that the error was issued on.
return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node;
return createTextSpanFromBounds(pos, errorNode.end);
}

export function isExternalModule(file: SourceFile): boolean {
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/ambientErrors.errors.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(6,1): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/conformance/ambient/ambientErrors.ts(6,18): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/conformance/ambient/ambientErrors.ts(17,22): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
tests/cases/conformance/ambient/ambientErrors.ts(20,24): error TS1184: An implementation cannot be declared in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(24,5): error TS1066: Ambient enum elements can only have integer literal initializers.
Expand All @@ -25,7 +25,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
// Ambient functions with invalid overloads
declare function fn(x: number): string;
declare function fn(x: 'foo'): number;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.

// Ambient functions with duplicate signatures
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/anyIdenticalToItself.errors.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
tests/cases/compiler/anyIdenticalToItself.ts(1,1): error TS2394: Overload signature is not compatible with function implementation.
tests/cases/compiler/anyIdenticalToItself.ts(1,10): error TS2394: Overload signature is not compatible with function implementation.
tests/cases/compiler/anyIdenticalToItself.ts(6,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/anyIdenticalToItself.ts(10,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.


==== tests/cases/compiler/anyIdenticalToItself.ts (3 errors) ====
function foo(x: any);
~~~~~~~~~~~~~~~~~~~~~
~~~
!!! error TS2394: Overload signature is not compatible with function implementation.
function foo(x: any);
function foo(x: any, y: number) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ tests/cases/compiler/assignLambdaToNominalSubtypeOfFunction.ts(8,4): error TS234
!!! error TS2345: Argument of type '(a: any, b: any) => boolean' is not assignable to parameter of type 'IResultCallback'.
!!! error TS2345: Property 'x' is missing in type '(a: any, b: any) => boolean'.
fn(function (a, b) { return true; })
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~
!!! error TS2345: Argument of type '(a: any, b: any) => boolean' is not assignable to parameter of type 'IResultCallback'.
!!! error TS2345: Property 'x' is missing in type '(a: any, b: any) => boolean'.

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(4,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(9,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(15,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(16,9): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(16,18): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(20,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(21,9): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(21,18): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(26,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(28,13): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(28,22): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(33,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(35,13): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(35,22): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.


==== tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts (10 errors) ====
Expand All @@ -33,20 +33,18 @@ tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(35,13): error
~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
return 10;
}
set prop2(val: number) {
~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
}
}
class c extends Foo {
Expand All @@ -55,10 +53,9 @@ tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(35,13): error
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
var x = () => {
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
}
return 10;
}
Expand All @@ -67,10 +64,9 @@ tests/cases/compiler/collisionSuperAndLocalFunctionInAccessors.ts(35,13): error
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
var x = () => {
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts(12,9): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts(20,13): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts(12,18): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts(20,22): error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.


==== tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts (2 errors) ====
Expand All @@ -15,21 +15,19 @@ tests/cases/compiler/collisionSuperAndLocalFunctionInConstructor.ts(20,13): erro
constructor() {
super();
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
}
}
class c extends Foo {
constructor() {
super();
var x = () => {
function _super() { // Should be error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~~~~~~~~~
~~~~~~
!!! error TS2401: Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.
}
}
}
}
Loading