mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-26 10:43:51 -05:00
fix(54465): Broken emit with private field in class decorator (#54679)
This commit is contained in:
@@ -248,6 +248,7 @@ import {
|
||||
getCombinedModifierFlags,
|
||||
getCombinedNodeFlags,
|
||||
getContainingClass,
|
||||
getContainingClassExcludingClassDecorators,
|
||||
getContainingClassStaticBlock,
|
||||
getContainingFunction,
|
||||
getContainingFunctionOrClassStaticBlock,
|
||||
@@ -31407,7 +31408,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
// Lookup the private identifier lexically.
|
||||
function lookupSymbolForPrivateIdentifierDeclaration(propName: __String, location: Node): Symbol | undefined {
|
||||
for (let containingClass = getContainingClass(location); !!containingClass; containingClass = getContainingClass(containingClass)) {
|
||||
for (let containingClass = getContainingClassExcludingClassDecorators(location); !!containingClass; containingClass = getContainingClass(containingClass)) {
|
||||
const { symbol } = containingClass;
|
||||
const name = getSymbolNameForPrivateIdentifier(symbol, propName);
|
||||
const prop = (symbol.members && symbol.members.get(name)) || (symbol.exports && symbol.exports.get(name));
|
||||
@@ -31547,23 +31548,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) {
|
||||
grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right));
|
||||
}
|
||||
|
||||
if (isAnyLike) {
|
||||
if (lexicallyScopedSymbol) {
|
||||
return isErrorType(apparentType) ? errorType : apparentType;
|
||||
}
|
||||
if (!getContainingClass(right)) {
|
||||
if (getContainingClassExcludingClassDecorators(right) === undefined) {
|
||||
grammarErrorOnNode(right, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
|
||||
return anyType;
|
||||
}
|
||||
}
|
||||
prop = lexicallyScopedSymbol ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol) : undefined;
|
||||
// Check for private-identifier-specific shadowing and lexical-scoping errors.
|
||||
if (!prop && checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) {
|
||||
return errorType;
|
||||
|
||||
prop = lexicallyScopedSymbol && getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedSymbol);
|
||||
if (prop === undefined) {
|
||||
// Check for private-identifier-specific shadowing and lexical-scoping errors.
|
||||
if (checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) {
|
||||
return errorType;
|
||||
}
|
||||
const containingClass = getContainingClassExcludingClassDecorators(right);
|
||||
if (containingClass && isPlainJsFile(getSourceFileOfNode(containingClass), compilerOptions.checkJs)) {
|
||||
grammarErrorOnNode(right, Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, idText(right));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
|
||||
const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
|
||||
if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) {
|
||||
error(node, Diagnostics.Private_accessor_was_defined_without_a_getter);
|
||||
}
|
||||
|
||||
@@ -315,6 +315,10 @@
|
||||
"category": "Error",
|
||||
"code": 1110
|
||||
},
|
||||
"Private field '{0}' must be declared in an enclosing class.": {
|
||||
"category": "Error",
|
||||
"code": 1111
|
||||
},
|
||||
"A 'default' clause cannot appear more than once in a 'switch' statement.": {
|
||||
"category": "Error",
|
||||
"code": 1113
|
||||
|
||||
@@ -1430,6 +1430,7 @@ export const plainJSErrors: Set<number> = new Set([
|
||||
Diagnostics.Class_constructor_may_not_be_an_accessor.code,
|
||||
Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code,
|
||||
Diagnostics.await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code,
|
||||
Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class.code,
|
||||
// Type errors
|
||||
Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value.code,
|
||||
]);
|
||||
|
||||
@@ -2838,6 +2838,12 @@ export function getContainingFunctionOrClassStaticBlock(node: Node): SignatureDe
|
||||
return findAncestor(node.parent, isFunctionLikeOrClassStaticBlockDeclaration);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getContainingClassExcludingClassDecorators(node: Node): ClassLikeDeclaration | undefined {
|
||||
const decorator = findAncestor(node.parent, n => isClassLike(n) ? "quit" : isDecorator(n));
|
||||
return decorator && isClassLike(decorator.parent) ? getContainingClass(decorator.parent) : getContainingClass(decorator ?? node);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type ThisContainer =
|
||||
| FunctionDeclaration
|
||||
|
||||
Reference in New Issue
Block a user