-
Notifications
You must be signed in to change notification settings - Fork 14
Private Name Support in the Checker #5
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
Conversation
5892232 to
ef4e718
Compare
6a0ea87 to
6482040
Compare
src/compiler/checker.ts
Outdated
| // A reserved member name starts with two underscores, but the third character cannot be an underscore | ||
| // or the @ symbol. A third underscore indicates an escaped form of an identifer that started | ||
| // A reserved member name starts with two underscores, but the third character cannot be an underscore, | ||
| // @ or #. A third underscore indicates an escaped form of an identifer that started |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oxford comma
src/compiler/checker.ts
Outdated
| reportError( | ||
| Diagnostics.Property_0_is_missing_in_type_1_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct, | ||
| diagnosticName(privateNameDescription), | ||
| diagnosticName(source.symbol.valueDeclaration.name || ("anonymous" as __String)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, elsewhere we use the string "(anonymous)" with parentheses around it (e.g. checkNoTypeArguments)
src/compiler/checker.ts
Outdated
| right, | ||
| Diagnostics.This_usage_of_0_refers_to_the_private_member_declared_in_its_enclosing_class_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct, | ||
| diagnosticName(right), | ||
| diagnosticName(classWithShadowedPrivateName.name || ("anonymous" as __String)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"(anonymous)"
src/compiler/checker.ts
Outdated
| } | ||
| if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) { | ||
| error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray newline, and this is as far as my review goes before I have to get off the bus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚌
DanielRosenwasser
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this looks good apart from the nits I've left. We'll need one or two more pairs of eyes though. My biggest feedback will be around testing.
I think one test for duplicate private fields would be useful, which is an early error in the proposal. Something like class C { #foo; #foo }.
It'd also be good to see some set of tests in the compiler folder for common scenarios people will expect to work. For example,
// @strict: true
class C {
#a = 1;
#b: number;
#c;
#d: string | null = null;
constructor() {
this.#c = 2;
}
foo() {
this.#d.toLowerCase();
}
}I would expect noImplicitAny, strictClassInitialization, and strictNullChecks checks to cause issues here.
tests/baselines/reference/privateNameConstructorReserved.errors.txt
Outdated
Show resolved
Hide resolved
b9b77f4 to
2d7e227
Compare
c493238 to
9767522
Compare
853486f to
221111e
Compare
5e83071 to
5aa1b7a
Compare
- [x] treat private names as unique:
- case 1: cannot say that a variable is of a class type unless the variable points to an instance of the class
- see [test](https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNamesUnique.ts)
- case 2: private names in class hierarchies do not conflict
- see [test](https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNamesNoConflictWhenInheriting.ts)
- [x] `#constructor` is reserved
- see [test](https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNameConstructorReserved.ts)
- check in `bindWorker`, where every node is visited
- [x] Accessibility modifiers can't be used with private names
- see [test](https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNamesNoAccessibilityModifiers.ts)
- implemented in `checkAccessibilityModifiers`, using `ModifierFlags.AccessibilityModifier`
- [x] `delete #foo` not allowed
- [x] Private name accesses not allowed outside of the defining class
- see test: https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNameNotAccessibleOutsideDefiningClass.ts
- see [test](https://github.com/mheiber/TypeScript/tree/checker/tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts)
- implemented in `checkDeleteExpression`
- [x] Do [the right thing](https://gist.github.com/mheiber/b6fc7adb426c2e1cdaceb5d7786fc630) for nested classes
Signed-off-by: Max Heiber <mheiber@bloomberg.net>
Signed-off-by: Max Heiber <mheiber@bloomberg.net>
Signed-off-by: Max Heiber <mheiber@bloomberg.net>
Update private name tests to use 'strict' type checking and to target es6 instead of default. Makes the js output easier to read and tests more surface area with other checker features. Signed-off-by: Max Heiber <max.heiber@gmail.com>
src/compiler/types.ts
Outdated
| } | ||
|
|
||
| export interface PrivateName extends Declaration { | ||
| export interface PrivateName extends Expression, Declaration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is a PrivateName a Declaration? It seems to me like it would just be (one option for) the name of PropertyDeclaration or a PropertyAccess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good 👀 .
I made it an Expression to debug something else and forgot to switch it back.
Should just be Declaration. Needs to be a declaration because binder::addDeclarationToSymbol expects a declaration.
Signed-off-by: Max Heiber <max.heiber@gmail.com>
#constructoris reservedbindWorker, where every node is visitedcheckAccessibilityModifiers, usingModifierFlags.AccessibilityModifierdelete #foonot allowedcheckDeleteExpressiongetPropertyForPrivateNameto public compiler API