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

Remove most special treatment of specialized signatures. #6278

Merged
merged 14 commits into from
Feb 2, 2016
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 20 additions & 87 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5898,29 +5898,24 @@ namespace ts {
const saveErrorInfo = errorInfo;

outer: for (const t of targetSignatures) {
if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
// Only elaborate errors from the first failure
let shouldElaborateErrors = reportErrors;
for (const s of sourceSignatures) {
if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) {
const related = signatureRelatedTo(s, t, shouldElaborateErrors);
if (related) {
result &= related;
errorInfo = saveErrorInfo;
continue outer;
}
shouldElaborateErrors = false;
}
}
// don't elaborate the primitive apparent types (like Number)
// because the actual primitives will have already been reported.
if (shouldElaborateErrors) {
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
typeToString(source),
signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind));
// Only elaborate errors from the first failure
let shouldElaborateErrors = reportErrors;
for (const s of sourceSignatures) {
const related = signatureRelatedTo(s, t, shouldElaborateErrors);
if (related) {
result &= related;
errorInfo = saveErrorInfo;
continue outer;
}
return Ternary.False;
shouldElaborateErrors = false;
}

if (shouldElaborateErrors) {
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
typeToString(source),
signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind));
}
return Ternary.False;
}
return result;
}
Expand Down Expand Up @@ -11674,8 +11669,6 @@ namespace ts {
}
}
}

checkSpecializedSignatureDeclaration(node);
}

function checkTypeForDuplicateIndexSignatures(node: Node) {
Expand Down Expand Up @@ -11986,48 +11979,6 @@ namespace ts {
return (node.flags & NodeFlags.Private) && isInAmbientContext(node);
}

function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void {
if (!produceDiagnostics) {
return;
}
const signature = getSignatureFromDeclaration(signatureDeclarationNode);
if (!signature.hasStringLiterals) {
return;
}

// TypeScript 1.0 spec (April 2014): 3.7.2.2
// Specialized signatures are not permitted in conjunction with a function body
if (nodeIsPresent((<FunctionLikeDeclaration>signatureDeclarationNode).body)) {
error(signatureDeclarationNode, Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type);
return;
}

// TypeScript 1.0 spec (April 2014): 3.7.2.4
// Every specialized call or construct signature in an object type must be assignable
// to at least one non-specialized call or construct signature in the same object type
let signaturesToCheck: Signature[];
// Unnamed (call\construct) signatures in interfaces are inherited and not shadowed so examining just node symbol won't give complete answer.
// Use declaring type to obtain full list of signatures.
if (!signatureDeclarationNode.name && signatureDeclarationNode.parent && signatureDeclarationNode.parent.kind === SyntaxKind.InterfaceDeclaration) {
Debug.assert(signatureDeclarationNode.kind === SyntaxKind.CallSignature || signatureDeclarationNode.kind === SyntaxKind.ConstructSignature);
const signatureKind = signatureDeclarationNode.kind === SyntaxKind.CallSignature ? SignatureKind.Call : SignatureKind.Construct;
const containingSymbol = getSymbolOfNode(signatureDeclarationNode.parent);
const containingType = getDeclaredTypeOfSymbol(containingSymbol);
signaturesToCheck = getSignaturesOfType(containingType, signatureKind);
}
else {
signaturesToCheck = getSignaturesOfSymbol(getSymbolOfNode(signatureDeclarationNode));
}

for (const otherSignature of signaturesToCheck) {
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false)) {
return;
}
}

error(signatureDeclarationNode, Diagnostics.Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature);
}

