Skip to content

fix(46246): Extending Class/Interface With a Primitive Throws a More Concise Error Report #49208

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

Closed
wants to merge 9 commits into from

Conversation

maross3
Copy link

@maross3 maross3 commented May 22, 2022

fixes #46246

Example

Class:

class foo extends number {} 

Error:
A class cannot extend a primitive type like 'number'. A class can only extend named object types.

Interface:

interface bar extends number { }

Error:
An interface cannot extend a primitive type like 'number'. An interface can only extend named object types.

Notes:

  • gulp runtests passed on current branch.
  • I updated a few unit tests to test for the error. I did not feel new test cases were necessary, as the errors were well covered.
  • Function responsible for the ambiguous error: checkAndReportErrorForUsingTypeAsValue
  • Function to check heritage clause: checkAndReportErrorForExtendingPrimitiveType

Description

The approach was to check for extension of primitives directly before the ambiguous error message was thrown. This lead to making a new function.

I didn't add the code to the function checkAndReportErrorForUsingTypeAsValue because the intended error checking functionality was separate from evaluating the value for error checking.

The new function checkAndReportErrorForExtendingPrimitiveType now handles checking heritage clause related errors in regards to classes extending primitives.

In the code, we check if the current errorLocation's expected heritage clause was, in fact, a SyntaxKind.HeritageClause. A bitmask was used to check against the expected heritage clause: errorLocation.parent.parent.kind. If it's a primitive name and a heritage clause, we throw a more descriptive error.

This was my first contribution to any project of any size, so I would appreciate any feedback!

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label May 22, 2022
@ghost
Copy link

ghost commented May 22, 2022

CLA assistant check
All CLA requirements met.

@maross3 maross3 marked this pull request as ready for review May 22, 2022 20:45
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@typescript-bot typescript-bot added For Backlog Bug PRs that fix a backlog bug and removed For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels May 22, 2022
@MartinJohns
Copy link
Contributor

An interface can only extend named types and classes.

Unless that named type is a union type or a mapped type.

Or as error 2312 frames it:

An interface can only extend an object type or intersection of object types with statically known members.

@maross3
Copy link
Author

maross3 commented May 23, 2022

An interface can only extend named types and classes.

Hey, thanks for the info.

I accidentally made a bonus descriptive error for classes extending primitives:

class foo extends number {} // An interface (SHOULD BE CLASS) cannot extend a primitive type like 'number'; An interface can only extend named types and classes.

Couple quick questions:

  • Should we keep this error message and use {1} to state whether class or interface?
  • Should we call error with error 2312 as the second parameter instead?
  • Should we make a new error or remove the error for classes?

@maross3 maross3 changed the title fix(46246): Extending a Primitive Throws a More Concise Error Report fix(46246): Extending Class With a Primitive Throws a More Concise Error Report May 23, 2022
@maross3 maross3 changed the title fix(46246): Extending Class With a Primitive Throws a More Concise Error Report fix(46246): Extending Class/Interface With a Primitive Throws a More Concise Error Report May 23, 2022
@MartinJohns
Copy link
Contributor

Couple quick questions:

No idea. I'm no member of the TypeScript team. I just saw the new error message you added and wanted to point that it's incorrect (or at least not always correct).

@maross3 maross3 requested a review from DanielRosenwasser May 23, 2022 21:41
@maross3
Copy link
Author

maross3 commented May 23, 2022

Thank you,

  • Added the logic to distinguish between the interface and class errors.
  • Added additional error to keep consistent with other functions/error messages.
  • Fixed the typos

Added <repo-root>/ to example usage
@maross3
Copy link
Author

maross3 commented May 25, 2022

I'm following up on the review request, thank you @DanielRosenwasser

@sandersn
Copy link
Member

#46357 fixed #46246 earlier, although we dropped it until now. I merged that PR, but this PR also adds an error message on classes, which is pretty useful. If you want to continue on this PR, you could add the class error to the code added by #46357.

@@ -95,7 +95,7 @@ gulp help # List the above commands.
## Usage

```bash
node built/local/tsc.js hello.ts
node <repo-root>/built/local/tsc.js hello.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you revert the changes here and in package.json? They're not related to the fix.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, will do.

"category": "Error",
"code": 18042
},
"A class cannot extend a primitive type like '{0}'. A class can only extend named object types.": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're adding class-specific errors, a separate error for when classes implement primitive types would be nice.

else if(meaning & SymbolFlags.Class) {
error(errorLocation, Diagnostics.A_class_cannot_extend_a_primitive_type_like_0_A_class_can_only_extend_named_object_types, rawName);
}
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you should return true unless one of the above errors was issued.

Copy link
Author

@maross3 maross3 Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 2503 if (isPrimitiveTypeName(name) && !(errorLocation.parent.parent.kind & ~SyntaxKind.HeritageClause))

This is our error check. If we are in this scope, there is an error, so we only need one return statement. The if/else checks if it's a class or interface and throws a respective error. After the error is called, we return true. Would you like to see the return within the inner scopes above, or is this okay? (It does need a default error, though)

if(meaning & SymbolFlags.Interface) {
error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_An_interface_can_only_extend_named_object_types, rawName);
}
else if(meaning & SymbolFlags.Class) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A syntactic check (of errorLocation.parent.parent.parent I think) is better. meaning is the kind of symbol requested by name resolution.

Also you should probably check that all those parent nodes are defined.

@maross3
Copy link
Author

maross3 commented Jun 3, 2022

I'll be picking this back up within the week. I would like to continue working on this and add the additional class error. Thank you for the feedback!

@sandersn
Copy link
Member

sandersn commented Aug 1, 2022

@maross3 Do you want to keep working on this? Otherwise I'd like to close it to reduce the number of open PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Unhelpful error message when interface ... extends number
5 participants