@@ -10400,25 +10400,44 @@ namespace ts {
1040010400 return true;
1040110401 }
1040210402
10403- function isReferenceWithinOwnConstructor(expr: Expression, symbol: Symbol): boolean {
10404- // Allow assignments to readonly properties or methods (but not readonly accessors) within constructors
10405- // of the same class declaration.
10406- if ((expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
10407- (expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword &&
10408- symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) {
10409- const func = getContainingFunction(expr);
10410- return func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent;
10411- }
10412- }
10413-
1041410403 function isReadonlySymbol(symbol: Symbol): boolean {
1041510404 return symbol.flags & SymbolFlags.Property && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Readonly) !== 0;
1041610405 }
1041710406
10418- function isConstantSymbol(symbol: Symbol): boolean {
10419- return symbol === undefinedSymbol ||
10420- symbol.flags & SymbolFlags.Variable && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 ||
10421- symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor);
10407+ function isReferenceToConstant(expr: Expression, symbol: Symbol): boolean {
10408+ if (symbol.flags & SymbolFlags.Variable) {
10409+ // A variable declared with 'const' is considered constant.
10410+ if (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) {
10411+ return true;
10412+ }
10413+ // An exported variable declared in an external module and accessed through a property
10414+ // or element access is considered constant.
10415+ if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
10416+ if (symbol.parent && symbol.parent.flags & SymbolFlags.ValueModule) {
10417+ const declaration = symbol.parent.valueDeclaration;
10418+ return declaration && (declaration.kind === SyntaxKind.SourceFile ||
10419+ declaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>declaration).name.kind === SyntaxKind.StringLiteral);
10420+ }
10421+ }
10422+ }
10423+ if (symbol.flags & SymbolFlags.Accessor) {
10424+ // An get accessor with no corresponding set accessor is considered constant.
10425+ return !(symbol.flags & SymbolFlags.SetAccessor);
10426+ }
10427+ return false;
10428+ }
10429+
10430+ function isReferenceToReadonlyProperty(expr: Expression, symbol: Symbol): boolean {
10431+ if (isReadonlySymbol(symbol)) {
10432+ // Allow assignments to readonly properties within constructors of the same class declaration.
10433+ if ((expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
10434+ (expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
10435+ const func = getContainingFunction(expr);
10436+ return !(func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent);
10437+ }
10438+ return true;
10439+ }
10440+ return false;
1042210441 }
1042310442
1042410443 function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, constantVariableMessage: DiagnosticMessage): boolean {
@@ -10435,11 +10454,12 @@ namespace ts {
1043510454 const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
1043610455 if (symbol) {
1043710456 if (symbol !== unknownSymbol && symbol !== argumentsSymbol) {
10438- if (symbol === undefinedSymbol || !(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Method | SymbolFlags.Accessor))) {
10457+ if (symbol === undefinedSymbol ||
10458+ !(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Method | SymbolFlags.Accessor))) {
1043910459 error(expr, invalidReferenceMessage);
1044010460 return false;
1044110461 }
10442- if (isConstantSymbol( symbol) || (isReadonlySymbol(symbol) && !isReferenceWithinOwnConstructor(expr , symbol) )) {
10462+ if (isReferenceToConstant(node, symbol) || isReferenceToReadonlyProperty(node , symbol)) {
1044310463 error(expr, constantVariableMessage);
1044410464 return false;
1044510465 }
0 commit comments