Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variant accessors #42425

Merged
merged 20 commits into from
Mar 27, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 94 additions & 58 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1706,11 +1706,7 @@
"category": "Error",
"code": 2378
},
"Getter and setter accessors do not agree in visibility.": {
"category": "Error",
"code": 2379
},
"'get' and 'set' accessor must have the same type.": {
"The return type of a 'get' accessor must be assignable to its 'set' accessor type": {
"category": "Error",
"code": 2380
},
Expand Down Expand Up @@ -3308,6 +3304,10 @@
"category": "Error",
"code": 2807
},
"A get accessor must be at least as accessible as the setter": {
"category": "Error",
"code": 2808
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
13 changes: 12 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3213,7 +3213,10 @@ namespace ts {

function isTypeMemberStart(): boolean {
// Return true if we have the start of a signature member
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
if (token() === SyntaxKind.OpenParenToken ||
token() === SyntaxKind.LessThanToken ||
token() === SyntaxKind.GetKeyword ||
token() === SyntaxKind.SetKeyword) {
return true;
}
let idToken = false;
Expand Down Expand Up @@ -3254,6 +3257,14 @@ namespace ts {
const pos = getNodePos();
const hasJSDoc = hasPrecedingJSDocComment();
const modifiers = parseModifiers();
if (parseContextualModifier(SyntaxKind.GetKeyword)) {
return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor);
}

if (parseContextualModifier(SyntaxKind.SetKeyword)) {
return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor);
}

if (isIndexSignature()) {
return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers);
}
Expand Down
9 changes: 5 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1475,19 +1475,19 @@ namespace ts {

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

// See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a
// ClassElement and an ObjectLiteralElement.
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
readonly kind: SyntaxKind.SetAccessor;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
readonly name: PropertyName;
readonly body?: FunctionBody;
/* @internal */ typeParameters?: NodeArray<TypeParameterDeclaration>; // Present for use with reporting a grammar error
Expand Down Expand Up @@ -4765,6 +4765,7 @@ namespace ts {
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
target?: Symbol; // Resolved (non-alias) target of an alias
type?: Type; // Type of value symbol
writeType?: Type; // Type of value symbol in write contexts
nameType?: Type; // Type associated with a late-bound symbol
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5275,9 +5275,10 @@ namespace ts {
return symbol.flags & SymbolFlags.Transient ? (<TransientSymbol>symbol).checkFlags : 0;
}

export function getDeclarationModifierFlagsFromSymbol(s: Symbol): ModifierFlags {
export function getDeclarationModifierFlagsFromSymbol(s: Symbol, isWrite = false): ModifierFlags {
if (s.valueDeclaration) {
const flags = getCombinedModifierFlags(s.valueDeclaration);
const declaration = (isWrite && s.declarations && find(s.declarations, d => d.kind === SyntaxKind.SetAccessor)) || s.valueDeclaration;
const flags = getCombinedModifierFlags(declaration);
return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier;
}
if (getCheckFlags(s) & CheckFlags.Synthetic) {
Expand Down
9 changes: 3 additions & 6 deletions tests/baselines/reference/abstractPropertyNegative.errors.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: 'get' and 'set' accessor must have the same type.
tests/cases/compiler/abstractPropertyNegative.ts(11,18): error TS2380: 'get' and 'set' accessor must have the same type.
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
Expand All @@ -19,7 +18,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(40,9): error TS2676: Accessors
tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors must both be abstract or non-abstract.


==== tests/cases/compiler/abstractPropertyNegative.ts (16 errors) ====
==== tests/cases/compiler/abstractPropertyNegative.ts (15 errors) ====
interface A {
prop: string;
m(): string;
Expand All @@ -31,10 +30,8 @@ tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors
abstract m(): string;
abstract get mismatch(): string;
~~~~~~~~
!!! error TS2380: 'get' and 'set' accessor must have the same type.
!!! error TS2380: The return type of a 'get' accessor must be assignable to its 'set' accessor type
abstract set mismatch(val: number); // error, not same type
~~~~~~~~
!!! error TS2380: 'get' and 'set' accessor must have the same type.
}
class C extends B {
~
Expand Down
32 changes: 32 additions & 0 deletions tests/baselines/reference/accessorBodyInTypeContext.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
tests/cases/compiler/accessorBodyInTypeContext.ts(2,15): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/compiler/accessorBodyInTypeContext.ts(6,21): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/compiler/accessorBodyInTypeContext.ts(10,15): error TS1183: An implementation cannot be declared in ambient contexts.
tests/cases/compiler/accessorBodyInTypeContext.ts(14,21): error TS1183: An implementation cannot be declared in ambient contexts.


==== tests/cases/compiler/accessorBodyInTypeContext.ts (4 errors) ====
type A = {
get foo() { return 0 }
~~~~~~~~~~~~
!!! error TS1183: An implementation cannot be declared in ambient contexts.
};

type B = {
set foo(v: any) { }
~~~
!!! error TS1183: An implementation cannot be declared in ambient contexts.
};

interface X {
get foo() { return 0 }
~~~~~~~~~~~~
!!! error TS1183: An implementation cannot be declared in ambient contexts.
}

interface Y {
set foo(v: any) { }
~~~
!!! error TS1183: An implementation cannot be declared in ambient contexts.
}


20 changes: 20 additions & 0 deletions tests/baselines/reference/accessorBodyInTypeContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [accessorBodyInTypeContext.ts]
type A = {
get foo() { return 0 }
};

type B = {
set foo(v: any) { }
};

interface X {
get foo() { return 0 }
}

interface Y {
set foo(v: any) { }
}



//// [accessorBodyInTypeContext.js]
34 changes: 34 additions & 0 deletions tests/baselines/reference/accessorBodyInTypeContext.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== tests/cases/compiler/accessorBodyInTypeContext.ts ===
type A = {
>A : Symbol(A, Decl(accessorBodyInTypeContext.ts, 0, 0))

get foo() { return 0 }
>foo : Symbol(foo, Decl(accessorBodyInTypeContext.ts, 0, 10))

};

type B = {
>B : Symbol(B, Decl(accessorBodyInTypeContext.ts, 2, 2))

set foo(v: any) { }
>foo : Symbol(foo, Decl(accessorBodyInTypeContext.ts, 4, 10))
>v : Symbol(v, Decl(accessorBodyInTypeContext.ts, 5, 12))

};

interface X {
>X : Symbol(X, Decl(accessorBodyInTypeContext.ts, 6, 2))

get foo() { return 0 }
>foo : Symbol(X.foo, Decl(accessorBodyInTypeContext.ts, 8, 13))
}

interface Y {
>Y : Symbol(Y, Decl(accessorBodyInTypeContext.ts, 10, 1))

set foo(v: any) { }
>foo : Symbol(Y.foo, Decl(accessorBodyInTypeContext.ts, 12, 13))
>v : Symbol(v, Decl(accessorBodyInTypeContext.ts, 13, 12))
}


32 changes: 32 additions & 0 deletions tests/baselines/reference/accessorBodyInTypeContext.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
=== tests/cases/compiler/accessorBodyInTypeContext.ts ===
type A = {
>A : A

get foo() { return 0 }
>foo : number
>0 : 0

};

type B = {
>B : B

set foo(v: any) { }
>foo : any
>v : any

};

interface X {
get foo() { return 0 }
>foo : number
>0 : 0
}

interface Y {
set foo(v: any) { }
>foo : any
>v : any
}


This file was deleted.

8 changes: 4 additions & 4 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,15 +823,15 @@ declare namespace ts {
readonly kind: SyntaxKind.SemicolonClassElement;
readonly parent: ClassLikeDeclaration;
}
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
readonly kind: SyntaxKind.GetAccessor;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
readonly name: PropertyName;
readonly body?: FunctionBody;
}
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
readonly kind: SyntaxKind.SetAccessor;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
readonly name: PropertyName;
readonly body?: FunctionBody;
}
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,15 +823,15 @@ declare namespace ts {
readonly kind: SyntaxKind.SemicolonClassElement;
readonly parent: ClassLikeDeclaration;
}
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
readonly kind: SyntaxKind.GetAccessor;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
readonly name: PropertyName;
readonly body?: FunctionBody;
}
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer {
readonly kind: SyntaxKind.SetAccessor;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression;
readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration;
readonly name: PropertyName;
readonly body?: FunctionBody;
}
Expand Down
39 changes: 39 additions & 0 deletions tests/baselines/reference/divergentAccessors1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//// [divergentAccessors1.ts]
// Accessors in interfaces/types

{
interface IHasGetSet {
get foo(): number;
set foo(v: number | string);
}

const ihgs: IHasGetSet = null as any;
ihgs.foo = "32";
let r_ihgs_foo: number = ihgs.foo;
}

{
type T_HasGetSet = {
get foo(): number;
set foo(v: number | string);
}

const t_hgs: T_HasGetSet = null as any;
t_hgs.foo = "32";
let r_t_hgs_foo: number = t_hgs.foo;
}


//// [divergentAccessors1.js]
"use strict";
// Accessors in interfaces/types
{
var ihgs = null;
ihgs.foo = "32";
var r_ihgs_foo = ihgs.foo;
}
{
var t_hgs = null;
t_hgs.foo = "32";
var r_t_hgs_foo = t_hgs.foo;
}
Loading