Skip to content

Bring back SourceFile.EndOfFileToken #1257

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

Conversation

Andarist
Copy link
Contributor

No description provided.

@Andarist Andarist marked this pull request as ready for review June 22, 2025 10:02
@sandersn sandersn self-requested a review June 23, 2025 13:54
@sandersn sandersn self-assigned this Jun 23, 2025
Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Still reviewing baselines, but here are some out of order comments.

@@ -49,6 +49,9 @@ func getTokenAtPosition(
left := 0

testNode := func(node *ast.Node) int {
if node.Kind == ast.KindEndOfFile {
return 0
Copy link
Member

Choose a reason for hiding this comment

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

how does this translate from the code in services/utilities.ts? I don't see a specific EOF case in that code so I assume it's simplified from it in some way.

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 is a good question. It's an indirect port of the EOF case checked by nodeContainsPosition. The related code in Corsa is rewritten sligthly so it's not easy to see this. There is a chance this second nodeContainsPosition call might have to be ported too... but, so far, I have not found a need for it (at least not in the case of EOF):

            // first element whose start position is before the input and whose end position is after or equal to the input
            if (nodeContainsPosition(children[middle], start, end)) {
                if (children[middle - 1]) {
                    // we want the _first_ element that contains the position, so left-recur if the prior node also contains the position
                    if (nodeContainsPosition(children[middle - 1])) {
                        return Comparison.GreaterThan;
                    }
                }
                return Comparison.EqualTo;
            }

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 know either but I suspect that it's the cause of the difference in astnav baselines

@@ -102,6 +106,9 @@ func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Nod
case ast.KindJSDocImportTag:
importTag := tag.AsJSDocImportTag()
importClause := importTag.ImportClause
if importClause == nil {
Copy link
Member

Choose a reason for hiding this comment

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

I think ModuleSpecifier is actually the critical property to require non-nil, although an import tag that imports no identifiers is pointless, so keep checking importClause for nil too.

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'm not sure if I understand correctly. Have you meant I should adjust it to this?

if importClause == nil || importTag.ModuleSpecifier == nil  {
  break
}

Copy link
Member

Choose a reason for hiding this comment

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

yes, that

Copy link
Contributor Author

@Andarist Andarist Jun 24, 2025

Choose a reason for hiding this comment

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

All of those work alright-ish right now:

// @checkJs: true
// @allowJs: true

// @filename: /foo.js
/**
 * @import {A} from 
 */

/**
 * @import from 
 */

/**
 * @import
 */

So I wonder, if the proposed change is actually needed. The module specifier end up being an "empty identifier" (with an error flag set on it) in all three of those cases

Copy link
Member

Choose a reason for hiding this comment

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

Yes, if it works without the new code, please delete it.

@@ -1,3 +1,39 @@
〚Positions: [729, 730]〛
【TS: SourceFile [0, 9772)】
《Go: EndOfFileToken [9770, 9772)》
Copy link
Member

Choose a reason for hiding this comment

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

@andrewbranch I don't know how to read these baselines, but this could be the difference in GetTokenAtPosition that I was worried about.

Copy link
Member

Choose a reason for hiding this comment

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

Later: no, there's no jsdoc at the end; this is just a difference in GetTokenAtPosition or something similar between Strada and Corsa. Based on my reading of the diff--still not an expert--it looks like it is incorrect and Strada is correct.

Copy link
Member

Choose a reason for hiding this comment

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

I think the diff generator has a subtle bug where it’s not showing the actual positions where this is occurring, but all of these (729, 730, 780–783, etc.) are whitespace between top-level statements where Strada returns the SourceFile (seems right enough) and Corsa is returning the EOF token (seems wrong, since its text range is nowhere near the position being triggered).

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Requesting changes based on my previous comments, since this batch is just guesses for why diffs have happened.

@@ -1,3 +1,39 @@
〚Positions: [729, 730]〛
【TS: SourceFile [0, 9772)】
《Go: EndOfFileToken [9770, 9772)》
Copy link
Member

Choose a reason for hiding this comment

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

Later: no, there's no jsdoc at the end; this is just a difference in GetTokenAtPosition or something similar between Strada and Corsa. Based on my reading of the diff--still not an expert--it looks like it is incorrect and Strada is correct.

+!!! error TS1268: An index signature parameter type must be 'string', 'number', 'symbol', or a template literal type.
Copy link
Member

Choose a reason for hiding this comment

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

this error seems more accurate than the Strada one, although it's missing the suggestion to use a mapped type.

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 depends on t := c.getTypeFromTypeNode(typeNode). Corsa gets an unresolved any type (an error type) whereas Strada gets unique symbol type.

In what way, you'd like to unify this stuff?

Copy link
Member

Choose a reason for hiding this comment

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

ah, well, in that case the Strada type is more correct. I dn't think there's anything to fix for this PR, just a later fix--it sounds as if this might even be a difference between Corsa and Strada in TS as well.

//// [index3.d.ts]
// merge type alias and variable (behavior is borked, see #32366)
declare const x = 12;
export { x as default };
export type default = string | number;
export type _default = string | number;
Copy link
Member

Choose a reason for hiding this comment

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

Hm, but this is weird, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it is, the comment above this says the behavior is borked - and the type alias declaration here is the same in Strada:
https://github.com/microsoft/TypeScript/blob/78c16795cdee70b9d9f0f248b6dbb6ba50994a59/tests/baselines/reference/jsDeclarationsDefaultsErr.js#L81-L84

@jakebailey
Copy link
Member

Seems like it needs more baseline updates.


return value;
->value : import("a").WithSymbol
+>value : any
+>value : import("./a").WithSymbol
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

This is a known difference across a lot of these baselines, yeah.

Note that "accepted" applies to basically all JS code right now given we're claiming it's "not complete", so it was helpful to ignore these diffs in other PRs just fixing type checking issues.

@jakebailey
Copy link
Member

Still a test failure?

+--- old.partiallyNamedTuples2.types
++++ new.partiallyNamedTuples2.types
+@@= skipped -37, +37 lines =@@
+ const matches = x.get(id1);
+ >matches : Iterable<[id2: string, object]>
+ >x.get(id1) : Iterable<[id2: string, object]>
+->x.get : <Key extends [id1: string, id2: string] | [id1: string] | []>(...key: Key) => GetResult<[id1: string, id2: string], Key, object>
++>x.get : <Key extends [] | [id1: string] | [id1: string, id2: string]>(...key: Key) => GetResult<[id1: string, id2: string], Key, object>
+ >x : MultiKeyMap<[id1: string, id2: string], object>
+->get : <Key extends [id1: string, id2: string] | [id1: string] | []>(...key: Key) => GetResult<[id1: string, id2: string], Key, object>
++>get : <Key extends [] | [id1: string] | [id1: string, id2: string]>(...key: Key) => GetResult<[id1: string, id2: string], Key, object>
+ >id1 : string

Seems to have been a bad merge with main?

@Andarist
Copy link
Contributor Author

weird, maybe I have forgotten to git add this one single baseline after syncing with main. But either way, this is still blocked on the GetTouchingPropertyName difference - I hope to fix this before Friday but we'll see how it goes

@@ -1767,3 +1772,12 @@ func (tx *DeclarationTransformer) transformJSDocOptionalType(input *ast.JSDocOpt
tx.EmitContext().SetOriginal(replacement, input.AsNode())
return replacement
}

func (tx *DeclarationTransformer) getGeneratedDefaultExportIdentifier() *ast.Node {
Copy link
Member

Choose a reason for hiding this comment

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

This function feels wrong to me; this means we're putting the same node into the tree multiple times, which is a no-no.

Copy link
Member

Choose a reason for hiding this comment

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

(I'm not 100% sure this fix is required for the rest of the PR, so would probably be worth a follow-up as a d.ts improvement?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, ye - I meant to ask if I should clone this before returning and forgot.

(I'm not 100% sure this fix is required for the rest of the PR, so would probably be worth a follow-up as a d.ts improvement?)

yes, it's a little bit out of scope of this PR. This has just popped up in the diffs after EOF got included. I'll remove it from this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants