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
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
@@ -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
},
@@ -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",
13 changes: 12 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
@@ -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;
@@ -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);
}
9 changes: 5 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
@@ -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
@@ -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
5 changes: 3 additions & 2 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
@@ -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) {
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'.
@@ -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;
@@ -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 {
~
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
@@ -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;
}
8 changes: 4 additions & 4 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
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