fix(compiler-cli): remove the concept of an errored trait (#39967) · angular/angular@0aa35ec
@@ -181,15 +181,13 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
181181const handler = this.handlersByName.get(priorTrait.handler.name)!;
182182let trait: Trait<unknown, unknown, unknown> = Trait.pending(handler, priorTrait.detected);
183183184-if (priorTrait.state === TraitState.ANALYZED || priorTrait.state === TraitState.RESOLVED) {
185-trait = trait.toAnalyzed(priorTrait.analysis);
186-if (trait.handler.register !== undefined) {
184+if (priorTrait.state === TraitState.Analyzed || priorTrait.state === TraitState.Resolved) {
185+trait = trait.toAnalyzed(priorTrait.analysis, priorTrait.analysisDiagnostics);
186+if (trait.analysis !== null && trait.handler.register !== undefined) {
187187trait.handler.register(record.node, trait.analysis);
188188}
189-} else if (priorTrait.state === TraitState.SKIPPED) {
189+} else if (priorTrait.state === TraitState.Skipped) {
190190trait = trait.toSkipped();
191-} else if (priorTrait.state === TraitState.ERRORED) {
192-trait = trait.toErrored(priorTrait.diagnostics);
193191}
194192195193record.traits.push(trait);
@@ -314,7 +312,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
314312preanalysis = trait.handler.preanalyze(clazz, trait.detected.metadata) || null;
315313} catch (err) {
316314if (err instanceof FatalDiagnosticError) {
317-trait.toErrored([err.toDiagnostic()]);
315+trait.toAnalyzed(null, [err.toDiagnostic()]);
318316return;
319317} else {
320318throw err;
@@ -332,7 +330,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
332330protected analyzeTrait(
333331clazz: ClassDeclaration, trait: Trait<unknown, unknown, unknown>,
334332flags?: HandlerFlags): void {
335-if (trait.state !== TraitState.PENDING) {
333+if (trait.state !== TraitState.Pending) {
336334throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${
337335 TraitState[trait.state]} (expected DETECTED)`);
338336}
@@ -343,26 +341,18 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
343341result = trait.handler.analyze(clazz, trait.detected.metadata, flags);
344342} catch (err) {
345343if (err instanceof FatalDiagnosticError) {
346-trait = trait.toErrored([err.toDiagnostic()]);
344+trait.toAnalyzed(null, [err.toDiagnostic()]);
347345return;
348346} else {
349347throw err;
350348}
351349}
352350353-if (result.diagnostics !== undefined) {
354-trait = trait.toErrored(result.diagnostics);
355-} else if (result.analysis !== undefined) {
356-// Analysis was successful. Trigger registration.
357-if (trait.handler.register !== undefined) {
358-trait.handler.register(clazz, result.analysis);
359-}
360-361-// Successfully analyzed and registered.
362-trait = trait.toAnalyzed(result.analysis);
363-} else {
364-trait = trait.toSkipped();
351+if (result.analysis !== undefined && trait.handler.register !== undefined) {
352+trait.handler.register(clazz, result.analysis);
365353}
354+355+trait = trait.toAnalyzed(result.analysis ?? null, result.diagnostics ?? null);
366356}
367357368358resolve(): void {
@@ -372,19 +362,23 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
372362for (let trait of record.traits) {
373363const handler = trait.handler;
374364switch (trait.state) {
375-case TraitState.SKIPPED:
376-case TraitState.ERRORED:
365+case TraitState.Skipped:
377366continue;
378-case TraitState.PENDING:
367+case TraitState.Pending:
379368throw new Error(`Resolving a trait that hasn't been analyzed: ${clazz.name.text} / ${
380369 Object.getPrototypeOf(trait.handler).constructor.name}`);
381-case TraitState.RESOLVED:
370+case TraitState.Resolved:
382371throw new Error(`Resolving an already resolved trait`);
383372}
384373374+if (trait.analysis === null) {
375+// No analysis results, cannot further process this trait.
376+continue;
377+}
378+385379if (handler.resolve === undefined) {
386380// No resolution of this trait needed - it's considered successful by default.
387-trait = trait.toResolved(null);
381+trait = trait.toResolved(null, null);
388382continue;
389383}
390384@@ -393,22 +387,14 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
393387result = handler.resolve(clazz, trait.analysis as Readonly<unknown>);
394388} catch (err) {
395389if (err instanceof FatalDiagnosticError) {
396-trait = trait.toErrored([err.toDiagnostic()]);
390+trait = trait.toResolved(null, [err.toDiagnostic()]);
397391continue;
398392} else {
399393throw err;
400394}
401395}
402396403-if (result.diagnostics !== undefined && result.diagnostics.length > 0) {
404-trait = trait.toErrored(result.diagnostics);
405-} else {
406-if (result.data !== undefined) {
407-trait = trait.toResolved(result.data);
408-} else {
409-trait = trait.toResolved(null);
410-}
411-}
397+trait = trait.toResolved(result.data ?? null, result.diagnostics ?? null);
412398413399if (result.reexports !== undefined) {
414400const fileName = clazz.getSourceFile().fileName;
@@ -436,12 +422,14 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
436422for (const clazz of this.fileToClasses.get(sf)!) {
437423const record = this.classes.get(clazz)!;
438424for (const trait of record.traits) {
439-if (trait.state !== TraitState.RESOLVED) {
425+if (trait.state !== TraitState.Resolved) {
440426continue;
441427} else if (trait.handler.typeCheck === undefined) {
442428continue;
443429}
444-trait.handler.typeCheck(ctx, clazz, trait.analysis, trait.resolution);
430+if (trait.resolution !== null) {
431+trait.handler.typeCheck(ctx, clazz, trait.analysis, trait.resolution);
432+}
445433}
446434}
447435}
@@ -450,15 +438,17 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
450438for (const clazz of this.classes.keys()) {
451439const record = this.classes.get(clazz)!;
452440for (const trait of record.traits) {
453-if (trait.state !== TraitState.RESOLVED) {
441+if (trait.state !== TraitState.Resolved) {
454442// Skip traits that haven't been resolved successfully.
455443continue;
456444} else if (trait.handler.index === undefined) {
457445// Skip traits that don't affect indexing.
458446continue;
459447}
460448461-trait.handler.index(ctx, clazz, trait.analysis, trait.resolution);
449+if (trait.resolution !== null) {
450+trait.handler.index(ctx, clazz, trait.analysis, trait.resolution);
451+}
462452}
463453}
464454}
@@ -475,19 +465,26 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
475465let res: CompileResult[] = [];
476466477467for (const trait of record.traits) {
478-if (trait.state !== TraitState.RESOLVED) {
468+if (trait.state !== TraitState.Resolved || trait.analysisDiagnostics !== null ||
469+trait.resolveDiagnostics !== null) {
470+// Cannot compile a trait that is not resolved, or had any errors in its declaration.
479471continue;
480472}
481473482474const compileSpan = this.perf.start('compileClass', original);
483475476+477+// `trait.resolution` is non-null asserted here because TypeScript does not recognize that
478+// `Readonly<unknown>` is nullable (as `unknown` itself is nullable) due to the way that
479+// `Readonly` works.
480+484481let compileRes: CompileResult|CompileResult[];
485482if (this.compilationMode === CompilationMode.PARTIAL &&
486483trait.handler.compilePartial !== undefined) {
487-compileRes = trait.handler.compilePartial(clazz, trait.analysis, trait.resolution);
484+compileRes = trait.handler.compilePartial(clazz, trait.analysis, trait.resolution!);
488485} else {
489486compileRes =
490-trait.handler.compileFull(clazz, trait.analysis, trait.resolution, constantPool);
487+trait.handler.compileFull(clazz, trait.analysis, trait.resolution!, constantPool);
491488}
492489493490const compileMatchRes = compileRes;
@@ -522,7 +519,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
522519const decorators: ts.Decorator[] = [];
523520524521for (const trait of record.traits) {
525-if (trait.state !== TraitState.RESOLVED) {
522+if (trait.state !== TraitState.Resolved) {
526523continue;
527524}
528525@@ -542,8 +539,12 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
542539diagnostics.push(...record.metaDiagnostics);
543540}
544541for (const trait of record.traits) {
545-if (trait.state === TraitState.ERRORED) {
546-diagnostics.push(...trait.diagnostics);
542+if ((trait.state === TraitState.Analyzed || trait.state === TraitState.Resolved) &&
543+trait.analysisDiagnostics !== null) {
544+diagnostics.push(...trait.analysisDiagnostics);
545+}
546+if (trait.state === TraitState.Resolved && trait.resolveDiagnostics !== null) {
547+diagnostics.push(...trait.resolveDiagnostics);
547548}
548549}
549550}