Skip to content

Commit c320187

Browse files
authored
Revert "Revise accessor resolution logic and error reporting (microsoft#48459)"
This reverts commit df7ed82.
1 parent d962091 commit c320187

9 files changed

+127
-330
lines changed

src/compiler/checker.ts

Lines changed: 120 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ namespace ts {
172172
EnumTagType,
173173
ResolvedTypeArguments,
174174
ResolvedBaseTypes,
175-
WriteType,
176175
}
177176

178177
const enum CheckMode {
@@ -8530,8 +8529,6 @@ namespace ts {
85308529
return !!(target as TypeReference).resolvedTypeArguments;
85318530
case TypeSystemPropertyName.ResolvedBaseTypes:
85328531
return !!(target as InterfaceType).baseTypesResolved;
8533-
case TypeSystemPropertyName.WriteType:
8534-
return !!getSymbolLinks(target as Symbol).writeType;
85358532
}
85368533
return Debug.assertNever(propertyName);
85378534
}
@@ -9515,11 +9512,6 @@ namespace ts {
95159512
}
95169513
return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression)));
95179514
}
9518-
if (isAccessor(declaration)) {
9519-
// Binding of certain patterns in JS code will occasionally mark symbols as both properties
9520-
// and accessors. Here we dispatch to accessor resolution if needed.
9521-
return getTypeOfAccessors(symbol);
9522-
}
95239515

