Lock down computed names in object literals and classes under --isolatedDeclarations (#58596)

This commit is contained in:
Wesley Wigham
2024-05-22 12:28:07 -07:00
committed by GitHub
parent 9370347f5b
commit b682ed4504
15 changed files with 342 additions and 77 deletions
-21
View File
@@ -1504,7 +1504,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var syntacticNodeBuilder = createSyntacticTypeNodeBuilder(compilerOptions, {
isEntityNameVisible,
isExpandoFunctionDeclaration,
isNonNarrowedBindableName,
getAllAccessorDeclarations: getAllAccessorDeclarationsForDeclaration,
requiresAddingImplicitUndefined,
isUndefinedIdentifierExpression(node: Identifier) {
@@ -49118,25 +49117,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
return false;
}
function isNonNarrowedBindableName(node: ComputedPropertyName) {
if (!hasBindableName(node.parent)) {
return false;
}
const expression = node.expression;
if (!isEntityNameExpression(expression)) {
return true;
}
const type = getTypeOfExpression(expression);
const symbol = getSymbolAtLocation(expression);
if (!symbol) {
return false;
}
// Ensure not type narrowing
const declaredType = getTypeOfSymbol(symbol);
return declaredType === type;
}
function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression {
const enumResult = type.flags & TypeFlags.EnumLike ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, tracker)
@@ -49262,7 +49242,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return node && getExternalModuleFileFromDeclaration(node);
},
isLiteralConstDeclaration,
isNonNarrowedBindableName,
isLateBound: (nodeIn: Declaration): nodeIn is LateBoundDeclaration => {
const node = getParseTreeNode(nodeIn, isDeclaration);
const symbol = node && getSymbolOfDeclaration(node);
+4
View File
@@ -7014,6 +7014,10 @@
"category": "Error",
"code": 9037
},
"Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.": {
"category": "Error",
"code": 9038
},
"JSX attributes must only be assigned a non-empty 'expression'.": {
"category": "Error",
"code": 17000
-1
View File
@@ -1123,7 +1123,6 @@ export const notImplementedResolver: EmitResolver = {
isArgumentsLocalBinding: notImplemented,
getExternalModuleFileFromDeclaration: notImplemented,
isLiteralConstDeclaration: notImplemented,
isNonNarrowedBindableName: notImplemented,
getJsxFactoryEntity: notImplemented,
getJsxFragmentFactoryEntity: notImplemented,
isBindingCapturedByNode: notImplemented,
+1 -14
View File
@@ -26,7 +26,6 @@ import {
isBlock,
isConstTypeReference,
isDeclarationReadonly,
isEntityNameExpression,
isGetAccessor,
isIdentifier,
isJSDocTypeAssertion,
@@ -55,7 +54,6 @@ import {
PropertySignature,
SetAccessorDeclaration,
SignatureDeclaration,
SymbolAccessibility,
SyntacticTypeNodeBuilderContext,
SyntacticTypeNodeBuilderResolver,
SyntaxKind,
@@ -351,7 +349,7 @@ export function createSyntacticTypeNodeBuilder(options: CompilerOptions, resolve
}
else if (prop.name.kind === SyntaxKind.ComputedPropertyName) {
const expression = prop.name.expression;
if (!isPrimitiveLiteralValue(expression, /*includeBigInt*/ false) && !isEntityNameExpression(expression)) {
if (!isPrimitiveLiteralValue(expression, /*includeBigInt*/ false)) {
context.tracker.reportInferenceFallback(prop.name);
result = false;
}
@@ -367,17 +365,6 @@ export function createSyntacticTypeNodeBuilder(options: CompilerOptions, resolve
Debug.assert(!isShorthandPropertyAssignment(prop) && !isSpreadAssignment(prop));
const name = prop.name;
if (prop.name.kind === SyntaxKind.ComputedPropertyName) {
if (!resolver.isNonNarrowedBindableName(prop.name)) {
context.tracker.reportInferenceFallback(prop.name);
}
else if (isEntityNameExpression(prop.name.expression)) {
const visibilityResult = resolver.isEntityNameVisible(prop.name.expression, context.enclosingDeclaration!, /*shouldComputeAliasToMakeVisible*/ false);
if (visibilityResult.accessibility !== SymbolAccessibility.Accessible) {
context.tracker.reportInferenceFallback(prop.name);
}
}
}
switch (prop.kind) {
case SyntaxKind.MethodDeclaration:
canInferObjectLiteral = !!typeFromObjectLiteralMethod(prop, name, context) && canInferObjectLiteral;
+12 -7
View File
@@ -139,6 +139,7 @@ import {
isTupleTypeNode,
isTypeAliasDeclaration,
isTypeElement,
isTypeLiteralNode,
isTypeNode,
isTypeParameterDeclaration,
isTypeQueryNode,
@@ -995,16 +996,20 @@ export function transformDeclarations(context: TransformationContext) {
if (shouldStripInternal(input)) return;
if (isDeclaration(input)) {
if (isDeclarationAndNotVisible(input)) return;
if (hasDynamicName(input) && !resolver.isLateBound(getParseTreeNode(input) as Declaration)) {
if (hasDynamicName(input)) {
if (
isolatedDeclarations
// Classes usually elide properties with computed names that are not of a literal type
// Classes and object literals usually elide properties with computed names that are not of a literal type
// In isolated declarations TSC needs to error on these as we don't know the type in a DTE.
&& isClassDeclaration(input.parent)
&& isEntityNameExpression(input.name.expression)
// If the symbol is not accessible we get another TS error no need to add to that
&& resolver.isEntityNameVisible(input.name.expression, input.parent).accessibility === SymbolAccessibility.Accessible
&& !resolver.isNonNarrowedBindableName(input.name)
&& (isClassDeclaration(input.parent) || isObjectLiteralExpression(input.parent))
) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations));
}
if (
isolatedDeclarations
// Type declarations just need to double-check that the input computed name is an entity name expression
&& (isInterfaceDeclaration(input.parent) || isTypeLiteralNode(input.parent))
&& !isEntityNameExpression(input.name.expression)
) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations));
}
@@ -623,7 +623,7 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
[SyntaxKind.VariableDeclaration]: Diagnostics.Variable_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.PropertyDeclaration]: Diagnostics.Property_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.PropertySignature]: Diagnostics.Property_must_have_an_explicit_type_annotation_with_isolatedDeclarations,
[SyntaxKind.ComputedPropertyName]: Diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations,
[SyntaxKind.ComputedPropertyName]: Diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations,
[SyntaxKind.SpreadAssignment]: Diagnostics.Objects_that_contain_spread_assignments_can_t_be_inferred_with_isolatedDeclarations,
[SyntaxKind.ShorthandPropertyAssignment]: Diagnostics.Objects_that_contain_shorthand_properties_can_t_be_inferred_with_isolatedDeclarations,
[SyntaxKind.ArrayLiteralExpression]: Diagnostics.Only_const_arrays_can_be_inferred_with_isolatedDeclarations,
-2
View File
@@ -5754,7 +5754,6 @@ export enum TypeReferenceSerializationKind {
/** @internal */
export interface EmitResolver {
isNonNarrowedBindableName(node: ComputedPropertyName): boolean;
hasGlobalName(name: string): boolean;
getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined;
getReferencedImportDeclaration(node: Identifier): Declaration | undefined;
@@ -10291,7 +10290,6 @@ export interface SyntacticTypeNodeBuilderContext {
/** @internal */
export interface SyntacticTypeNodeBuilderResolver {
isUndefinedIdentifierExpression(name: Identifier): boolean;
isNonNarrowedBindableName(name: ComputedPropertyName): boolean;
isExpandoFunctionDeclaration(name: FunctionDeclaration | VariableDeclaration): boolean;
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
@@ -121,6 +121,7 @@ const errorCodes = [
Diagnostics.Property_must_have_an_explicit_type_annotation_with_isolatedDeclarations.code,
Diagnostics.Expression_type_can_t_be_inferred_with_isolatedDeclarations.code,
Diagnostics.Binding_elements_can_t_be_exported_directly_with_isolatedDeclarations.code,
Diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations.code,
Diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations.code,
Diagnostics.Enum_member_initializers_must_be_computable_without_references_to_external_symbols_with_isolatedDeclarations.code,
Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations.code,