-
Notifications
You must be signed in to change notification settings - Fork 14
es private fields in in #52
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
Changes from 26 commits
306397b
df7e97d
219899f
fa3a4c7
7df6a99
df5a86f
3560223
17c95e6
ec072dc
45e1b48
9127d55
4399cf5
0462595
23c8f98
43a7d9f
170e61b
7e33365
f2efbcf
598215b
f7ff235
f3d1e52
dbd7113
91cfecb
5eead91
85a367b
02f59a3
8928039
211b39e
a846027
d2bddf3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23232,6 +23232,33 @@ namespace ts { | |
| return type; | ||
| } | ||
|
|
||
| function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: PrivateIdentifierInInExpression, assumeTrue: boolean): Type { | ||
| const target = getReferenceCandidate(expr.expression); | ||
| if (!isMatchingReference(reference, target)) { | ||
| return type; | ||
| } | ||
|
|
||
| const privateId = expr.name; | ||
| const symbol = lookupSymbolForPrivateIdentifierDeclaration(privateId.escapedText, privateId); | ||
| if (symbol === undefined) { | ||
| return type; | ||
| } | ||
| const classSymbol = symbol.parent!; | ||
| const classType = <InterfaceType>getTypeOfSymbol(classSymbol); | ||
| const firstDecl = symbol.declarations?.[0]; | ||
| Debug.assert(firstDecl, "should always have a declaration"); | ||
| let targetType: Type; | ||
| if (hasSyntacticModifier(firstDecl, ModifierFlags.Static)) { | ||
|
||
| targetType = classType; | ||
| } | ||
| else { | ||
| const ctorSigs = getSignaturesOfType(classType, SignatureKind.Construct); | ||
| Debug.assert(ctorSigs.length > 0, "should always have a constructor"); | ||
| targetType = getReturnTypeOfSignature(ctorSigs[0]); | ||
|
||
| } | ||
| return getNarrowedType(type, targetType, assumeTrue, isTypeDerivedFrom); | ||
| } | ||
|
|
||
| function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { | ||
| // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: | ||
| // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. | ||
|
|
@@ -23645,6 +23672,8 @@ namespace ts { | |
| return narrowType(type, (<ParenthesizedExpression | NonNullExpression>expr).expression, assumeTrue); | ||
| case SyntaxKind.BinaryExpression: | ||
| return narrowTypeByBinaryExpression(type, <BinaryExpression>expr, assumeTrue); | ||
| case SyntaxKind.PrivateIdentifierInInExpression: | ||
| return narrowTypeByPrivateIdentifierInInExpression(type, <PrivateIdentifierInInExpression>expr, assumeTrue); | ||
| case SyntaxKind.PrefixUnaryExpression: | ||
| if ((<PrefixUnaryExpression>expr).operator === SyntaxKind.ExclamationToken) { | ||
| return narrowType(type, (<PrefixUnaryExpression>expr).operand, !assumeTrue); | ||
|
|
@@ -27274,6 +27303,7 @@ namespace ts { | |
| } | ||
|
|
||
| function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { | ||
| const originalName = name; | ||
| let props = getPropertiesOfType(containingType); | ||
| if (typeof name !== "string") { | ||
| const parent = name.parent; | ||
|
|
@@ -27282,7 +27312,23 @@ namespace ts { | |
| } | ||
| name = idText(name); | ||
| } | ||
| return getSpellingSuggestionForName(name, props, SymbolFlags.Value); | ||
| const suggestion = getSpellingSuggestionForName(name, props, SymbolFlags.Value); | ||
| if (suggestion) { | ||
| return suggestion; | ||
| } | ||
| // If we have `#typo in expr` then we can still look up potential privateIdentifiers from the surrounding classes | ||
| if (typeof originalName !== "string" && isPrivateIdentifierInInExpression(originalName.parent)) { | ||
| const privateIdentifiers: Symbol[] = []; | ||
| forEachEnclosingClass(originalName, (klass: ClassLikeDeclaration) => { | ||
| forEach(klass.members, member => { | ||
| if (isPrivateIdentifierClassElementDeclaration(member)) { | ||
| privateIdentifiers.push(member.symbol); | ||
| } | ||
| }); | ||
| }); | ||
| return getSpellingSuggestionForName(name, privateIdentifiers, SymbolFlags.Value); | ||
| } | ||
| return undefined; | ||
| } | ||
|
|
||
| function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { | ||
|
|
@@ -31056,6 +31102,11 @@ namespace ts { | |
| isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) { | ||
| error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); | ||
| } | ||
| checkInExpressionRHS(right, rightType); | ||
| return booleanType; | ||
| } | ||
|
|
||
| function checkInExpressionRHS(right: Expression, rightType: Type) { | ||
| const rightTypeConstraint = getConstraintOfType(rightType); | ||
| if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) || | ||
| rightTypeConstraint && ( | ||
|
|
@@ -31065,7 +31116,6 @@ namespace ts { | |
| ) { | ||
| error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_not_be_a_primitive); | ||
| } | ||
| return booleanType; | ||
| } | ||
|
|
||
| function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { | ||
|
|
@@ -31302,6 +31352,40 @@ namespace ts { | |
| return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); | ||
| } | ||
|
|
||
| function checkPrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression, checkMode?: CheckMode) { | ||
| const privateId = node.name; | ||
| const exp = node.expression; | ||
| let rightType = checkExpression(exp, checkMode); | ||
|
|
||
| const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privateId.escapedText, privateId); | ||
| if (lexicallyScopedSymbol === undefined) { | ||
| if (!getContainingClass(node)) { | ||
| error(privateId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); | ||
| } | ||
| else { | ||
| const suggestion = getSuggestedSymbolForNonexistentProperty(privateId, rightType); | ||
| if (suggestion) { | ||
| const suggestedName = symbolName(suggestion); | ||
| error(privateId, Diagnostics.Cannot_find_name_0_Did_you_mean_1, diagnosticName(privateId), suggestedName); | ||
| } | ||
| else { | ||
| error(privateId, Diagnostics.Cannot_find_name_0, diagnosticName(privateId)); | ||
| } | ||
| } | ||
| return anyType; | ||
| } | ||
|
|
||
| markPropertyAsReferenced(lexicallyScopedSymbol, /* nodeForCheckWriteOnly: */ undefined, /* isThisAccess: */ false); | ||
| getNodeLinks(node).resolvedSymbol = lexicallyScopedSymbol; | ||
|
|
||
| if (rightType === silentNeverType) { | ||
| return silentNeverType; | ||
| } | ||
| rightType = checkNonNullType(rightType, exp); | ||
| checkInExpressionRHS(exp, rightType); | ||
| return booleanType; | ||
| } | ||
|
|
||
| function createCheckBinaryExpression() { | ||
| interface WorkArea { | ||
| readonly checkMode: CheckMode | undefined; | ||
|
|
@@ -32483,6 +32567,8 @@ namespace ts { | |
| return checkPostfixUnaryExpression(<PostfixUnaryExpression>node); | ||
| case SyntaxKind.BinaryExpression: | ||
| return checkBinaryExpression(<BinaryExpression>node, checkMode); | ||
| case SyntaxKind.PrivateIdentifierInInExpression: | ||
| return checkPrivateIdentifierInInExpression(<PrivateIdentifierInInExpression>node, checkMode); | ||
| case SyntaxKind.ConditionalExpression: | ||
| return checkConditionalExpression(<ConditionalExpression>node, checkMode); | ||
| case SyntaxKind.SpreadElement: | ||
|
|
@@ -38923,6 +39009,15 @@ namespace ts { | |
| return resolveEntityName(<Identifier>name, /*meaning*/ SymbolFlags.FunctionScopedVariable); | ||
| } | ||
|
|
||
| if (isPrivateIdentifier(name) && isPrivateIdentifierInInExpression(name.parent)) { | ||
| const links = getNodeLinks(name.parent); | ||
| if (links.resolvedSymbol) { | ||
| return links.resolvedSymbol; | ||
| } | ||
| checkPrivateIdentifierInInExpression(name.parent); | ||
| return links.resolvedSymbol; | ||
| } | ||
|
|
||
| // Do we want to return undefined here? | ||
| return undefined; | ||
| } | ||
|
|
||
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.
Wasn't there a
valueDeclarationthat is what is needed here ?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.
ah yes there is
symbol.valueDeclaration- that looks much better. I'll change to that.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.
done :)