95249516
// Handle variable, parameter or property
95259517
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
@@ -9585,6 +9577,9 @@ namespace ts {
95859577
else if (isEnumMember(declaration)) {
95869578
type = getTypeOfEnumMember(symbol);
95879579
}
9580+
else if (isAccessor(declaration)) {
9581+
type = resolveTypeOfAccessors(symbol) || Debug.fail("Non-write accessor resolution must always produce a type");
9582+
}
95889583
else {
95899584
return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
95909585
}
@@ -9629,62 +9624,97 @@ namespace ts {
96299624

96309625
function getTypeOfAccessors(symbol: Symbol): Type {
96319626
const links = getSymbolLinks(symbol);
9632-
if (!links.type) {
9633-
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9634-
return errorType;
9635-
}
9627+
return links.type || (links.type = getTypeOfAccessorsWorker(symbol) || Debug.fail("Read type of accessor must always produce a type"));
9628+
}
9629+
9630+
function getTypeOfSetAccessor(symbol: Symbol): Type | undefined {
9631+
const links = getSymbolLinks(symbol);
9632+
return links.writeType || (links.writeType = getTypeOfAccessorsWorker(symbol, /*writing*/ true));
9633+
}
9634+
9635+
function getTypeOfAccessorsWorker(symbol: Symbol, writing = false): Type | undefined {
9636+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9637+
return errorType;
9638+
}
9639+
9640+
let type = resolveTypeOfAccessors(symbol, writing);
9641+
if (!popTypeResolution()) {
96369642
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
9637-
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9638-
// We try to resolve a getter type annotation, a setter type annotation, or a getter function
9639-
// body return type inference, in that order.
9640-
let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) ||
9641-
getAnnotatedAccessorType(getter) ||
9642-
getAnnotatedAccessorType(setter) ||
9643-
getter && getter.body && getReturnTypeFromBody(getter);
9644-
if (!type) {
9645-
if (setter && !isPrivateWithinAmbient(setter)) {
9646-
errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
9647-
}
9648-
else if (getter && !isPrivateWithinAmbient(getter)) {
9649-
errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
9650-
}
9651-
type = anyType;
9652-
}
9653-
if (!popTypeResolution()) {
9654-
if (getAnnotatedAccessorTypeNode(getter)) {
9655-
error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9643+
if (getter) {
9644+
if (getEffectiveTypeAnnotationNode(getter)) {
9645+
error(getter.name, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
96569646
}
9657-
else if (getAnnotatedAccessorTypeNode(setter)) {
9658-
error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9659-
}
9660-
else if (getter && noImplicitAny) {
9647+
else if (noImplicitAny) {
96619648
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
96629649
}
9663-
type = anyType;
96649650
}
9665-
links.type = type;
9651+
type = anyType;
96669652
}
9667-
return links.type;
9653+
return type;
96689654
}
96699655

9670-
function getWriteTypeOfAccessors(symbol: Symbol): Type {
9671-
const links = getSymbolLinks(symbol);
9672-
if (!links.writeType) {
9673-
if (!pushTypeResolution(symbol, TypeSystemPropertyName.WriteType)) {
9674-
return errorType;
9656+
function resolveTypeOfAccessors(symbol: Symbol, writing = false) {
9657+
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
9658+
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9659+
9660+
// For write operations, prioritize type annotations on the setter
9661+
if (writing) {
9662+
const setterType = getAnnotatedAccessorType(setter);
9663+
if (setterType) {
9664+
return instantiateTypeIfNeeded(setterType, symbol);
96759665
}
9676-
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9677-
let writeType = getAnnotatedAccessorType(setter);
9678-
if (!popTypeResolution()) {
9679-
if (getAnnotatedAccessorTypeNode(setter)) {
9680-
error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9681-
}
9682-
writeType = anyType;
9666+
}
9667+
// Else defer to the getter type
9668+
9669+
if (getter && isInJSFile(getter)) {
9670+
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
9671+
if (jsDocType) {
9672+
return instantiateTypeIfNeeded(jsDocType, symbol);
96839673
}
9684-
// Absent an explicit setter type annotation we use the read type of the accessor.
9685-
links.writeType = writeType || getTypeOfAccessors(symbol);
96869674
}
9687-
return links.writeType;
9675+
9676+
// Try to see if the user specified a return type on the get-accessor.
9677+
const getterType = getAnnotatedAccessorType(getter);
9678+
if (getterType) {
9679+
return instantiateTypeIfNeeded(getterType, symbol);
9680+
}
9681+
9682+
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
9683+
const setterType = getAnnotatedAccessorType(setter);
9684+
if (setterType) {
9685+
return setterType;
9686+
}
9687+
9688+
// If there are no specified types, try to infer it from the body of the get accessor if it exists.
9689+
if (getter && getter.body) {
9690+
const returnTypeFromBody = getReturnTypeFromBody(getter);
9691+
return instantiateTypeIfNeeded(returnTypeFromBody, symbol);
9692+
}
9693+
9694+
// Otherwise, fall back to 'any'.
9695+
if (setter) {
9696+
if (!isPrivateWithinAmbient(setter)) {
9697+
errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
9698+
}
9699+
return anyType;
9700+
}
9701+
else if (getter) {
9702+
Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
9703+
if (!isPrivateWithinAmbient(getter)) {
9704+
errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
9705+
}
9706+
return anyType;
9707+
}
9708+
return undefined;
9709+
9710+
function instantiateTypeIfNeeded(type: Type, symbol: Symbol) {
9711+
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
9712+
const links = getSymbolLinks(symbol);
9713+
return instantiateType(type, links.mapper);
9714+
}
9715+
9716+
return type;
9717+
}
96889718
}
96899719

96909720
function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -9772,12 +9802,17 @@ namespace ts {
97729802

97739803
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
97749804
const links = getSymbolLinks(symbol);
9775-
return links.type || (links.type = instantiateType(getTypeOfSymbol(links.target!), links.mapper));
9776-
}
9777-
9778-
function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type {
9779-
const links = getSymbolLinks(symbol);
9780-
return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper));
9805+
if (!links.type) {
9806+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9807+
return links.type = errorType;
9808+
}
9809+
let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper);
9810+
if (!popTypeResolution()) {
9811+
type = reportCircularityError(symbol);
9812+
}
9813+
links.type = type;
9814+
}
9815+
return links.type;
97819816
}
97829817

97839818
function reportCircularityError(symbol: Symbol) {
@@ -9820,23 +9855,36 @@ namespace ts {
98209855
}
98219856

98229857
/**
9823-
* Distinct write types come only from set accessors, but synthetic union and intersection
9824-
* properties deriving from set accessors will either pre-compute or defer the union or
9825-
* intersection of the writeTypes of their constituents.
9858+
* Distinct write types come only from set accessors, but union and intersection
9859+
* properties deriving from set accessors will either pre-compute or defer the
9860+
* union or intersection of the writeTypes of their constituents. To account for
9861+
* this, we will assume that any deferred type or transient symbol may have a
9862+
* `writeType` (or a deferred write type ready to be computed) that should be
9863+
* used before looking for set accessor declarations.
98269864
*/
98279865
function getWriteTypeOfSymbol(symbol: Symbol): Type {
98289866
const checkFlags = getCheckFlags(symbol);
9829-
if (symbol.flags & SymbolFlags.Property) {
9830-
return checkFlags & CheckFlags.SyntheticProperty ?
9831-
checkFlags & CheckFlags.DeferredType ?
9832-
getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) :
9833-
(symbol as TransientSymbol).writeType || (symbol as TransientSymbol).type! :
9834-
getTypeOfSymbol(symbol);
9867+
if (checkFlags & CheckFlags.DeferredType) {
9868+
const writeType = getWriteTypeOfSymbolWithDeferredType(symbol);
9869+
if (writeType) {
9870+
return writeType;
9871+
}
9872+
}
9873+
if (symbol.flags & SymbolFlags.Transient) {
9874+
const { writeType } = symbol as TransientSymbol;
9875+
if (writeType) {
9876+
return writeType;
9877+
}
98359878
}
9879+
return getSetAccessorTypeOfSymbol(symbol);
9880+
}
9881+
9882+
function getSetAccessorTypeOfSymbol(symbol: Symbol): Type {
98369883
if (symbol.flags & SymbolFlags.Accessor) {
9837-
return checkFlags & CheckFlags.Instantiated ?
9838-
getWriteTypeOfInstantiatedSymbol(symbol) :
9839-
getWriteTypeOfAccessors(symbol);
9884+
const type = getTypeOfSetAccessor(symbol);
9885+
if (type) {
9886+
return type;
9887+
}
98409888
}
98419889
return getTypeOfSymbol(symbol);
98429890
}
@@ -25199,7 +25247,7 @@ namespace ts {
2519925247
}
2520025248
}
2520125249
if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) {
25202-
return getWriteTypeOfAccessors(location.parent.symbol);
25250+
return resolveTypeOfAccessors(location.parent.symbol, /*writing*/ true)!;
2520325251
}
2520425252
// The location isn't a reference to the given symbol, meaning we're being asked
2520525253
// a hypothetical question of what type the symbol would have if there was a reference

src/compiler/utilitiesPublic.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,9 +1335,7 @@ namespace ts {
13351335
|| kind === SyntaxKind.CallSignature
13361336
|| kind === SyntaxKind.PropertySignature
13371337
|| kind === SyntaxKind.MethodSignature
1338-
|| kind === SyntaxKind.IndexSignature
1339-
|| kind === SyntaxKind.GetAccessor
1340-
|| kind === SyntaxKind.SetAccessor;
1338+
|| kind === SyntaxKind.IndexSignature;
13411339
}
13421340

13431341
export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {

tests/baselines/reference/circularAccessorAnnotations.errors.txt

Lines changed: 0 additions & 41 deletions
This file was deleted.

tests/baselines/reference/circularAccessorAnnotations.js

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)