Skip to content
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
66 changes: 50 additions & 16 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2160,24 +2160,25 @@ namespace ts {
return type.flags & TypeFlags.StringLiteral ? `"${escapeString((<LiteralType>type).text)}"` : (<LiteralType>type).text;
}

function getSymbolDisplayBuilder(): SymbolDisplayBuilder {

function getNameOfSymbol(symbol: Symbol): string {
if (symbol.declarations && symbol.declarations.length) {
const declaration = symbol.declarations[0];
if (declaration.name) {
return declarationNameToString(declaration.name);
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
function getNameOfSymbol(symbol: Symbol): string {
if (symbol.declarations && symbol.declarations.length) {
const declaration = symbol.declarations[0];
if (declaration.name) {
return declarationNameToString(declaration.name);
}
switch (declaration.kind) {
case SyntaxKind.ClassExpression:
return "(Anonymous class)";
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return "(Anonymous function)";
}
return symbol.name;
}
return symbol.name;
}

function getSymbolDisplayBuilder(): SymbolDisplayBuilder {

/**
* Writes only the name of the symbol out to the writer. Uses the original source text
Expand Down Expand Up @@ -15654,7 +15655,7 @@ namespace ts {
}
}
else {
const isStatic = forEach(member.modifiers, m => m.kind === SyntaxKind.StaticKeyword);
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
const names = isStatic ? staticNames : instanceNames;

const memberName = member.name && getPropertyNameForPropertyNameNode(member.name);
Expand Down Expand Up @@ -15692,6 +15693,38 @@ namespace ts {
}
}

/**
* Static members being set on a constructor function may conflict with built-in properties
* of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable
* built-in properties. This check issues a transpile error when a class has a static
* member with the same name as a non-writable built-in property.
*
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-function-instances
*/
function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) {
for (const member of node.members) {
const memberNameNode = member.name;
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
if (isStatic && memberNameNode) {
const memberName = getPropertyNameForPropertyNameNode(memberNameNode);
switch (memberName) {
case "name":
case "length":
case "caller":
case "arguments":
case "prototype":
const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1;
const className = getNameOfSymbol(getSymbolOfNode(node));
error(memberNameNode, message, memberName, className);
break;
}
}
}
}

function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) {
const names = createMap<boolean>();
for (const member of node.members) {
Expand Down Expand Up @@ -18267,6 +18300,7 @@ namespace ts {
const staticType = <ObjectType>getTypeOfSymbol(symbol);
checkTypeParameterListsIdentical(node, symbol);
checkClassForDuplicateDeclarations(node);
checkClassForStaticPropertyNameConflicts(node);

const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2015,6 +2015,10 @@
"category": "Error",
"code": 2698
},
"Static property '{0}' conflicts with built-in property 'Function.{0}' of constructor function '{1}'.": {
"category": "Error",
"code": 2699
},
"Rest types may only be created from object types.": {
"category": "Error",
"code": 2700
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/propertyNamedPrototype.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedPrototype.ts(3,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'C'.


==== tests/cases/conformance/classes/propertyMemberDeclarations/propertyNamedPrototype.ts (1 errors) ====
class C {
prototype: number; // ok
static prototype: C; // error
~~~~~~~~~
!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'C'.
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(12,1): error TS2322: Type 'C' is not assignable to type 'A'.
Property 'name' is missing in type 'C'.
Property 'prop' is missing in type 'C'.
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(13,1): error TS2322: Type 'typeof B' is not assignable to type 'A'.
Property 'name' is missing in type 'typeof B'.
Property 'prop' is missing in type 'typeof B'.
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(16,5): error TS2322: Type 'C' is not assignable to type 'B'.
Property 'name' is missing in type 'C'.
Property 'prop' is missing in type 'C'.
tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts(17,1): error TS2322: Type 'typeof B' is not assignable to type 'B'.
Property 'name' is missing in type 'typeof B'.
Property 'prop' is missing in type 'typeof B'.


==== tests/cases/compiler/staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts (4 errors) ====
interface A {
name();
prop();
}
class B {
public name() { }
public prop() { }
}
class C {
public static name() { }
public static prop() { }
}

var a: A = new B();
a = new C(); // error name is missing
a = new C(); // error prop is missing
~
!!! error TS2322: Type 'C' is not assignable to type 'A'.
!!! error TS2322: Property 'name' is missing in type 'C'.
a = B; // error name is missing
!!! error TS2322: Property 'prop' is missing in type 'C'.
a = B; // error prop is missing
~
!!! error TS2322: Type 'typeof B' is not assignable to type 'A'.
!!! error TS2322: Property 'name' is missing in type 'typeof B'.
!!! error TS2322: Property 'prop' is missing in type 'typeof B'.
a = C;

var b: B = new C(); // error name is missing
var b: B = new C(); // error prop is missing
~
!!! error TS2322: Type 'C' is not assignable to type 'B'.
!!! error TS2322: Property 'name' is missing in type 'C'.
b = B; // error name is missing
!!! error TS2322: Property 'prop' is missing in type 'C'.
b = B; // error prop is missing
~
!!! error TS2322: Type 'typeof B' is not assignable to type 'B'.
!!! error TS2322: Property 'name' is missing in type 'typeof B'.
!!! error TS2322: Property 'prop' is missing in type 'typeof B'.
b = C;
b = a;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//// [staticMemberOfClassAndPublicMemberOfAnotherClassAssignment.ts]
interface A {
name();
prop();
}
class B {
public name() { }
public prop() { }
}
class C {
public static name() { }
public static prop() { }
}

var a: A = new B();
a = new C(); // error name is missing
a = B; // error name is missing
a = new C(); // error prop is missing
a = B; // error prop is missing
a = C;

var b: B = new C(); // error name is missing
b = B; // error name is missing
var b: B = new C(); // error prop is missing
b = B; // error prop is missing
b = C;
b = a;

Expand All @@ -29,21 +29,21 @@ c = a;
var B = (function () {
function B() {
}
B.prototype.name = function () { };
B.prototype.prop = function () { };
return B;
}());
var C = (function () {
function C() {
}
C.name = function () { };
C.prop = function () { };
return C;
}());
var a = new B();
a = new C(); // error name is missing
a = B; // error name is missing
a = new C(); // error prop is missing
a = B; // error prop is missing
a = C;
var b = new C(); // error name is missing
b = B; // error name is missing
var b = new C(); // error prop is missing
b = B; // error prop is missing
b = C;
b = a;
var c = new B();
Expand Down
Loading