microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.7k stars 12.45k forks source link

Error: Debug Failure. False expression. #52952

Open calebpitan opened 1 year ago

calebpitan commented 1 year ago

Bug Report

🔎 Search Terms

debug failure, false expression, at object.first

🕗 Version & Regression Information

⏯ Playground Link

Playground link with relevant code

💻 Code

stack trace:

/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:99615
                throw e;
                ^

Error: Debug Failure. False expression.
    at Object.first (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:990:18)
    at getSpecifierForModuleSymbol (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:45313:36)
    at serializeAsAlias (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:46419:107)
    at serializeSymbolWorker (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:46084:25)
    at serializeSymbol (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:45978:25)
    at /Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:45963:29
    at Map.forEach (<anonymous>)
    at visitSymbolTable (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:45962:81)
    at symbolTableToDeclarationStatements (/Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:45847:17)
    at /Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js:44127:106

Node.js v18.11.0

source: node_modules/typescript/lib/tsc.js

ts.firstOrUndefined = firstOrUndefined;
first(array) {
    ts.Debug.assert(array.length !== 0);
    return array[0];
}
ts.first = first;

tsconfig.json:

{
  "compilerOptions": {
    "module": "ES2020",
    "moduleResolution": "node",
    "allowJs": true,
    "checkJs": false,
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "target": "ES2022",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "rootDir": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictBindCallApply": true,
    "alwaysStrict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "paths": {
      "@/shared/*": ["backend-services-shared/src/*"], // contains .js files
      "@/utils/*": ["src/utils/*"],
      "@/modules/*": ["src/modules/*"]
    }
  },
  "exclude": ["node_modules", "test", "dist"]
}

🙁 Actual behavior

Error happens when I turn on allowJs

🙂 Expected behavior

allowJs shouldn't crash build process and should include the js files from the source in the build output 😔

RyanCavanaugh commented 1 year ago

We'd need a way to reproduce the problem. Do you have a repo we can clone, or other way to produce this crash?

DanielRosenwasser commented 1 year ago

To help narrow it down, you might be able to modify your tsc.js at /Users/calebpitan/source/work/zendwa/emailing-service/node_modules/typescript/lib/tsc.js

                  symbolTableToDeclarationStatements: function (symbolTable, enclosingDeclaration, flags, tracker, bundled) {
+                     console.log("FILE NAME", ts.getSourceFileOfNode(enclosingDeclaration).fileName);
                      return withContext(enclosingDeclaration, flags, tracker, function (context) { return symbolTableToDeclarationStatements(symbolTable, context, bundled); });
                  },

It starts at line 44125 in TypeScript 4.9.5's tsc.js.

calebpitan commented 1 year ago

Thanks to @DanielRosenwasser "debug snippet" which seems to have pointed me in the right direction, and did help narrow it down just as he mentioned. I inserted a console statement on that line and it was able to log the filenames till it crashed again. I inspected the last logged file before crash and found out it imported files that imported uninstalled modules/deps.

Instaliing the missing module fixed it and tsc could build successfully.

But this doesn't mean there's no problem. The problem is: the compiler couldn't resolve a specifier, why couldn't it just say so in an understandable, helpful error message, rather than an elusive jargon like "Error: Debug Failure. False expression."?

first(array) {
    ts.Debug.assert(array.length !== 0);
    return array[0];
}

It seems, apparently, the only thing that makes this array empty is an unresolved module specifier, if so, the Debug.assert could make room for a custom error message rather than a generic "Debug Failure. False expression"

fatcerberus commented 1 year ago

But this doesn't mean there's no problem. The problem is: the compiler couldn't resolve a specifier, why couldn't it just say so in an understandable, helpful error message, rather than an elusive jargon like "Error: Debug Failure. False expression."?

The message is cryptic because it's intended for TS developers, not end-users. A debug assert being hit means the compiler has done something that, if it were functioning correctly, would literally never happen (in this case calling first() with an empty array); it always indicates a bug that has to be fixed elsewhere. In this case, it sounds like there might be a missing check during module specifier resolution.

In other words: "Debug Failure" is a crash, not an expected error condition.

ljharb commented 1 year ago

I got this same error.

Specifically, it seems like I had @types/gopd installed, and then also made a types/gopd/index.d.ts, in which I provided my own definition that uses export =. @RyanCavanaugh can you reproduce it with that approach?

Note that it does not crash when my overload uses export default, but every CJS module's type is export = so I need to use that.

DanielRosenwasser commented 1 year ago

I tried briefly, but haven't gotten far. Can you do the same thing I told @calebpitan to try above and see if you can provide a pared down version of that file? A pared-down config file is going to be helpful too.

ljharb commented 1 year ago

@DanielRosenwasser when i apply that console log diff (which is slightly tricker in TS 5 beta), it's never hit - the line it dies on is Debug.assert(node.kind !== 257 /* VariableDeclaration */); inside checkAliasSymbol, and when i add a console.log(node) in front of it, i get:

