Merge pull request #602 from Microsoft/noImplicitAnyOnCast

Do not show noImplictAny errors when widening for a cast expression
This commit is contained in:
Mohamed Hegazy 2014-09-08 17:28:49 -07:00
commit 6fee404152
4 changed files with 113 additions and 50 deletions

View File

@ -3132,45 +3132,6 @@ module ts {
return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
}
function getWidenedTypeOfObjectLiteral(type: Type): Type {
var properties = getPropertiesOfType(type);
if (properties.length) {
var widenedTypes: Type[] = [];
var propTypeWasWidened: boolean = false;
forEach(properties, p => {
var propType = getTypeOfSymbol(p);
var widenedType = getWidenedType(propType);
if (propType !== widenedType) {
propTypeWasWidened = true;
if (program.getCompilerOptions().noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType));
}
}
widenedTypes.push(widenedType);
});
if (propTypeWasWidened) {
var members: SymbolTable = {};
var index = 0;
forEach(properties, p => {
var symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, p.name);
symbol.declarations = p.declarations;
symbol.parent = p.parent;
symbol.type = widenedTypes[index++];
symbol.target = p;
if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
members[symbol.name] = symbol;
});
var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
if (stringIndexType) stringIndexType = getWidenedType(stringIndexType);
if (numberIndexType) numberIndexType = getWidenedType(numberIndexType);
type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType);
}
}
return type;
}
function isArrayType(type: Type): boolean {
return type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType;
}
@ -3183,17 +3144,8 @@ module ts {
return type;
}
function getWidenedTypeOfArrayLiteral(type: Type): Type {
var elementType = (<TypeReference>type).typeArguments[0];
var widenedType = getWidenedType(elementType);
type = elementType !== widenedType ? createArrayType(widenedType) : type;
return type;
}
/* If we are widening on a literal, then we may need to the 'node' parameter for reporting purposes */
function getWidenedType(type: Type): Type {
function getWidenedType(type: Type, supressNoImplicitAnyErrors?: boolean): Type {
if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
return anyType;
}
@ -3204,6 +3156,54 @@ module ts {
return getWidenedTypeOfArrayLiteral(type);
}
return type;
function getWidenedTypeOfObjectLiteral(type: Type): Type {
var properties = getPropertiesOfType(type);
if (properties.length) {
var widenedTypes: Type[] = [];
var propTypeWasWidened: boolean = false;
forEach(properties, p => {
var propType = getTypeOfSymbol(p);
var widenedType = getWidenedType(propType);
if (propType !== widenedType) {
propTypeWasWidened = true;
if (!supressNoImplicitAnyErrors && program.getCompilerOptions().noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType));
}
}
widenedTypes.push(widenedType);
});
if (propTypeWasWidened) {
var members: SymbolTable = {};
var index = 0;
forEach(properties, p => {
var symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, p.name);
symbol.declarations = p.declarations;
symbol.parent = p.parent;
symbol.type = widenedTypes[index++];
symbol.target = p;
if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
members[symbol.name] = symbol;
});
var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
if (stringIndexType) stringIndexType = getWidenedType(stringIndexType);
if (numberIndexType) numberIndexType = getWidenedType(numberIndexType);
type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType);
}
}
return type;
}
function getWidenedTypeOfArrayLiteral(type: Type): Type {
var elementType = (<TypeReference>type).typeArguments[0];
var widenedType = getWidenedType(elementType, supressNoImplicitAnyErrors);
type = elementType !== widenedType ? createArrayType(widenedType) : type;
return type;
}
}
function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) {
@ -4329,7 +4329,7 @@ module ts {
var exprType = checkExpression(node.operand);
var targetType = getTypeFromTypeNode(node.type);
if (fullTypeCheck && targetType !== unknownType) {
var widenedType = getWidenedType(exprType);
var widenedType = getWidenedType(exprType, /*supressNoImplicitAnyErrors*/ true);
if (!(isTypeAssignableTo(targetType, widenedType))) {
checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
}

View File

@ -0,0 +1,20 @@
==== tests/cases/compiler/noImplicitAnyInCastExpression.ts (1 errors) ====
// verify no noImplictAny errors reported with cast expression
interface IFoo {
a: number;
b: string;
}
// Expr type not assignable to target type
(<IFoo>{ a: null });
// Expr type assignable to target type
(<IFoo>{ a: 2, b: undefined });
// Neither types is assignable to each other
(<IFoo>{ c: null });
~~~~~~~~~~~~~~~~~
!!! Neither type '{ c: null; }' nor type 'IFoo' is assignable to the other:
!!! Property 'a' is missing in type '{ c: null; }'.

View File

@ -0,0 +1,26 @@
//// [noImplicitAnyInCastExpression.ts]
// verify no noImplictAny errors reported with cast expression
interface IFoo {
a: number;
b: string;
}
// Expr type not assignable to target type
(<IFoo>{ a: null });
// Expr type assignable to target type
(<IFoo>{ a: 2, b: undefined });
// Neither types is assignable to each other
(<IFoo>{ c: null });
//// [noImplicitAnyInCastExpression.js]
// verify no noImplictAny errors reported with cast expression
// Expr type not assignable to target type
{ a: null };
// Expr type assignable to target type
{ a: 2, b: undefined };
// Neither types is assignable to each other
{ c: null };

View File

@ -0,0 +1,17 @@
//@noImplicitAny: true
// verify no noImplictAny errors reported with cast expression
interface IFoo {
a: number;
b: string;
}
// Expr type not assignable to target type
(<IFoo>{ a: null });
// Expr type assignable to target type
(<IFoo>{ a: 2, b: undefined });
// Neither types is assignable to each other
(<IFoo>{ c: null });