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

Shorten error spans for errors reported on constructor declarations #58061

Merged
merged 6 commits into from
May 31, 2024

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Apr 3, 2024

No description provided.

Comment on lines 2274 to 2275
const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, start);
while (scanner.scan() !== SyntaxKind.ConstructorKeyword) {
Copy link
Member

Choose a reason for hiding this comment

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

Seems pretty hefty to need an entire rescan to understand this; the info above doesn't seem to do this either. Is the position not just after the modifiers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems pretty hefty to need an entire rescan to understand this;

this is actually what some of the other branches do here indirectly (see the calls to getSpanOfTokenAtPosition)

Is the position not just after the modifiers?

that would roughly be the start position of the constructor keyword but for some of the errors it makes sense to highlight the modifiers and I think there is little value in differentiating this span between different error types (highlighting modifiers is fine since they usually are placed on the same line anyway). The bigger problem is when it comes to finding the end position of this span. I've tried to use node.parameters.start but it wasn't too precise. That's how I landed on this solution

Copy link
Member

Choose a reason for hiding this comment

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

I have a fear that some bad parse recovery mechanism will possibly make this code end up in an endless loop. Consider bailing on an EOF token or something similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should be highly-unlikely cause we know that we are already processing ConstructorDeclaration and I can't imagine a situation in which that would be created without the ConstructorKeyword. Being extra safe is probably for the better though - I applied the suggested change

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I didn't realize that getSpanOfTokenAtPosition creates a scanner each time. Definitely expensive but not new for this.

Why didn't getSpanOfTokenAtPosition work for this again? I guess I'm not sure why we'd want to highlight modifiers at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was worried about classConstructorOverloadsAccessibility but taking another look at it right now... it doesn't look bad if we only highlight the constructor keyword there:

git diff
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index f13946d637..5965e78154 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -2274,12 +2274,12 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa
         }
         case SyntaxKind.Constructor: {
             const constructorDeclaration = node as ConstructorDeclaration;
-            const start = skipTrivia(sourceFile.text, constructorDeclaration.pos);
-            const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, start);
+            const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, skipTrivia(sourceFile.text, constructorDeclaration.pos));
             let token = scanner.scan();
             while (token !== SyntaxKind.ConstructorKeyword && token !== SyntaxKind.EndOfFileToken) {
                 token = scanner.scan();
             }
+            const start = skipTrivia(sourceFile.text, scanner.getTokenStart());
             const end = scanner.getTokenEnd();
             return createTextSpanFromBounds(start, end);
         }