function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags): NodeFlags {
let flags = getCombinedNodeFlags(n);

Expand Down Expand Up @@ -12249,28 +12200,10 @@ namespace ts {
if (bodyDeclaration) {
const signatures = getSignaturesOfSymbol(symbol);
const bodySignature = getSignatureFromDeclaration(bodyDeclaration);
// If the implementation signature has string literals, we will have reported an error in
// checkSpecializedSignatureDeclaration
if (!bodySignature.hasStringLiterals) {
// TypeScript 1.0 spec (April 2014): 6.1
// If a function declaration includes overloads, the overloads determine the call
// signatures of the type given to the function object
// and the function implementation signature must be assignable to that type
//
// TypeScript 1.0 spec (April 2014): 3.8.4
// Note that specialized call and construct signatures (section 3.7.2.4) are not significant when determining assignment compatibility
// Consider checking against specialized signatures too. Not doing so creates a type hole:
//
// function g(x: "hi", y: boolean);
// function g(x: string, y: {});
// function g(x: string, y: string) { }
//
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
for (const signature of signatures) {
if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload(bodySignature, signature)) {
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
break;
}
for (const signature of signatures) {
if (!isImplementationCompatibleWithOverload(bodySignature, signature)) {
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
break;
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions tests/baselines/reference/ambientErrors.errors.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
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 TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(29,9): error TS1066: In ambient enum declarations member initializer must be constant expression.
Expand All @@ -15,7 +14,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(51,16): error TS2436: Ambient m
tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export assignment cannot be used in a module with other exported elements.


==== tests/cases/conformance/ambient/ambientErrors.ts (15 errors) ====
==== tests/cases/conformance/ambient/ambientErrors.ts (14 errors) ====
// Ambient variable with an initializer
declare var x = 4;
~
Expand All @@ -24,8 +23,6 @@ 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
declare function fn1(x: number): string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
tests/cases/compiler/callbackArgsDifferByOptionality.ts(1,23): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
tests/cases/compiler/callbackArgsDifferByOptionality.ts(4,5): error TS2304: Cannot find name 'cb'.


==== tests/cases/compiler/callbackArgsDifferByOptionality.ts (2 errors) ====
==== tests/cases/compiler/callbackArgsDifferByOptionality.ts (1 errors) ====
function x3(callback: (x?: 'hi') => number);
~~~~~~~~~~~~~~~~~~~~
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
function x3(callback: (x: string) => number);
function x3(callback: (x: any) => number) {
cb();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
=== tests/cases/compiler/constantOverloadFunctionNoSubtypeError.ts ===
class Base { foo() { } }
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 12))

class Derived1 extends Base { bar() { } }
>Derived1 : Symbol(Derived1, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 24))
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
>bar : Symbol(bar, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 29))

class Derived2 extends Base { baz() { } }
>Derived2 : Symbol(Derived2, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 41))
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
>baz : Symbol(baz, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 29))

class Derived3 extends Base { biz() { } }
>Derived3 : Symbol(Derived3, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 41))
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
>biz : Symbol(biz, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 29))

function foo(tagName: 'canvas'): Derived3;
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 13))
>Derived3 : Symbol(Derived3, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 41))

function foo(tagName: 'div'): Derived2;
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 13))
>Derived2 : Symbol(Derived2, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 41))

function foo(tagName: 'span'): Derived1;
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 13))
>Derived1 : Symbol(Derived1, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 24))

function foo(tagName: number): Base;
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 13))
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))

function foo(tagName: any): Base {
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 9, 13))
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))

return null;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
=== tests/cases/compiler/constantOverloadFunctionNoSubtypeError.ts ===
class Base { foo() { } }
>Base : Base
>foo : () => void

class Derived1 extends Base { bar() { } }
>Derived1 : Derived1
>Base : Base
>bar : () => void

class Derived2 extends Base { baz() { } }
>Derived2 : Derived2
>Base : Base
>baz : () => void

class Derived3 extends Base { biz() { } }
>Derived3 : Derived3
>Base : Base
>biz : () => void

function foo(tagName: 'canvas'): Derived3;
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
>tagName : "canvas"
>Derived3 : Derived3

function foo(tagName: 'div'): Derived2;
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
>tagName : "div"
>Derived2 : Derived2

function foo(tagName: 'span'): Derived1;
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
>tagName : "span"
>Derived1 : Derived1

function foo(tagName: number): Base;
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
>tagName : number
>Base : Base

function foo(tagName: any): Base {
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
>tagName : any
>Base : Base

return null;
>null : null
}

Loading