Skip to content

Commit

Permalink
Improvements to type relation errors (#4357)
Browse files Browse the repository at this point in the history
fix #3291

Changes: 
1. Figure out the most accurate location for the diagnostic
2. If diagnostic target a child node of the base diagnostic target then
emit diagnostic directly there
3. Otherwise emit back at the root(or closest child node) and build
stack of error message

Example the following would now emit the error on a
```ts
 const b = #{ prop: #{a: "abc"}};
 const a: {prop: {}} = b;
```

```
Type '{ prop: { a: "abc" } }' is not assignable to type '{ prop: {} }'
  Type '{ a: "abc" }' is not assignable to type '{}'
    Object value may only specify known properties, and 'a' does not exist in type '{}'.
```

Previously the error would have been in the complete wrong place 
<img width="271" alt="image"
src="https://github.com/user-attachments/assets/c403d1ec-3611-4ad6-87b0-2e0a075dc1c5">
  • Loading branch information
timotheeguerin authored Sep 6, 2024
1 parent 89e19ef commit 03d4fca
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/compiler"
---

Improvements to type relation errors: Show stack when it happens in a nested property otherwise show up in the correct location.
12 changes: 4 additions & 8 deletions packages/compiler/src/core/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5649,7 +5649,7 @@ export function createChecker(program: Program): Checker {
function checkArgumentAssignable(
argumentType: Type | Value | IndeterminateEntity,
parameterType: Entity,
diagnosticTarget: DiagnosticTarget
diagnosticTarget: Entity | Node
): boolean {
const [valid] = relation.isTypeAssignableTo(argumentType, parameterType, diagnosticTarget);
if (!valid) {
Expand Down Expand Up @@ -7420,7 +7420,7 @@ export function createChecker(program: Program): Checker {
function checkTypeOfValueMatchConstraint(
source: Entity,
constraint: CheckValueConstraint,
diagnosticTarget: DiagnosticTarget
diagnosticTarget: Entity | Node
): boolean {
const [related, diagnostics] = relation.isTypeAssignableTo(
source,
Expand Down Expand Up @@ -7455,7 +7455,7 @@ export function createChecker(program: Program): Checker {
function checkTypeAssignable(
source: Entity | IndeterminateEntity,
target: Entity,
diagnosticTarget: DiagnosticTarget
diagnosticTarget: Entity | Node
): boolean {
const [related, diagnostics] = relation.isTypeAssignableTo(source, target, diagnosticTarget);
if (!related) {
Expand All @@ -7464,11 +7464,7 @@ export function createChecker(program: Program): Checker {
return related;
}

function checkValueOfType(
source: Value,
target: Type,
diagnosticTarget: DiagnosticTarget
): boolean {
function checkValueOfType(source: Value, target: Type, diagnosticTarget: Entity | Node): boolean {
const [related, diagnostics] = relation.isValueOfType(source, target, diagnosticTarget);
if (!related) {
reportCheckerDiagnostics(diagnostics);
Expand Down
9 changes: 7 additions & 2 deletions packages/compiler/src/core/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,13 @@ const diagnostics = {
unassignable: {
severity: "error",
messages: {
default: paramMessage`Type '${"value"}' is not assignable to type '${"targetType"}'`,
withDetails: paramMessage`Type '${"sourceType"}' is not assignable to type '${"targetType"}'\n ${"details"}`,
default: paramMessage`Type '${"sourceType"}' is not assignable to type '${"targetType"}'`,
},
},
"property-unassignable": {
severity: "error",
messages: {
default: paramMessage`Types of property '${"propName"}' are incompatible`,
},
},
"property-required": {
Expand Down
Loading

0 comments on commit 03d4fca

Please sign in to comment.