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

Allow literal initializers of readonly properties in declaration files #26313

Merged
merged 4 commits into from Sep 5, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 23 additions & 21 deletions src/compiler/checker.ts
Expand Up @@ -21706,7 +21706,7 @@ namespace ts {
const initializer = getEffectiveInitializer(declaration)!;
const type = getTypeOfExpression(initializer, /*cache*/ true);
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const ||
(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration)) ||
isDeclarationReadonly(declaration) ||
isTypeAssertion(initializer) ? type : getWidenedLiteralType(type);
if (isInJavaScriptFile(declaration)) {
if (widened.flags & TypeFlags.Nullable) {
Expand Down Expand Up @@ -28080,7 +28080,7 @@ namespace ts {
}

function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean {
if (isVariableDeclaration(node) && isVarConst(node)) {
if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node)) {
const type = getTypeOfSymbol(getSymbolOfNode(node));
return !!(type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral);
}
Expand Down Expand Up @@ -29418,26 +29418,28 @@ namespace ts {
(<PrefixUnaryExpression>expr).operand.kind === SyntaxKind.NumericLiteral;
}

function checkAmbientInitializer(node: VariableDeclaration | PropertyDeclaration | PropertySignature) {
if (node.initializer) {
const isInvalidInitializer = !isStringOrNumberLiteralExpression(node.initializer);
const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node);
if (isConstOrReadonly && !node.type) {
if (isInvalidInitializer) {
return grammarErrorOnNode(node.initializer!, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
}
}
else {
return grammarErrorOnNode(node.initializer!, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
if (!isConstOrReadonly || isInvalidInitializer) {
return grammarErrorOnNode(node.initializer!, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
}
}

function checkGrammarVariableDeclaration(node: VariableDeclaration) {
if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
if (node.flags & NodeFlags.Ambient) {
if (node.initializer) {
if (isVarConst(node) && !node.type) {
if (!isStringOrNumberLiteralExpression(node.initializer)) {
return grammarErrorOnNode(node.initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
}
}
else {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
}
if (node.initializer && !(isVarConst(node) && isStringOrNumberLiteralExpression(node.initializer))) {
// Error on equals token which immediate precedes the initializer
const equalsTokenLength = "=".length;
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
}
checkAmbientInitializer(node);
}
else if (!node.initializer) {
if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
Expand Down Expand Up @@ -29630,8 +29632,8 @@ namespace ts {
}
}

if (node.flags & NodeFlags.Ambient && node.initializer) {
return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
if (node.flags & NodeFlags.Ambient) {
checkAmbientInitializer(node);
}

if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer ||
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/utilities.ts
Expand Up @@ -922,6 +922,10 @@ namespace ts {
return !!(getCombinedModifierFlags(node) & ModifierFlags.Const);
}

export function isDeclarationReadonly(declaration: Declaration): boolean {
return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration));
}

export function isVarConst(node: VariableDeclaration | VariableDeclarationList): boolean {
return !!(getCombinedNodeFlags(node) & NodeFlags.Const);
}
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/ambientErrors.errors.txt
@@ -1,8 +1,8 @@
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(2,17): error TS1039: Initializers are not allowed in ambient contexts.
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.
tests/cases/conformance/ambient/ambientErrors.ts(34,11): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(34,13): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(35,19): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(37,20): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/ambient/ambientErrors.ts(38,13): error TS1039: Initializers are not allowed in ambient contexts.
Expand All @@ -17,7 +17,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
==== tests/cases/conformance/ambient/ambientErrors.ts (14 errors) ====
// Ambient variable with an initializer
declare var x = 4;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.

// Ambient functions with invalid overloads
Expand Down Expand Up @@ -57,7 +57,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
// Ambient module with initializers for values, bodies for functions / classes
declare module M1 {
var x = 3;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
function fn() { }
~
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/ambientErrors1.errors.txt
@@ -1,7 +1,7 @@
tests/cases/compiler/ambientErrors1.ts(1,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/ambientErrors1.ts(1,17): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/compiler/ambientErrors1.ts (1 errors) ====
declare var x = 4;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
4 changes: 2 additions & 2 deletions tests/baselines/reference/ambientStatement1.errors.txt
@@ -1,5 +1,5 @@
tests/cases/compiler/ambientStatement1.ts(2,6): error TS1036: Statements are not allowed in ambient contexts.
tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/ambientStatement1.ts(4,22): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/compiler/ambientStatement1.ts (2 errors) ====
Expand All @@ -9,6 +9,6 @@ tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are
!!! error TS1036: Statements are not allowed in ambient contexts.

export var v1 = () => false;
~
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this readonly declaration?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not, the error span location was just normalized for the initializer forbidden error to always be on the initializer instead of sometimes on the initializer and sometimes on the equals token.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weswigham makes sense. Sorry somehow I perceived as error removed. My bad.

~~~~~~~~~~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
}
@@ -1,30 +1,30 @@
tests/cases/compiler/constDeclarations-ambient-errors.ts(2,27): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,26): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(2,29): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,28): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,20): error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,37): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,51): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,22): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,39): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,53): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,24): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/compiler/constDeclarations-ambient-errors.ts (6 errors) ====
// error: no intialization expected in ambient declarations
declare const c1: boolean = true;
~
~~~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
declare const c2: number = 0;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
declare const c3 = null, c4 :string = "", c5: any = 0;
~~~~
!!! error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
~
~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.

