diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index f54a3e0666f00..72f9855af772d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3285,9 +3285,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) { // Class declarations in Typescript do not allow property declarations const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer) ; - if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) { + const isFunctionSym = isFunctionSymbol(parentSymbol); + if (!isInJSFile(node) && !isFunctionSym) { return; } + if (isFunctionSym && isBindableStaticNameExpression(node.left)) { + const declarationName = getDeclarationName(node.left); + // specialcase readonly properties of functions as we don't have access to type info here + if (declarationName === "length" || declarationName === "name") { + return; + } + } const rootExpr = getLeftmostAccessExpression(node.left); if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias) { return; diff --git a/tests/baselines/reference/functionReadonlyLength.errors.txt b/tests/baselines/reference/functionReadonlyLength.errors.txt new file mode 100644 index 0000000000000..35bf194b28d86 --- /dev/null +++ b/tests/baselines/reference/functionReadonlyLength.errors.txt @@ -0,0 +1,27 @@ +functionReadonlyLength.ts(2,4): error TS2540: Cannot assign to 'length' because it is a read-only property. +functionReadonlyLength.ts(5,4): error TS2540: Cannot assign to 'length' because it is a read-only property. +functionReadonlyLength.ts(8,4): error TS2540: Cannot assign to 'length' because it is a read-only property. +functionReadonlyLength.ts(11,4): error TS2540: Cannot assign to 'length' because it is a read-only property. + + +==== functionReadonlyLength.ts (4 errors) ==== + const f0 = new Function() + f0.length = 1; + ~~~~~~ +!!! error TS2540: Cannot assign to 'length' because it is a read-only property. + + function f1() {}; + f1.length = 1; + ~~~~~~ +!!! error TS2540: Cannot assign to 'length' because it is a read-only property. + + const f2 = function () {}; + f2.length = 1 + ~~~~~~ +!!! error TS2540: Cannot assign to 'length' because it is a read-only property. + + const f3 = () => {} + f3.length = 1 + ~~~~~~ +!!! error TS2540: Cannot assign to 'length' because it is a read-only property. + \ No newline at end of file diff --git a/tests/baselines/reference/functionReadonlyLength.symbols b/tests/baselines/reference/functionReadonlyLength.symbols new file mode 100644 index 0000000000000..33e2808be790f --- /dev/null +++ b/tests/baselines/reference/functionReadonlyLength.symbols @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/functionReadonlyLength.ts] //// + +=== functionReadonlyLength.ts === +const f0 = new Function() +>f0 : Symbol(f0, Decl(functionReadonlyLength.ts, 0, 5)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +f0.length = 1; +>f0.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>f0 : Symbol(f0, Decl(functionReadonlyLength.ts, 0, 5)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) + +function f1() {}; +>f1 : Symbol(f1, Decl(functionReadonlyLength.ts, 1, 14)) + +f1.length = 1; +>f1.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>f1 : Symbol(f1, Decl(functionReadonlyLength.ts, 1, 14)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) + +const f2 = function () {}; +>f2 : Symbol(f2, Decl(functionReadonlyLength.ts, 6, 5)) + +f2.length = 1 +>f2.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>f2 : Symbol(f2, Decl(functionReadonlyLength.ts, 6, 5)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) + +const f3 = () => {} +>f3 : Symbol(f3, Decl(functionReadonlyLength.ts, 9, 5)) + +f3.length = 1 +>f3.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>f3 : Symbol(f3, Decl(functionReadonlyLength.ts, 9, 5)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/functionReadonlyLength.types b/tests/baselines/reference/functionReadonlyLength.types new file mode 100644 index 0000000000000..60637a618d626 --- /dev/null +++ b/tests/baselines/reference/functionReadonlyLength.types @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/functionReadonlyLength.ts] //// + +=== functionReadonlyLength.ts === +const f0 = new Function() +>f0 : Function +>new Function() : Function +>Function : FunctionConstructor + +f0.length = 1; +>f0.length = 1 : 1 +>f0.length : any +>f0 : Function +>length : any +>1 : 1 + +function f1() {}; +>f1 : () => void + +f1.length = 1; +>f1.length = 1 : 1 +>f1.length : any +>f1 : () => void +>length : any +>1 : 1 + +const f2 = function () {}; +>f2 : () => void +>function () {} : () => void + +f2.length = 1 +>f2.length = 1 : 1 +>f2.length : any +>f2 : () => void +>length : any +>1 : 1 + +const f3 = () => {} +>f3 : () => void +>() => {} : () => void + +f3.length = 1 +>f3.length = 1 : 1 +>f3.length : any +>f3 : () => void +>length : any +>1 : 1 + diff --git a/tests/baselines/reference/functionReadonlyName.errors.txt b/tests/baselines/reference/functionReadonlyName.errors.txt new file mode 100644 index 0000000000000..9d47c9a2a2ffd --- /dev/null +++ b/tests/baselines/reference/functionReadonlyName.errors.txt @@ -0,0 +1,27 @@ +functionReadonlyName.ts(2,4): error TS2339: Property 'name' does not exist on type 'Function'. +functionReadonlyName.ts(5,4): error TS2339: Property 'name' does not exist on type '() => void'. +functionReadonlyName.ts(8,4): error TS2339: Property 'name' does not exist on type '() => void'. +functionReadonlyName.ts(11,4): error TS2339: Property 'name' does not exist on type '() => void'. + + +==== functionReadonlyName.ts (4 errors) ==== + const f0 = new Function() + f0.name = 'foo'; + ~~~~ +!!! error TS2339: Property 'name' does not exist on type 'Function'. + + function f1() {}; + f1.name = 'foo'; + ~~~~ +!!! error TS2339: Property 'name' does not exist on type '() => void'. + + const f2 = function () {}; + f2.name = 'foo' + ~~~~ +!!! error TS2339: Property 'name' does not exist on type '() => void'. + + const f3 = () => {} + f3.name = 'foo' + ~~~~ +!!! error TS2339: Property 'name' does not exist on type '() => void'. + \ No newline at end of file diff --git a/tests/baselines/reference/functionReadonlyName.symbols b/tests/baselines/reference/functionReadonlyName.symbols new file mode 100644 index 0000000000000..20e98473aeb9d --- /dev/null +++ b/tests/baselines/reference/functionReadonlyName.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/functionReadonlyName.ts] //// + +=== functionReadonlyName.ts === +const f0 = new Function() +>f0 : Symbol(f0, Decl(functionReadonlyName.ts, 0, 5)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +f0.name = 'foo'; +>f0 : Symbol(f0, Decl(functionReadonlyName.ts, 0, 5)) + +function f1() {}; +>f1 : Symbol(f1, Decl(functionReadonlyName.ts, 1, 16)) + +f1.name = 'foo'; +>f1 : Symbol(f1, Decl(functionReadonlyName.ts, 1, 16)) + +const f2 = function () {}; +>f2 : Symbol(f2, Decl(functionReadonlyName.ts, 6, 5)) + +f2.name = 'foo' +>f2 : Symbol(f2, Decl(functionReadonlyName.ts, 6, 5)) + +const f3 = () => {} +>f3 : Symbol(f3, Decl(functionReadonlyName.ts, 9, 5)) + +f3.name = 'foo' +>f3 : Symbol(f3, Decl(functionReadonlyName.ts, 9, 5)) + diff --git a/tests/baselines/reference/functionReadonlyName.types b/tests/baselines/reference/functionReadonlyName.types new file mode 100644 index 0000000000000..6f893f69494b4 --- /dev/null +++ b/tests/baselines/reference/functionReadonlyName.types @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/functionReadonlyName.ts] //// + +=== functionReadonlyName.ts === +const f0 = new Function() +>f0 : Function +>new Function() : Function +>Function : FunctionConstructor + +f0.name = 'foo'; +>f0.name = 'foo' : "foo" +>f0.name : any +>f0 : Function +>name : any +>'foo' : "foo" + +function f1() {}; +>f1 : () => void + +f1.name = 'foo'; +>f1.name = 'foo' : "foo" +>f1.name : any +>f1 : () => void +>name : any +>'foo' : "foo" + +const f2 = function () {}; +>f2 : () => void +>function () {} : () => void + +f2.name = 'foo' +>f2.name = 'foo' : "foo" +>f2.name : any +>f2 : () => void +>name : any +>'foo' : "foo" + +const f3 = () => {} +>f3 : () => void +>() => {} : () => void + +f3.name = 'foo' +>f3.name = 'foo' : "foo" +>f3.name : any +>f3 : () => void +>name : any +>'foo' : "foo" + diff --git a/tests/cases/compiler/functionReadonlyLength.ts b/tests/cases/compiler/functionReadonlyLength.ts new file mode 100644 index 0000000000000..1872f6a58ff63 --- /dev/null +++ b/tests/cases/compiler/functionReadonlyLength.ts @@ -0,0 +1,13 @@ +// @noEmit: true + +const f0 = new Function() +f0.length = 1; + +function f1() {}; +f1.length = 1; + +const f2 = function () {}; +f2.length = 1 + +const f3 = () => {} +f3.length = 1 diff --git a/tests/cases/compiler/functionReadonlyName.ts b/tests/cases/compiler/functionReadonlyName.ts new file mode 100644 index 0000000000000..36fdf0749d08d --- /dev/null +++ b/tests/cases/compiler/functionReadonlyName.ts @@ -0,0 +1,13 @@ +// @noEmit: true + +const f0 = new Function() +f0.name = 'foo'; + +function f1() {}; +f1.name = 'foo'; + +const f2 = function () {}; +f2.name = 'foo' + +const f3 = () => {} +f3.name = 'foo'