From 3120bf448cc160cb0249aa57a0a2bd62e35c1659 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Mon, 14 Dec 2020 18:16:48 +0100 Subject: [PATCH] fix(jsii): unknown error in Assembler._validateHeritageClauses (#2350) When the source code does not compile due to type checking errors, the TypeScript program model may include "error type" placeholders, to allow the compiler to provide feedback on subsequent code. The placeholder types do not have a symbol (quite intentionally!), and will hence cause a failure in the `Assembler.validateHeritageClauses` method. This change makes the code more defensive so it does not crash on this symptom, and does not report an additional error either (the TypeScript compiler will have done this for us already). The bug is more likely to hit users operating under `--watch`, as the type checker is more likely to be able to insert placeholder types in this case, as a previous version of the program might be used as a crutch to understand the error's context... This makes this bug difficult to reproduce in lab conditions, and is why this change does not include a corresponding unit test. Fixes #2349 --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- packages/jsii/lib/assembler.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index f756983558..11cee8cff7 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -959,6 +959,12 @@ export class Assembler implements Emitter { for (const clause of clauses) { for (const node of clause.types) { const parentType = this._typeChecker.getTypeAtLocation(node); + if (parentType.symbol == null) { + // The parent type won't have a symbol if it's an "error type" inserted by the type checker when the original + // code contains a compilation error. In such cases, the TypeScript compiler will already have reported about + // the incoherent declarations, so we'll just not re-validate it there (we'd fail anyway). + continue; + } // For some reason, we cannot trust parentType.isClassOrInterface() const badDecl = parentType.symbol.declarations.find( (decl) =>