declare module M {
const c6 = 0;
const c7: number = 7;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
}
24 changes: 24 additions & 0 deletions tests/baselines/reference/declarationEmitConstantNoWidening.js
@@ -0,0 +1,24 @@
//// [declarationEmitConstantNoWidening.ts]
export const FOO = 'FOO';
export class Bar {
readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
}

//// [declarationEmitConstantNoWidening.js]
"use strict";
exports.__esModule = true;
exports.FOO = 'FOO';
var Bar = /** @class */ (function () {
function Bar() {
this.type = exports.FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
}
return Bar;
}());
exports.Bar = Bar;


//// [declarationEmitConstantNoWidening.d.ts]
export declare const FOO = "FOO";
export declare class Bar {
readonly type = "FOO";
}
@@ -0,0 +1,11 @@
=== tests/cases/compiler/declarationEmitConstantNoWidening.ts ===
export const FOO = 'FOO';
>FOO : Symbol(FOO, Decl(declarationEmitConstantNoWidening.ts, 0, 12))

export class Bar {
>Bar : Symbol(Bar, Decl(declarationEmitConstantNoWidening.ts, 0, 25))

readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
>type : Symbol(Bar.type, Decl(declarationEmitConstantNoWidening.ts, 1, 18))
>FOO : Symbol(FOO, Decl(declarationEmitConstantNoWidening.ts, 0, 12))
}
12 changes: 12 additions & 0 deletions tests/baselines/reference/declarationEmitConstantNoWidening.types
@@ -0,0 +1,12 @@
=== tests/cases/compiler/declarationEmitConstantNoWidening.ts ===
export const FOO = 'FOO';
>FOO : "FOO"
>'FOO' : "FOO"

export class Bar {
>Bar : Bar

readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
>type : "FOO"
>FOO : "FOO"
}
8 changes: 4 additions & 4 deletions tests/baselines/reference/externSemantics.errors.txt
@@ -1,13 +1,13 @@
tests/cases/compiler/externSemantics.ts(1,14): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/externSemantics.ts(3,21): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/externSemantics.ts(1,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/externSemantics.ts(3,22): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/compiler/externSemantics.ts (2 errors) ====
declare var x=10;
~
~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
declare var v;
declare var y:number=3;
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.

12 changes: 6 additions & 6 deletions tests/baselines/reference/initializersInDeclarations.errors.txt
@@ -1,10 +1,10 @@
tests/cases/conformance/externalModules/file1.d.ts(4,9): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(5,16): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(6,16): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(11,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(12,15): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(11,17): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(12,17): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(15,2): error TS1036: Statements are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(17,16): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/externalModules/file1.d.ts(17,18): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/conformance/externalModules/file1.d.ts (7 errors) ====
Expand All @@ -25,10 +25,10 @@ tests/cases/conformance/externalModules/file1.d.ts(17,16): error TS1039: Initial
}

declare var x = [];
~
~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
declare var y = {};
~
~~
!!! error TS1039: Initializers are not allowed in ambient contexts.

declare module M1 {
Expand All @@ -37,6 +37,6 @@ tests/cases/conformance/externalModules/file1.d.ts(17,16): error TS1039: Initial
!!! error TS1036: Statements are not allowed in ambient contexts.

export var v1 = () => false;
~
~~~~~~~~~~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/missingRequiredDeclare.d.errors.txt
@@ -1,10 +1,10 @@
tests/cases/compiler/missingRequiredDeclare.d.ts(1,1): error TS1046: A 'declare' modifier is required for a top level declaration in a .d.ts file.
tests/cases/compiler/missingRequiredDeclare.d.ts(1,7): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/compiler/missingRequiredDeclare.d.ts(1,9): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/compiler/missingRequiredDeclare.d.ts (2 errors) ====
var x = 1;
~~~
!!! error TS1046: A 'declare' modifier is required for a top level declaration in a .d.ts file.
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.
@@ -1,13 +1,13 @@
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,4): error TS1184: Modifiers cannot appear here.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,18): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,20): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts (2 errors) ====
{
declare var x = this;
~~~~~~~
!!! error TS1184: Modifiers cannot appear here.
~
~~~~
!!! error TS1039: Initializers are not allowed in ambient contexts.
}

@@ -1,10 +1,10 @@
tests/cases/conformance/parser/ecmascript5/Statements/parserVariableStatement1.d.ts(1,1): error TS1046: A 'declare' modifier is required for a top level declaration in a .d.ts file.
tests/cases/conformance/parser/ecmascript5/Statements/parserVariableStatement1.d.ts(1,7): error TS1039: Initializers are not allowed in ambient contexts.
tests/cases/conformance/parser/ecmascript5/Statements/parserVariableStatement1.d.ts(1,9): error TS1039: Initializers are not allowed in ambient contexts.


==== tests/cases/conformance/parser/ecmascript5/Statements/parserVariableStatement1.d.ts (2 errors) ====
var v = 1;
~~~
!!! error TS1046: A 'declare' modifier is required for a top level declaration in a .d.ts file.
~
~
!!! error TS1039: Initializers are not allowed in ambient contexts.