diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 845f62365bb84..14bec59efdc95 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -15379,7 +15379,10 @@ func (c *Checker) getExternalModuleFileFromDeclaration(declaration *ast.Node) *a if ast.HasImportAttributes(declaration) { importAttributesType = c.getTypeFromImportAttributes(ast.GetImportAttributes(declaration)) } - moduleSymbol := c.resolveExternalModuleNameWorker(specifier, specifier /*moduleNotFoundError*/, nil, false, false, importAttributesType) // TODO: GH#18217 + // This is only used by emit and type printing, after checking has already reported any + // resolution errors for this specifier. Resolve with ignoreErrors so that these queries + // don't add new diagnostics (e.g. an implicit-any-module suggestion) as a side effect. + moduleSymbol := c.resolveExternalModuleNameWorker(specifier, specifier, nil /*moduleNotFoundError*/, true /*ignoreErrors*/, false /*isForAugmentation*/, importAttributesType) if moduleSymbol == nil { return nil } diff --git a/tsc/internal/fourslash/fourslash.go b/tsc/internal/fourslash/fourslash.go index de4ae802e3f84..8aac0ca986922 100644 --- a/tsc/internal/fourslash/fourslash.go +++ b/tsc/internal/fourslash/fourslash.go @@ -166,6 +166,9 @@ type FourslashOptions struct { Capabilities *lsproto.ClientCapabilities ContentMapperSpawner contentmapper.Spawner RunExternalCode bool + // Makes every textDocument/diagnostic request also emit the program and compare + // the diagnostics before and after emit, e.g. to catch ones added by the emit resolver. + TrackFlakyDiagnostics *lsproto.DiagnosticFlakeLogLevel } func NewFourslashWithOptions(t *testing.T, content string, options *FourslashOptions) (*FourslashTest, func()) { @@ -260,7 +263,7 @@ func newFourslash(t *testing.T, content string, options *FourslashOptions, testP // !!! temporary; remove when we have `handleDidChangeConfiguration`/implicit project config support // !!! replace with a proper request *after initialize* client.SetCompilerOptionsForInferredProjects(compilerOptions) - f.initialize(t, options.Capabilities, options.RunExternalCode) + f.initialize(t, options) if testData.isStateBaseliningEnabled() { // Single baseline, so initialize project state baseline too @@ -365,11 +368,12 @@ func getBaseFileNameFromTest(t *testing.T) string { const showCodeLensLocationsCommandName = "typescript.showCodeLensLocations" -func (f *FourslashTest) initialize(t *testing.T, capabilities *lsproto.ClientCapabilities, runExternalCode bool) { +func (f *FourslashTest) initialize(t *testing.T, options *FourslashOptions) { initializationOptions := &lsproto.InitializationOptions{ CodeLensShowLocationsCommandName: new(showCodeLensLocationsCommandName), + TrackFlakyDiagnostics: options.TrackFlakyDiagnostics, } - if runExternalCode { + if options.RunExternalCode { initializationOptions.RunExternalCode = new(true) } params := &lsproto.InitializeParams{ @@ -378,7 +382,7 @@ func (f *FourslashTest) initialize(t *testing.T, capabilities *lsproto.ClientCap InitializationOptions: initializationOptions, }, } - params.Capabilities = getCapabilitiesWithDefaults(capabilities) + params.Capabilities = getCapabilitiesWithDefaults(options.Capabilities) f.capabilities = params.Capabilities resp, _, ok := f.client.SendRequest(t, lsproto.InitializeInfo, params) if !ok { diff --git a/tsc/internal/testutil/harnessutil/harnessutil.go b/tsc/internal/testutil/harnessutil/harnessutil.go index 0b46a9a7a7cd7..1de43adc3761a 100644 --- a/tsc/internal/testutil/harnessutil/harnessutil.go +++ b/tsc/internal/testutil/harnessutil/harnessutil.go @@ -663,12 +663,12 @@ func compileFilesWithHost( preErrors = append(preErrors, preProgram.GetSyntacticDiagnostics(ctx, nil)...) preErrors = append(preErrors, preProgram.GetSemanticDiagnostics(ctx, nil)...) preErrors = append(preErrors, preProgram.GetGlobalDiagnostics(ctx)...) - if preProgram.Options().GetEmitDeclarations() { - preErrors = append(preErrors, preProgram.GetDeclarationDiagnostics(ctx, nil)...) - } if harnessOptions.CaptureSuggestions { preErrors = append(preErrors, preProgram.GetSuggestionDiagnostics(ctx, nil)...) } + if preProgram.Options().GetEmitDeclarations() { + preErrors = append(preErrors, preProgram.GetDeclarationDiagnostics(ctx, nil)...) + } preErrors = compiler.SortAndDeduplicateDiagnostics(preErrors) postProgram := createProgram(host, config) diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.js b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.js new file mode 100644 index 0000000000000..127d8e7dcb788 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.js @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts] //// + +//// [index.js] +exports.x = 1; +//// [index.js] +import { x } from "untyped"; +x; + + +//// [index.js] +import { x } from "untyped"; +x; + + +//// [index.d.ts] +export {}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.symbols new file mode 100644 index 0000000000000..a6703bcae24b5 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.symbols @@ -0,0 +1,9 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts] //// + +=== /index.js === +import { x } from "untyped"; +>x : Symbol(x, Decl(index.js, 0, 8)) + +x; +>x : Symbol(x, Decl(index.js, 0, 8)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.types new file mode 100644 index 0000000000000..5282c8905ece1 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule1.types @@ -0,0 +1,9 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts] //// + +=== /index.js === +import { x } from "untyped"; +>x : any + +x; +>x : error + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.js b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.js new file mode 100644 index 0000000000000..6b5a480bdb37d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.js @@ -0,0 +1,18 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts] //// + +//// [untyped.js] +exports.x = 1; +//// [index.ts] +// @ts-expect-error +import { x } from "./untyped"; +x; + + +//// [index.js] +// @ts-expect-error +import { x } from "./untyped"; +x; + + +//// [index.d.ts] +export {}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.symbols new file mode 100644 index 0000000000000..66b7fa45f7d77 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.symbols @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts] //// + +=== /index.ts === +// @ts-expect-error +import { x } from "./untyped"; +>x : Symbol(x, Decl(index.ts, 1, 8)) + +x; +>x : Symbol(x, Decl(index.ts, 1, 8)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.types new file mode 100644 index 0000000000000..7f2feb1e7fd4f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule2.types @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts] //// + +=== /index.ts === +// @ts-expect-error +import { x } from "./untyped"; +>x : any + +x; +>x : error + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.js b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.js new file mode 100644 index 0000000000000..916b339a214ce --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.js @@ -0,0 +1,18 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts] //// + +//// [untyped.mjs] +export const x = 1; +//// [index.mts] +// @ts-expect-error +import { x } from "./untyped.mjs"; +x; + + +//// [index.mjs] +// @ts-expect-error +import { x } from "./untyped.mjs"; +x; + + +//// [index.d.mts] +export {}; diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.symbols b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.symbols new file mode 100644 index 0000000000000..9e2f7c5506c1d --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.symbols @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts] //// + +=== /index.mts === +// @ts-expect-error +import { x } from "./untyped.mjs"; +>x : Symbol(x, Decl(index.mts, 1, 8)) + +x; +>x : Symbol(x, Decl(index.mts, 1, 8)) + diff --git a/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.types b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.types new file mode 100644 index 0000000000000..bfbd81030b2a0 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/noFlakyDiagnosticsUntypedModule3.types @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts] //// + +=== /index.mts === +// @ts-expect-error +import { x } from "./untyped.mjs"; +>x : any + +x; +>x : error + diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts new file mode 100644 index 0000000000000..297be38455c66 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule1.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @noImplicitAny: true +// @declaration: true +// @outDir: /out +// @noImplicitReferences: true +// @captureSuggestions: true +// @Filename: /node_modules/untyped/index.js +exports.x = 1; +// @Filename: /index.js +import { x } from "untyped"; +x; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts new file mode 100644 index 0000000000000..a2833d3af1087 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule2.ts @@ -0,0 +1,10 @@ +// @noImplicitAny: true +// @declaration: true +// @noImplicitReferences: true +// @captureSuggestions: true +// @Filename: /untyped.js +exports.x = 1; +// @Filename: /index.ts +// @ts-expect-error +import { x } from "./untyped"; +x; diff --git a/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts new file mode 100644 index 0000000000000..445e5b38a84a5 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/noFlakyDiagnosticsUntypedModule3.ts @@ -0,0 +1,11 @@ +// @module: nodenext +// @noImplicitAny: true +// @declaration: true +// @noImplicitReferences: true +// @captureSuggestions: true +// @Filename: /untyped.mjs +export const x = 1; +// @Filename: /index.mts +// @ts-expect-error +import { x } from "./untyped.mjs"; +x;