@@ -181,15 +181,13 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
181 | 181 | const handler = this.handlersByName.get(priorTrait.handler.name)!; |
182 | 182 | let trait: Trait<unknown, unknown, unknown> = Trait.pending(handler, priorTrait.detected); |
183 | 183 |
|
184 | | - 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) { |
187 | 187 | trait.handler.register(record.node, trait.analysis); |
188 | 188 | } |
189 | | - } else if (priorTrait.state === TraitState.SKIPPED) { |
| 189 | + } else if (priorTrait.state === TraitState.Skipped) { |
190 | 190 | trait = trait.toSkipped(); |
191 | | - } else if (priorTrait.state === TraitState.ERRORED) { |
192 | | - trait = trait.toErrored(priorTrait.diagnostics); |
193 | 191 | } |
194 | 192 |
|
195 | 193 | record.traits.push(trait); |
@@ -314,7 +312,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
314 | 312 | preanalysis = trait.handler.preanalyze(clazz, trait.detected.metadata) || null; |
315 | 313 | } catch (err) { |
316 | 314 | if (err instanceof FatalDiagnosticError) { |
317 | | - trait.toErrored([err.toDiagnostic()]); |
| 315 | + trait.toAnalyzed(null, [err.toDiagnostic()]); |
318 | 316 | return; |
319 | 317 | } else { |
320 | 318 | throw err; |
@@ -332,7 +330,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
332 | 330 | protected analyzeTrait( |
333 | 331 | clazz: ClassDeclaration, trait: Trait<unknown, unknown, unknown>, |
334 | 332 | flags?: HandlerFlags): void { |
335 | | - if (trait.state !== TraitState.PENDING) { |
| 333 | + if (trait.state !== TraitState.Pending) { |
336 | 334 | throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${ |
337 | 335 | TraitState[trait.state]} (expected DETECTED)`); |
338 | 336 | } |
@@ -343,26 +341,18 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
343 | 341 | result = trait.handler.analyze(clazz, trait.detected.metadata, flags); |
344 | 342 | } catch (err) { |
345 | 343 | if (err instanceof FatalDiagnosticError) { |
346 | | - trait = trait.toErrored([err.toDiagnostic()]); |
| 344 | + trait.toAnalyzed(null, [err.toDiagnostic()]); |
347 | 345 | return; |
348 | 346 | } else { |
349 | 347 | throw err; |
350 | 348 | } |
351 | 349 | } |
352 | 350 |
|
353 | | - 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); |
365 | 353 | } |
| 354 | + |
| 355 | + trait = trait.toAnalyzed(result.analysis ?? null, result.diagnostics ?? null); |
366 | 356 | } |
367 | 357 |
|
368 | 358 | resolve(): void { |
@@ -372,19 +362,23 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
372 | 362 | for (let trait of record.traits) { |
373 | 363 | const handler = trait.handler; |
374 | 364 | switch (trait.state) { |
375 | | - case TraitState.SKIPPED: |
376 | | - case TraitState.ERRORED: |
| 365 | + case TraitState.Skipped: |
377 | 366 | continue; |
378 | | - case TraitState.PENDING: |
| 367 | + case TraitState.Pending: |
379 | 368 | throw new Error(`Resolving a trait that hasn't been analyzed: ${clazz.name.text} / ${ |
380 | 369 | Object.getPrototypeOf(trait.handler).constructor.name}`); |
381 | | - case TraitState.RESOLVED: |
| 370 | + case TraitState.Resolved: |
382 | 371 | throw new Error(`Resolving an already resolved trait`); |
383 | 372 | } |
384 | 373 |
|
| 374 | + if (trait.analysis === null) { |
| 375 | + // No analysis results, cannot further process this trait. |
| 376 | + continue; |
| 377 | + } |
| 378 | + |
385 | 379 | if (handler.resolve === undefined) { |
386 | 380 | // No resolution of this trait needed - it's considered successful by default. |
387 | | - trait = trait.toResolved(null); |
| 381 | + trait = trait.toResolved(null, null); |
388 | 382 | continue; |
389 | 383 | } |
390 | 384 |
|
@@ -393,22 +387,14 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
393 | 387 | result = handler.resolve(clazz, trait.analysis as Readonly<unknown>); |
394 | 388 | } catch (err) { |
395 | 389 | if (err instanceof FatalDiagnosticError) { |
396 | | - trait = trait.toErrored([err.toDiagnostic()]); |
| 390 | + trait = trait.toResolved(null, [err.toDiagnostic()]); |
397 | 391 | continue; |
398 | 392 | } else { |
399 | 393 | throw err; |
400 | 394 | } |
401 | 395 | } |
402 | 396 |
|
403 | | - 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); |
412 | 398 |
|
413 | 399 | if (result.reexports !== undefined) { |
414 | 400 | const fileName = clazz.getSourceFile().fileName; |
@@ -436,12 +422,14 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
436 | 422 | for (const clazz of this.fileToClasses.get(sf)!) { |
437 | 423 | const record = this.classes.get(clazz)!; |
438 | 424 | for (const trait of record.traits) { |
439 | | - if (trait.state !== TraitState.RESOLVED) { |
| 425 | + if (trait.state !== TraitState.Resolved) { |
440 | 426 | continue; |
441 | 427 | } else if (trait.handler.typeCheck === undefined) { |
442 | 428 | continue; |
443 | 429 | } |
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 | + } |
445 | 433 | } |
446 | 434 | } |
447 | 435 | } |
@@ -450,15 +438,17 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
450 | 438 | for (const clazz of this.classes.keys()) { |
451 | 439 | const record = this.classes.get(clazz)!; |
452 | 440 | for (const trait of record.traits) { |
453 | | - if (trait.state !== TraitState.RESOLVED) { |
| 441 | + if (trait.state !== TraitState.Resolved) { |
454 | 442 | // Skip traits that haven't been resolved successfully. |
455 | 443 | continue; |
456 | 444 | } else if (trait.handler.index === undefined) { |
457 | 445 | // Skip traits that don't affect indexing. |
458 | 446 | continue; |
459 | 447 | } |
460 | 448 |
|
461 | | - 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 | + } |
462 | 452 | } |
463 | 453 | } |
464 | 454 | } |
@@ -475,19 +465,26 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
475 | 465 | let res: CompileResult[] = []; |
476 | 466 |
|
477 | 467 | for (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. |
479 | 471 | continue; |
480 | 472 | } |
481 | 473 |
|
482 | 474 | const compileSpan = this.perf.start('compileClass', original); |
483 | 475 |
|
| 476 | + |
| 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 | + |
484 | 481 | let compileRes: CompileResult|CompileResult[]; |
485 | 482 | if (this.compilationMode === CompilationMode.PARTIAL && |
486 | 483 | trait.handler.compilePartial !== undefined) { |
487 | | - compileRes = trait.handler.compilePartial(clazz, trait.analysis, trait.resolution); |
| 484 | + compileRes = trait.handler.compilePartial(clazz, trait.analysis, trait.resolution!); |
488 | 485 | } else { |
489 | 486 | compileRes = |
490 | | - trait.handler.compileFull(clazz, trait.analysis, trait.resolution, constantPool); |
| 487 | + trait.handler.compileFull(clazz, trait.analysis, trait.resolution!, constantPool); |
491 | 488 | } |
492 | 489 |
|
493 | 490 | const compileMatchRes = compileRes; |
@@ -522,7 +519,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
522 | 519 | const decorators: ts.Decorator[] = []; |
523 | 520 |
|
524 | 521 | for (const trait of record.traits) { |
525 | | - if (trait.state !== TraitState.RESOLVED) { |
| 522 | + if (trait.state !== TraitState.Resolved) { |
526 | 523 | continue; |
527 | 524 | } |
528 | 525 |
|
@@ -542,8 +539,12 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { |
542 | 539 | diagnostics.push(...record.metaDiagnostics); |
543 | 540 | } |
544 | 541 | for (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); |
547 | 548 | } |
548 | 549 | } |
549 | 550 | } |
|