Skip to content

Commit 41c2054

Browse files
committed
Improve unification by moving more logic to getIndexedAccessType
1 parent 6b28d21 commit 41c2054

File tree

1 file changed

+19
-54
lines changed

1 file changed

+19
-54
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5738,14 +5738,24 @@ namespace ts {
57385738
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
57395739
}
57405740

5741-
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
5741+
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
57425742
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
5743-
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
5744-
const prop = getPropertyOfType(objectType, escapeIdentifier((<LiteralType>indexType).text));
5743+
const propName = indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral) ?
5744+
(<LiteralType>indexType).text :
5745+
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
5746+
getPropertyNameForKnownSymbolName((<Identifier>(<PropertyAccessExpression>accessExpression.argumentExpression).name).text) :
5747+
undefined;
5748+
if (propName) {
5749+
const prop = getPropertyOfType(objectType, propName);
57455750
if (prop) {
5746-
if (accessExpression && isAssignmentTarget(accessExpression) && isReadonlySymbol(prop)) {
5747-
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
5748-
return unknownType;
5751+
if (accessExpression) {
5752+
if (isAssignmentTarget(accessExpression) && (isReferenceToReadonlyEntity(accessExpression, prop) || isReferenceThroughNamespaceImport(accessExpression))) {
5753+
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, symbolToString(prop));
5754+
return unknownType;
5755+
}
5756+
if (cacheSymbol) {
5757+
getNodeLinks(accessNode).resolvedSymbol = prop;
5758+
}
57495759
}
57505760
return getTypeOfSymbol(prop);
57515761
}
@@ -5798,18 +5808,19 @@ namespace ts {
57985808
}
57995809
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>indexType);
58005810
}
5811+
const apparentType = getApparentType(objectType);
58015812
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Primitive)) {
58025813
const propTypes: Type[] = [];
58035814
for (const t of (<UnionType>indexType).types) {
5804-
const propType = getPropertyTypeForIndexType(objectType, t, accessNode);
5815+
const propType = getPropertyTypeForIndexType(apparentType, t, accessNode, /*cacheSymbol*/ false);
58055816
if (propType === unknownType) {
58065817
return unknownType;
58075818
}
58085819
propTypes.push(propType);
58095820
}
58105821
return getUnionType(propTypes);
58115822
}
5812-
return getPropertyTypeForIndexType(objectType, indexType, accessNode);
5823+
return getPropertyTypeForIndexType(apparentType, indexType, accessNode, /*cacheSymbol*/ true);
58135824
}
58145825

58155826
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
@@ -11644,55 +11655,9 @@ namespace ts {
1164411655
return unknownType;
1164511656
}
1164611657

11647-
const propName = getPropertyNameForIndexedAccess(indexExpression, indexType);
11648-
if (propName !== undefined) {
11649-
const prop = getPropertyOfType(getApparentType(objectType), propName);
11650-
if (prop) {
11651-
getNodeLinks(node).resolvedSymbol = prop;
11652-
if (isAssignmentTarget(node)) {
11653-
if (isReferenceToReadonlyEntity(<Expression>node, prop) || isReferenceThroughNamespaceImport(<Expression>node)) {
11654-
error(indexExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, propName);
11655-
return unknownType;
11656-
}
11657-
}
11658-
return getTypeOfSymbol(prop);
11659-
}
11660-
}
11661-
1166211658
return getIndexedAccessType(objectType, indexType, node);
1166311659
}
1166411660

11665-
/**
11666-
* If indexArgumentExpression is a string literal or number literal, returns its text.
11667-
* If indexArgumentExpression is a constant value, returns its string value.
11668-
* If indexArgumentExpression is a well known symbol, returns the property name corresponding
11669-
* to this symbol, as long as it is a proper symbol reference.
11670-
* Otherwise, returns undefined.
11671-
*/
11672-
function getPropertyNameForIndexedAccess(indexExpression: Expression, indexType: Type): string {
11673-
if (indexExpression.kind === SyntaxKind.StringLiteral || indexExpression.kind === SyntaxKind.NumericLiteral) {
11674-
return (<LiteralExpression>indexExpression).text;
11675-
}
11676-
if (indexExpression.kind === SyntaxKind.ElementAccessExpression || indexExpression.kind === SyntaxKind.PropertyAccessExpression) {
11677-
const value = getConstantValue(<ElementAccessExpression | PropertyAccessExpression>indexExpression);
11678-
if (value !== undefined) {
11679-
return value.toString();
11680-
}
11681-
}
11682-
if (checkThatExpressionIsProperSymbolReference(indexExpression, indexType, /*reportError*/ false)) {
11683-
const rightHandSideName = (<Identifier>(<PropertyAccessExpression>indexExpression).name).text;
11684-
return getPropertyNameForKnownSymbolName(rightHandSideName);
11685-
}
11686-
return undefined;
11687-
}
11688-
11689-
/**
11690-
* A proper symbol reference requires the following:
11691-
* 1. The property access denotes a property that exists
11692-
* 2. The expression is of the form Symbol.<identifier>
11693-
* 3. The property access is of the primitive type symbol.
11694-
* 4. Symbol in this context resolves to the global Symbol object
11695-
*/
1169611661
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
1169711662
if (expressionType === unknownType) {
1169811663
// There is already an error, so no need to report one.

0 commit comments

Comments
 (0)