diff --git a/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt b/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt
index e939262b02..1b0723b506 100644
--- a/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt
+++ b/tests/baselines/reference/classConstructorOverloadsAccessibility.errors.txt
@@ -1,15 +1,15 @@
-classConstructorOverloadsAccessibility.ts(2,2): error TS2385: Overload signatures must all be public, private or protected.
-classConstructorOverloadsAccessibility.ts(3,2): error TS2385: Overload signatures must all be public, private or protected.
-classConstructorOverloadsAccessibility.ts(11,2): error TS2385: Overload signatures must all be public, private or protected.
+classConstructorOverloadsAccessibility.ts(2,9): error TS2385: Overload signatures must all be public, private or protected.
+classConstructorOverloadsAccessibility.ts(3,12): error TS2385: Overload signatures must all be public, private or protected.
+classConstructorOverloadsAccessibility.ts(11,12): error TS2385: Overload signatures must all be public, private or protected.
 
 
 ==== classConstructorOverloadsAccessibility.ts (3 errors) ====
     class A {
     	public constructor(a: boolean) // error
-    	~~~~~~~~~~~~~~~~~~
+    	       ~~~~~~~~~~~
 !!! error TS2385: Overload signatures must all be public, private or protected.
     	protected constructor(a: number) // error
-    	~~~~~~~~~~~~~~~~~~~~~
+    	          ~~~~~~~~~~~
 !!! error TS2385: Overload signatures must all be public, private or protected.
     	private constructor(a: string)
     	private constructor() { 
@@ -19,7 +19,7 @@ classConstructorOverloadsAccessibility.ts(11,2): error TS2385: Overload signatur
     
     class B {
     	protected constructor(a: number) // error
-    	~~~~~~~~~~~~~~~~~~~~~
+    	          ~~~~~~~~~~~
 !!! error TS2385: Overload signatures must all be public, private or protected.
     	constructor(a: string)
     	constructor() { 
diff --git a/tests/baselines/reference/parserConstructorDeclaration8.errors.txt b/tests/baselines/reference/parserConstructorDeclaration8.errors.txt
index 8b37b60364..c798654628 100644
--- a/tests/baselines/reference/parserConstructorDeclaration8.errors.txt
+++ b/tests/baselines/reference/parserConstructorDeclaration8.errors.txt
@@ -1,4 +1,4 @@
-parserConstructorDeclaration8.ts(3,3): error TS2390: Constructor implementation is missing.
+parserConstructorDeclaration8.ts(3,10): error TS2390: Constructor implementation is missing.
 parserConstructorDeclaration8.ts(3,21): error TS1005: '(' expected.
 
 
@@ -6,7 +6,7 @@ parserConstructorDeclaration8.ts(3,21): error TS1005: '(' expected.
     class C {
       // Not a constructor
       public constructor;
-      ~~~~~~~~~~~~~~~~~~
+             ~~~~~~~~~~~
 !!! error TS2390: Constructor implementation is missing.
                         ~
 !!! error TS1005: '(' expected.

Copy link
Member

Choose a reason for hiding this comment

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

I see what you mean, yeah. Maybe it's best as-is. That or TS2385 should have been on the modifiers the whole time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That or TS2385 should have been on the modifiers the whole time?

I'm not sure what do u mean by "that" here :p TS2385 - that's the one I think might be worth keeping over modifiers too. I don't feel super strong about it though

Copy link
Member

Choose a reason for hiding this comment

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

I was just saying that we could either do:

  • This PR as is, squiggle over modifiers
  • Change TS2385 to only squiggle on modifiers, change this PR to only squiggle on constructor.

But the latter seems like work.

@DanielRosenwasser probably should say what feels best here; I don't know if the existing change is a problem, really.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But the latter seems like work.

Yeah, this isn't 100% straightforward because right now those errors are reported on nodes and u'd like to raise over a span or nodes array or something. I'm not sure if there is an existing infra for this at the higher level (closer to the checker - where the errors are raised). I'd prefer not to investigate this right now 😉

@sandersn sandersn added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label May 31, 2024
@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.

Copy link
Member

@jakebailey jakebailey left a comment

Choose a reason for hiding this comment

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

FWIW I think this PR is fine as-is, and after merging main could probably safely go in.

@Andarist
Copy link
Contributor Author

@jakebailey it's synced with main now :)

@jakebailey jakebailey merged commit 7f7ff92 into microsoft:main May 31, 2024
28 checks passed
@Andarist Andarist deleted the shorter-span-constructor-errors branch May 31, 2024 21:43
skeate added a commit to skeate/TypeScript that referenced this pull request Jun 1, 2024
* upstream/main: (37 commits)
  Added NoTruncation flag to completions (microsoft#58719)
  Clone node to remove location even when it has been modified if needed (microsoft#58706)
  Properly account for `this` argument in intersection apparent type caching (microsoft#58677)
  Fix: Include Values of Script Extensions for Unicode Property Value Expressions in Regular Expressions (microsoft#58615)
  In `reScanSlashToken` use `charCodeChecked` not `codePointChecked` (microsoft#58727)
  Shorten error spans for errors reported on constructor declarations (microsoft#58061)
  Mark file as skips typechecking if it contains ts-nocheck (microsoft#58593)
  Fixed an issue with broken `await using` declarations in `for of` loops (microsoft#56466)
  Do not expand type references in keyof and index access (microsoft#58715)
  Improve the performance of isolatedDeclarations quickfix  (microsoft#58722)
  Unwrap `NoInfer` types when narrowing (microsoft#58292)
  Recover from type reuse errors by falling back to inferred type printing (microsoft#58720)
  Fixing self import (microsoft#58718)
  Enable JS emit for noCheck and noCheck for transpileModule (microsoft#58364)
  Revert PR 55371 (microsoft#58702)
  Update dependencies (microsoft#58639)
  Fix baselines after PR 58621 (microsoft#58705)
  Do not infer `yield*` type from contextual `TReturn` (microsoft#58621)
  `await using` normative changes (microsoft#58624)
  Handling statements from a known source file (microsoft#58679)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants