No readonly checks in type relationships + No assignments through namespace imports

This commit is contained in:
Anders Hejlsberg 2016-01-23 15:35:33 -08:00
parent e5063786ec
commit ee0060bb2f
2 changed files with 22 additions and 55 deletions

View file

@ -5641,13 +5641,6 @@ namespace ts {
}
return Ternary.False;
}
if (isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp)) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_read_only_in_type_1_but_writable_in_type_2,
symbolToString(targetProp), typeToString(source), typeToString(target));
}
return Ternary.False;
}
}
}
}
@ -5780,13 +5773,6 @@ namespace ts {
}
return Ternary.False;
}
if (sourceInfo.isReadonly && !targetInfo.isReadonly) {
if (reportErrors) {
reportError(Diagnostics.Index_signature_is_read_only_in_type_0_but_writable_in_type_1,
typeToString(source), typeToString(target));
}
return Ternary.False;
}
return related;
}
return Ternary.True;
@ -5826,13 +5812,6 @@ namespace ts {
}
return Ternary.False;
}
if ((sourceStringInfo && sourceStringInfo.isReadonly || sourceNumberInfo && sourceNumberInfo.isReadonly) && !targetInfo.isReadonly) {
if (reportErrors) {
reportError(Diagnostics.Index_signature_is_read_only_in_type_0_but_writable_in_type_1,
typeToString(source), typeToString(target));
}
return Ternary.False;
}
return related;
}
return Ternary.True;
@ -10401,36 +10380,19 @@ namespace ts {
}
function isReadonlySymbol(symbol: Symbol): boolean {
return symbol.flags & SymbolFlags.Property && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Readonly) !== 0;
return symbol.flags & SymbolFlags.Property && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Readonly) !== 0 ||
symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor);
}
function isReferenceToConstant(expr: Expression, symbol: Symbol): boolean {
if (symbol.flags & SymbolFlags.Variable) {
// A variable declared with 'const' is considered constant.
if (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) {
return true;
}
// An exported variable declared in an external module and accessed through a property
// or element access is considered constant.
if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
if (symbol.parent && symbol.parent.flags & SymbolFlags.ValueModule) {
const declaration = symbol.parent.valueDeclaration;
return declaration && (declaration.kind === SyntaxKind.SourceFile ||
declaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>declaration).name.kind === SyntaxKind.StringLiteral);
}
}
}
if (symbol.flags & SymbolFlags.Accessor) {
// An get accessor with no corresponding set accessor is considered constant.
return !(symbol.flags & SymbolFlags.SetAccessor);
}
return false;
function isConstantSymbol(symbol: Symbol): boolean {
return symbol.flags & SymbolFlags.Variable && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0;
}
function isReferenceToReadonlyProperty(expr: Expression, symbol: Symbol): boolean {
if (isReadonlySymbol(symbol)) {
// Allow assignments to readonly properties within constructors of the same class declaration.
if ((expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
if (symbol.flags & SymbolFlags.Property &&
(expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
(expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
const func = getContainingFunction(expr);
return !(func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent);
@ -10440,6 +10402,20 @@ namespace ts {
return false;
}
function isReferenceThroughNamespaceImport(expr: Expression): boolean {
if (expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
const node = skipParenthesizedNodes((expr as PropertyAccessExpression | ElementAccessExpression).expression);
if (node.kind === SyntaxKind.Identifier) {
const symbol = getNodeLinks(node).resolvedSymbol;
if (symbol.flags & SymbolFlags.Alias) {
const declaration = getDeclarationOfAliasSymbol(symbol);
return declaration && declaration.kind === SyntaxKind.NamespaceImport;
}
}
}
return false;
}
function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, constantVariableMessage: DiagnosticMessage): boolean {
// References are combinations of identifiers, parentheses, and property accesses.
const node = skipParenthesizedNodes(expr);
@ -10454,12 +10430,11 @@ namespace ts {
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
if (symbol) {
if (symbol !== unknownSymbol && symbol !== argumentsSymbol) {
if (symbol === undefinedSymbol ||
!(symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Method | SymbolFlags.Accessor))) {
if (node.kind === SyntaxKind.Identifier && !(symbol.flags & SymbolFlags.Variable) || symbol.flags & SymbolFlags.EnumMember) {
error(expr, invalidReferenceMessage);
return false;
}
if (isReferenceToConstant(node, symbol) || isReferenceToReadonlyProperty(node, symbol)) {
if (isConstantSymbol(symbol) || isReferenceToReadonlyProperty(node, symbol) || isReferenceThroughNamespaceImport(node)) {
error(expr, constantVariableMessage);
return false;
}

View file

@ -995,10 +995,6 @@
"category": "Error",
"code": 2342
},
"Property '{0}' is read-only in type '{1}' but writable in type '{2}'.": {
"category": "Error",
"code": 2343
},
"Type '{0}' does not satisfy the constraint '{1}'.": {
"category": "Error",
"code": 2344
@ -1087,10 +1083,6 @@
"category": "Error",
"code": 2365
},
"Index signature is read-only in type '{0}' but writable in type '{1}'.": {
"category": "Error",
"code": 2366
},
"Type parameter name cannot be '{0}'": {
"category": "Error",
"code": 2368