Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6f09705

Browse filesBrowse files
committed
Divergent get/set types and visibility
1 parent d33143c commit 6f09705
Copy full SHA for 6f09705

41 files changed

+3,164-157Lines changed: 3164 additions & 157 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+37-15Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25967,10 +25967,18 @@ namespace ts {
2596725967
*/
2596825968
function checkPropertyAccessibility(
2596925969
node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement,
25970-
isSuper: boolean, type: Type, prop: Symbol): boolean {
25971-
const flags = getDeclarationModifierFlagsFromSymbol(prop);
25970+
isSuper: boolean, type: Type, prop: Symbol, isWrite = false): boolean {
25971+
let flags = getDeclarationModifierFlagsFromSymbol(prop);
2597225972
const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : node.kind === SyntaxKind.ImportType ? node : node.name;
2597325973

25974+
// Writes use the visibility modifier of the set accessor, if one is declared
25975+
if (isWrite) {
25976+
const setter = forEach(prop.declarations, p => p.kind === SyntaxKind.SetAccessor && p);
25977+
if (setter) {
25978+
flags = (flags & ~ModifierFlags.AccessibilityModifier) | getEffectiveDeclarationFlags(setter, ModifierFlags.AccessibilityModifier);
25979+
}
25980+
}
25981+
2597425982
if (isSuper) {
2597525983
// TS 1.0 spec (April 2014): 4.8.2
2597625984
// - In a constructor, instance member function, instance member accessor, or
@@ -26285,7 +26293,7 @@ namespace ts {
2628526293
markAliasReferenced(parentSymbol, node);
2628626294
}
2628726295

26288-
let propType: Type;
26296+
let propType: Type | undefined;
2628926297
if (!prop) {
2629026298
const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined;
2629126299
if (!(indexInfo && indexInfo.type)) {
@@ -26316,19 +26324,30 @@ namespace ts {
2631626324
}
2631726325
}
2631826326
else {
26327+
const isWrite = isWriteAccess(node);
2631926328
if (getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(node, prop)) {
2632026329
errorOrSuggestion(/* isError */ false, right, Diagnostics._0_is_deprecated, right.escapedText as string);
2632126330
}
2632226331
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
2632326332
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
2632426333
getNodeLinks(node).resolvedSymbol = prop;
26325-
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
26334+
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop, isWrite);
2632626335
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
2632726336
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
2632826337
return errorType;
2632926338
}
26330-
propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node);
26339+
if (isWrite) {
26340+
const setter = forEach(prop.declarations, p => (p.kind === SyntaxKind.SetAccessor && p));
26341+
if (setter) {
26342+
propType = getAnnotatedAccessorType(setter as SetAccessorDeclaration);
26343+
}
26344+
}
26345+
26346+
if (propType === undefined) {
26347+
propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node);
26348+
}
2633126349
}
26350+
// For writes to properties declared as accessors, use the 'set' type
2633226351
return getFlowTypeOfAccessExpression(node, prop, propType, right);
2633326352
}
2633426353

@@ -32321,15 +32340,19 @@ namespace ts {
3232132340
const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
3232232341
const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node), otherKind);
3232332342
if (otherAccessor) {
32324-
const nodeFlags = getEffectiveModifierFlags(node);
32325-
const otherFlags = getEffectiveModifierFlags(otherAccessor);
32326-
if ((nodeFlags & ModifierFlags.Abstract) !== (otherFlags & ModifierFlags.Abstract)) {
32343+
const getter = node.kind === SyntaxKind.GetAccessor ? node : otherAccessor;
32344+
const setter = node.kind === SyntaxKind.SetAccessor ? node : otherAccessor;
32345+
const getterFlags = getEffectiveModifierFlags(getter);
32346+
const setterFlags = getEffectiveModifierFlags(setter);
32347+
if ((getterFlags & ModifierFlags.Abstract) !== (setterFlags & ModifierFlags.Abstract)) {
3232732348
error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
3232832349
}
32350+
if (((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) ||
32351+
((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private))) {
32352+
error(node.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter);
32353+
}
3232932354

32330-
// TypeScript 1.0 spec (April 2014): 4.5
32331-
// If both accessors include type annotations, the specified types must be identical.
32332-
checkAccessorDeclarationTypesAssignable(node, otherAccessor, getAnnotatedAccessorType, Diagnostics.get_and_set_accessor_must_have_the_comparable_types);
32355+
checkAccessorDeclarationTypesAssignable(getter, setter, getAnnotatedAccessorType, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type);
3233332356
checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
3233432357
}
3233532358
}
@@ -32345,8 +32368,8 @@ namespace ts {
3234532368
return checkAccessorDeclarationTypesMatch(first, second, getAnnotatedType, isTypeIdenticalTo, message);
3234632369
}
3234732370

32348-
function checkAccessorDeclarationTypesAssignable(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32349-
return checkAccessorDeclarationTypesMatch(first, second, getAnnotatedType, areTypesComparable, message);
32371+
function checkAccessorDeclarationTypesAssignable(getter: AccessorDeclaration, setter: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32372+
return checkAccessorDeclarationTypesMatch(getter, setter, getAnnotatedType, isTypeAssignableTo, message);
3235032373
}
3235132374

3235232375
function checkAccessorDeclarationTypesMatch(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, match: typeof areTypesComparable, message: DiagnosticMessage) {
@@ -32357,7 +32380,6 @@ namespace ts {
3235732380
}
3235832381
}
3235932382

32360-
3236132383
function checkMissingDeclaration(node: Node) {
3236232384
checkDecorators(node);
3236332385
}
@@ -40171,7 +40193,7 @@ namespace ts {
4017140193
}
4017240194

4017340195
function checkGrammarAccessor(accessor: AccessorDeclaration): boolean {
40174-
if (!(accessor.flags & NodeFlags.Ambient)) {
40196+
if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration)) {
4017540197
if (languageVersion < ScriptTarget.ES5) {
4017640198
return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher);
4017740199
}
Collapse file

‎src/compiler/diagnosticMessages.json‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticMessages.json
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,7 @@
16971697
"category": "Error",
16981698
"code": 2378
16991699
},
1700-
"'get' and 'set' accessor must have comparable types.": {
1700+
"The return type of a 'get' accessor must be assignable to its 'set' accessor type": {
17011701
"category": "Error",
17021702
"code": 2380
17031703
},
@@ -3231,6 +3231,10 @@
32313231
"category": "Error",
32323232
"code": 2797
32333233
},
3234+
"A get accessor must be at least as accessible as the setter": {
3235+
"category": "Error",
3236+
"code": 2798
3237+
},
32343238

32353239
"Import declaration '{0}' is using private name '{1}'.": {
32363240
"category": "Error",
Collapse file

‎src/compiler/parser.ts‎

Copy file name to clipboardExpand all lines: src/compiler/parser.ts
+14-1Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,8 @@ namespace ts {
13051305
}
13061306

13071307
function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void {
1308+
debugger;
1309+
13081310
// Don't report another error if it would just be at the same position as the last error.
13091311
const lastError = lastOrUndefined(parseDiagnostics);
13101312
if (!lastError || start !== lastError.start) {
@@ -3172,7 +3174,10 @@ namespace ts {
31723174

31733175
function isTypeMemberStart(): boolean {
31743176
// Return true if we have the start of a signature member
3175-
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
3177+
if (token() === SyntaxKind.OpenParenToken ||
3178+
token() === SyntaxKind.LessThanToken ||
3179+
token() === SyntaxKind.GetKeyword ||
3180+
token() === SyntaxKind.SetKeyword) {
31763181
return true;
31773182
}
31783183
let idToken = false;
@@ -3213,6 +3218,14 @@ namespace ts {
32133218
const pos = getNodePos();
32143219
const hasJSDoc = hasPrecedingJSDocComment();
32153220
const modifiers = parseModifiers();
3221+
if (parseContextualModifier(SyntaxKind.GetKeyword)) {
3222+
return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor);
3223+
}
3224+
3225+
if (parseContextualModifier(SyntaxKind.SetKeyword)) {
3226+
return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor);
3227+
}
3228+
32163229
if (isIndexSignature()) {
32173230
return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers);
32183231
}
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,19 +1453,19 @@ namespace ts {
14531453

14541454
// See the comment on MethodDeclaration for the intuition behind GetAccessorDeclaration being a
14551455
// ClassElement and an ObjectLiteralElement.
1456-
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
1456+
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
14571457
readonly kind: SyntaxKind.GetAccessor;
1458-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
1458+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
14591459
readonly name: PropertyName;
14601460
readonly body?: FunctionBody;
14611461
/* @internal */ typeParameters?: NodeArray<TypeParameterDeclaration>; // Present for use with reporting a grammar error
14621462
}
14631463

14641464
// See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a
14651465
// ClassElement and an ObjectLiteralElement.
1466-
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
1466+
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
14671467
readonly kind: SyntaxKind.SetAccessor;
1468-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
1468+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
14691469
readonly name: PropertyName;
14701470
readonly body?: FunctionBody;
14711471
/* @internal */ typeParameters?: NodeArray<TypeParameterDeclaration>; // Present for use with reporting a grammar error
Collapse file

‎tests/baselines/reference/abstractPropertyNegative.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/abstractPropertyNegative.errors.txt
+3-6Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: 'get' and 'set' accessor must have the same type.
2-
tests/cases/compiler/abstractPropertyNegative.ts(11,18): error TS2380: 'get' and 'set' accessor must have the same type.
1+
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
32
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
43
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
54
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
@@ -19,7 +18,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(40,9): error TS2676: Accessors
1918
tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors must both be abstract or non-abstract.
2019

2120

22-
==== tests/cases/compiler/abstractPropertyNegative.ts (16 errors) ====
21+
==== tests/cases/compiler/abstractPropertyNegative.ts (15 errors) ====
2322
interface A {
2423
prop: string;
2524
m(): string;
@@ -31,10 +30,8 @@ tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors
3130
abstract m(): string;
3231
abstract get mismatch(): string;
3332
~~~~~~~~
34-
!!! error TS2380: 'get' and 'set' accessor must have the same type.
33+
!!! error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
3534
abstract set mismatch(val: number); // error, not same type
36-
~~~~~~~~
37-
!!! error TS2380: 'get' and 'set' accessor must have the same type.
3835
}
3936
class C extends B {
4037
~
Collapse file

‎tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.errors.txt
-58Lines changed: 0 additions & 58 deletions
This file was deleted.
Collapse file

‎tests/baselines/reference/api/tsserverlibrary.d.ts‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/api/tsserverlibrary.d.ts
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -820,15 +820,15 @@ declare namespace ts {
820820
readonly kind: SyntaxKind.SemicolonClassElement;
821821
readonly parent: ClassLikeDeclaration;
822822
}
823-
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
823+
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
824824
readonly kind: SyntaxKind.GetAccessor;
825-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
825+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
826826
readonly name: PropertyName;
827827
readonly body?: FunctionBody;
828828
}
829-
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
829+
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
830830
readonly kind: SyntaxKind.SetAccessor;
831-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
831+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
832832
readonly name: PropertyName;
833833
readonly body?: FunctionBody;
834834
}
Collapse file

‎tests/baselines/reference/api/typescript.d.ts‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/api/typescript.d.ts
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -820,15 +820,15 @@ declare namespace ts {
820820
readonly kind: SyntaxKind.SemicolonClassElement;
821821
readonly parent: ClassLikeDeclaration;
822822
}
823-
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
823+
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
824824
readonly kind: SyntaxKind.GetAccessor;
825-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
825+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
826826
readonly name: PropertyName;
827827
readonly body?: FunctionBody;
828828
}
829-
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
829+
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
830830
readonly kind: SyntaxKind.SetAccessor;
831-
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
831+
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
832832
readonly name: PropertyName;
833833
readonly body?: FunctionBody;
834834
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.