Special-case some more list error messages

This commit is contained in:
Richard Feldman 2025-06-28 22:26:10 -04:00
parent a017569916
commit bdc9997157
No known key found for this signature in database
12 changed files with 243 additions and 44 deletions

View file

@ -332,6 +332,7 @@ pub fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx) void {
.incompatible_elem_var = @enumFromInt(@intFromEnum(elem_expr_id)),
.incompatible_elem_snapshot = incompatible_snapshot,
.incompatible_elem_index = i,
.list_length = elems.len,
},
});

View file

@ -222,38 +222,54 @@ pub const Problem = union(enum) {
// Add description
buf.clearRetainingCapacity();
try buf.appendSlice("The ");
try appendOrdinal(buf, data.first_elem_index + 1);
try buf.appendSlice(" and ");
try appendOrdinal(buf, data.incompatible_elem_index + 1);
try buf.appendSlice(" elements in this list have incompatible types:");
if (data.list_length == 2) {
// Special case for lists with exactly 2 elements
try buf.appendSlice("The two elements in this list have incompatible types:");
} else if (data.first_elem_index == 0 and data.incompatible_elem_index == 1) {
// Special case for first two elements in longer lists
try buf.appendSlice("The first two elements in this list have incompatible types:");
} else {
try buf.appendSlice("The ");
try appendOrdinal(buf, data.first_elem_index + 1);
try buf.appendSlice(" and ");
try appendOrdinal(buf, data.incompatible_elem_index + 1);
try buf.appendSlice(" elements in this list have incompatible types:");
}
const owned_description = try report.addOwnedString(buf.items);
try report.document.addText(owned_description);
try report.document.addLineBreak();
// Show a single region spanning both mismatched elements
const span_start = if (data.first_elem_region.start.offset < data.incompatible_elem_region.start.offset)
data.first_elem_region.start
else
data.incompatible_elem_region.start;
const span_end = if (data.first_elem_region.end.offset > data.incompatible_elem_region.end.offset)
data.first_elem_region.end
else
data.incompatible_elem_region.end;
const span_region_info = base.RegionInfo.position(
// Show the two elements with separate underlines
// First element
const first_elem_region_info = base.RegionInfo.position(
source,
module_env.line_starts.items,
span_start.offset,
span_end.offset,
data.first_elem_region.start.offset,
data.first_elem_region.end.offset,
) catch return report;
try report.document.addSourceRegion(
source,
span_region_info.start_line_idx,
span_region_info.start_col_idx,
span_region_info.end_line_idx,
span_region_info.end_col_idx,
first_elem_region_info.start_line_idx,
first_elem_region_info.start_col_idx,
first_elem_region_info.end_line_idx,
first_elem_region_info.end_col_idx,
.error_highlight,
filename,
);
// Second element
const incompatible_elem_region_info = base.RegionInfo.position(
source,
module_env.line_starts.items,
data.incompatible_elem_region.start.offset,
data.incompatible_elem_region.end.offset,
) catch return report;
try report.document.addSourceRegion(
source,
incompatible_elem_region_info.start_line_idx,
incompatible_elem_region_info.start_col_idx,
incompatible_elem_region_info.end_line_idx,
incompatible_elem_region_info.end_col_idx,
.error_highlight,
filename,
);
@ -454,6 +470,7 @@ pub const IncompatibleListElements = struct {
incompatible_elem_var: Var,
incompatible_elem_snapshot: SnapshotContentIdx,
incompatible_elem_index: usize, // 0-based index of the incompatible element
list_length: usize, // Total number of elements in the list
};
/// A two var problem

View file

@ -9,12 +9,17 @@ type=expr
~~~
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The first and second elements in this list have incompatible types:
**can_list_first_concrete.md:1:2:1:13:**
The first two elements in this list have incompatible types:
**can_list_first_concrete.md:1:2:1:4:**
```roc
[42, "world", 3.14]
```
^^^^^^^^^^^
^^
**can_list_first_concrete.md:1:6:1:13:**
```roc
[42, "world", 3.14]
```
^^^^^^^
The first element has this type:
_Num(*)_

View file

@ -9,12 +9,17 @@ type=expr
~~~
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The first and second elements in this list have incompatible types:
**can_list_heterogeneous.md:1:2:1:12:**
The first two elements in this list have incompatible types:
**can_list_heterogeneous.md:1:2:1:3:**
```roc
[1, "hello", 3.14]
```
^^^^^^^^^^
^
**can_list_heterogeneous.md:1:5:1:12:**
```roc
[1, "hello", 3.14]
```
^^^^^^^
The first element has this type:
_Num(*)_

View file

@ -0,0 +1,72 @@
# META
~~~ini
description=Multiline list with type mismatch
type=expr
~~~
# SOURCE
~~~roc
[
42,
"hello world",
100
]
~~~
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The first two elements in this list have incompatible types:
**can_list_multiline_mismatch.md:2:5:2:7:**
```roc
42,
```
^^
**can_list_multiline_mismatch.md:3:5:3:18:**
```roc
"hello world",
```
^^^^^^^^^^^^^
The first element has this type:
_Num(*)_
However, the second element has this type:
_Str_
All elements in a list must have compatible types.
# TOKENS
~~~zig
OpenSquare(1:1-1:2),Newline(1:1-1:1),
Int(2:5-2:7),Comma(2:7-2:8),Newline(1:1-1:1),
StringStart(3:5-3:6),StringPart(3:6-3:17),StringEnd(3:17-3:18),Comma(3:18-3:19),Newline(1:1-1:1),
Int(4:5-4:8),Newline(1:1-1:1),
CloseSquare(5:1-5:2),EndOfFile(5:2-5:2),
~~~
# PARSE
~~~clojure
(e-list @1-1-5-2
(e-int @2-5-2-7 (raw "42"))
(e-string @3-5-3-18
(e-string-part @3-6-3-17 (raw "hello world")))
(e-int @4-5-4-8 (raw "100")))
~~~
# FORMATTED
~~~roc
[
42,
"hello world",
100,
]
~~~
# CANONICALIZE
~~~clojure
(e-list @1-1-5-2 (elem-var 72) (id 76)
(elems
(e-int @2-5-2-7 (value "42"))
(e-string @3-5-3-18
(e-literal @3-6-3-17 (string "hello world")))
(e-int @4-5-4-8 (value "100"))))
~~~
# TYPES
~~~clojure
(expr (id 76) (type "List(Error)"))
~~~

View file

@ -10,11 +10,16 @@ type=expr
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The second and third elements in this list have incompatible types:
**can_list_nested_heterogeneous.md:1:6:1:20:**
**can_list_nested_heterogeneous.md:1:6:1:9:**
```roc
[[], [1], ["hello"]]
```
^^^^^^^^^^^^^^
^^^
**can_list_nested_heterogeneous.md:1:11:1:20:**
```roc
[[], [1], ["hello"]]
```
^^^^^^^^^
The second element has this type:
_List(Num(*))_

View file

@ -15,12 +15,17 @@ This number literal is not valid: 1u8
This number literal is not valid: 2u8
**INCOMPATIBLE LIST ELEMENTS**
The first and second elements in this list have incompatible types:
**can_list_number_doesnt_fit.md:1:2:1:10:**
The first two elements in this list have incompatible types:
**can_list_number_doesnt_fit.md:1:2:1:5:**
```roc
[1u8, 2u8, 300]
```
^^^^^^^^
^^^
**can_list_number_doesnt_fit.md:1:7:1:10:**
```roc
[1u8, 2u8, 300]
```
^^^
The first element has this type:
_Error_

View file

@ -10,11 +10,16 @@ type=expr
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The second and third elements in this list have incompatible types:
**can_list_triple_nested_heterogeneous.md:1:6:1:32:**
**can_list_triple_nested_heterogeneous.md:1:6:1:15:**
```roc
[[], [[], [1]], [[], ["hello"]]]
```
^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^
**can_list_triple_nested_heterogeneous.md:1:17:1:32:**
```roc
[[], [[], [1]], [[], ["hello"]]]
```
^^^^^^^^^^^^^^^
The second element has this type:
_List(List(Num(*)))_

58
src/snapshots/can_list_two_elements.md generated Normal file
View file

@ -0,0 +1,58 @@
# META
~~~ini
description=List with exactly two incompatible elements
type=expr
~~~
# SOURCE
~~~roc
[1, "hello"]
~~~
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The two elements in this list have incompatible types:
**can_list_two_elements.md:1:2:1:3:**
```roc
[1, "hello"]
```
^
**can_list_two_elements.md:1:5:1:12:**
```roc
[1, "hello"]
```
^^^^^^^
The first element has this type:
_Num(*)_
However, the second element has this type:
_Str_
All elements in a list must have compatible types.
# TOKENS
~~~zig
OpenSquare(1:1-1:2),Int(1:2-1:3),Comma(1:3-1:4),StringStart(1:5-1:6),StringPart(1:6-1:11),StringEnd(1:11-1:12),CloseSquare(1:12-1:13),EndOfFile(1:13-1:13),
~~~
# PARSE
~~~clojure
(e-list @1-1-1-13
(e-int @1-2-1-3 (raw "1"))
(e-string @1-5-1-12
(e-string-part @1-6-1-11 (raw "hello"))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# CANONICALIZE
~~~clojure
(e-list @1-1-1-13 (elem-var 72) (id 75)
(elems
(e-int @1-2-1-3 (value "1"))
(e-string @1-5-1-12
(e-literal @1-6-1-11 (string "hello")))))
~~~
# TYPES
~~~clojure
(expr (id 75) (type "List(Error)"))
~~~

View file

@ -9,12 +9,17 @@ type=expr
~~~
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The first and second elements in this list have incompatible types:
**can_nested_heterogeneous_lists.md:1:3:1:13:**
The two elements in this list have incompatible types:
**can_nested_heterogeneous_lists.md:1:3:1:4:**
```roc
[[1, "hello"], [2, 3]]
```
^^^^^^^^^^
^
**can_nested_heterogeneous_lists.md:1:6:1:13:**
```roc
[[1, "hello"], [2, 3]]
```
^^^^^^^
The first element has this type:
_Num(*)_
@ -25,12 +30,17 @@ However, the second element has this type:
All elements in a list must have compatible types.
**INCOMPATIBLE LIST ELEMENTS**
The first and second elements in this list have incompatible types:
**can_nested_heterogeneous_lists.md:1:2:1:22:**
The two elements in this list have incompatible types:
**can_nested_heterogeneous_lists.md:1:2:1:14:**
```roc
[[1, "hello"], [2, 3]]
```
^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^
**can_nested_heterogeneous_lists.md:1:16:1:22:**
```roc
[[1, "hello"], [2, 3]]
```
^^^^^^
The first element has this type:
_List(Error)_

View file

@ -10,11 +10,16 @@ type=expr
# PROBLEMS
**INCOMPATIBLE LIST ELEMENTS**
The second and third elements in this list have incompatible types:
**list_type_err.md:1:5:1:15:**
**list_type_err.md:1:5:1:6:**
```roc
[1, 2, "hello"]
```
^^^^^^^^^^
^
**list_type_err.md:1:8:1:15:**
```roc
[1, 2, "hello"]
```
^^^^^^^
The second element has this type:
_Num(*)_

11
test_list_messages.txt Normal file
View file

@ -0,0 +1,11 @@
List with 2 elements, both incompatible:
[1, "hello"]
→ "The two elements in this list have incompatible types"
List with 3+ elements, first two incompatible:
[1, "hello", 3.14]
→ "The first two elements in this list have incompatible types"
List with 3+ elements, later elements incompatible:
[1, 2, "hello"]
→ "The second and third elements in this list have incompatible types"