``` Node4 { pos: 64, end: 88, kind: 257, id: 0, flags: 262144, modifierFlagsCache: 536875008, transformFlags: 0, parent: Node4 { pos: 59, end: 88, kind: 258, id: 0, flags: 262144, modifierFlagsCache: 536875008, transformFlags: 4194304, parent: Node4 { pos: 59, end: 89, kind: 240, id: 0, flags: 262144, modifierFlagsCache: 536875008, transformFlags: 4194304, parent: [Node4], original: undefined, emitNode: undefined, modifiers: undefined, declarationList: [Circular *1], jsDoc: undefined, flowNode: [Object] }, original: undefined, emitNode: undefined, declarations: [ [Circular *2], pos: 64, end: 88, hasTrailingComma: false, transformFlags: 0 ] }, original: undefined, emitNode: undefined, symbol: Symbol4 { flags: 2097152, escapedName: '$gOPD', declarations: [ [Circular *2] ], valueDeclaration: undefined, id: 24904, mergeId: 0, parent: undefined, members: undefined, exports: undefined, exportSymbol: undefined, constEnumOnlyModule: undefined, isReferenced: undefined, isAssigned: undefined, links: undefined }, localSymbol: undefined, name: Identifier2 { pos: 64, end: 70, kind: 79, id: 0, flags: 262144, transformFlags: 0, parent: [Circular *2], original: undefined, emitNode: undefined, escapedText: '$gOPD', jsDoc: undefined, flowNode: { flags: 2064, antecedent: [Object], node: [Node4] }, symbol: undefined }, exclamationToken: undefined, type: undefined, initializer: Node4 { pos: 72, end: 88, kind: 210, id: 0, flags: 262144, modifierFlagsCache: 0, transformFlags: 0, parent: [Circular *2], original: undefined, emitNode: undefined, symbol: undefined, localSymbol: undefined, expression: Identifier2 { pos: 72, end: 80, kind: 79, id: 0, flags: 262144, transformFlags: 0, parent: [Circular *3], original: undefined, emitNode: undefined, escapedText: 'require', jsDoc: undefined, flowNode: [Object], symbol: undefined }, questionDotToken: undefined, typeArguments: undefined, arguments: [ [Node4], pos: 81, end: 87, hasTrailingComma: false, transformFlags: 0 ] }, jsDoc: [ jsDocCache: [] ] } ```

Happy to debug live elsewhere, or with comments here, since it's consistently reproducible for me - just not in a branch i'm ready to share publicly.

Config file:

```json5 { "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Language and Environment */ "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ "typeRoots": ["types", "@node_modules/@types"], /* Specify multiple folders that act like `./node_modules/@types`. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "resolveJsonModule": true, /* Enable importing .json files */ // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ /* Emit */ "noEmit": true, /* Disable emitting files from a compilation. */ /* Interop Constraints */ "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ /* Type Checking */ "strict": true, /* Enable all strict type-checking options. */ "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ /* Completeness */ // "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": [ "**/*.js" ], "exclude": [ "coverage/**" ], } ```
DanielRosenwasser commented 1 year ago

That seems like a separate stack trace then, right? If so, what is the stack trace? And can you switch the console.log(node) to console.log("FILE NAME", ts.getSourceFileOfNode(enclosingDeclaration).fileName);?

ljharb commented 1 year ago

I can't, because ts is not defined in that function.

Stack trace:

$PWD/node_modules/typescript/lib/tsc.js:113967
      throw e;
      ^

Error: Debug Failure. False expression.
    at checkAliasSymbol ($PWD/node_modules/typescript/lib/tsc.js:78641:17)
    at checkVariableLikeDeclaration ($PWD/node_modules/typescript/lib/tsc.js:76204:7)
    at checkVariableDeclaration (/$PWD/node_modules/typescript/lib/tsc.js:76287:5)
    at checkSourceElementWorker ($PWD/node_modules/typescript/lib/tsc.js:79258:16)
    at checkSourceElement ($PWD/node_modules/typescript/lib/tsc.js:79089:7)
    at forEach ($PWD/node_modules/typescript/lib/tsc.js:37:22)
    at checkVariableStatement ($PWD/node_modules/typescript/lib/tsc.js:76297:5)
    at checkSourceElementWorker ($PWD/node_modules/typescript/lib/tsc.js:79227:16)
    at checkSourceElement ($PWD/node_modules/typescript/lib/tsc.js:79089:7)
    at forEach ($PWD/node_modules/typescript/lib/tsc.js:37:22)

Node.js v19.6.1
ljharb commented 1 year ago

@DanielRosenwasser actually turns out i was authoring my "declare module" incorrectly - i was doing type x = whatever instead of function x, and the export = with the type was what was crashing. Hope that helps :-)

divmgl commented 5 months ago

This is happening to me on version 5.3.3 of TypeScript.

image

I'm going to try 5.4.5 to see if this is resolved.

DanielRosenwasser commented 5 months ago

@divmgl that seems like an unrelated stack trace. Feel free to open a separate issue if you can provide a repro on the latest version of TS.

zigcccc commented 1 month ago

I'm getting this too after updating from 5.2.2 to 5.6.2. Similar to others reporting this, I have allowJs: true set.

Andarist commented 4 weeks ago

@zigcccc could you prepare a repro case of the problem? you could try to remove as much lines from your project as possible (gradually) and bisect the problem this way to the minimal repro case