mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Tweak an error message
This commit is contained in:
parent
843da2f239
commit
b490acffee
7 changed files with 157 additions and 45 deletions
|
|
@ -143,17 +143,18 @@ pub fn tokenizeDiagnosticToReport(self: *AST, diagnostic: tokenize.Diagnostic, a
|
|||
|
||||
var report = reporting.Report.init(allocator, title, .runtime_error);
|
||||
try report.document.addText(body);
|
||||
|
||||
|
||||
// Add the region information from the diagnostic if valid
|
||||
if (diagnostic.region.start.offset < diagnostic.region.end.offset and
|
||||
diagnostic.region.end.offset <= self.env.source.len) {
|
||||
|
||||
if (diagnostic.region.start.offset < diagnostic.region.end.offset and
|
||||
diagnostic.region.end.offset <= self.env.source.len)
|
||||
{
|
||||
|
||||
// Calculate line starts if not already done
|
||||
var env = self.env.*;
|
||||
if (env.line_starts.items.items.len == 0) {
|
||||
try env.calcLineStarts(allocator);
|
||||
}
|
||||
|
||||
|
||||
// Convert region to RegionInfo
|
||||
const region_info = base.RegionInfo.position(
|
||||
self.env.source,
|
||||
|
|
@ -164,7 +165,7 @@ pub fn tokenizeDiagnosticToReport(self: *AST, diagnostic: tokenize.Diagnostic, a
|
|||
// If we can't calculate region info, just return the report without source context
|
||||
return report;
|
||||
};
|
||||
|
||||
|
||||
// Add source region to the report
|
||||
try report.document.addSourceRegion(
|
||||
region_info,
|
||||
|
|
@ -174,7 +175,7 @@ pub fn tokenizeDiagnosticToReport(self: *AST, diagnostic: tokenize.Diagnostic, a
|
|||
env.line_starts.items.items,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
|
|
@ -541,9 +542,11 @@ pub fn parseDiagnosticToReport(self: *AST, env: *const CommonEnv, diagnostic: Di
|
|||
try report.document.addLineBreak();
|
||||
try report.document.addReflowingText("When ");
|
||||
try report.document.addKeyword("if");
|
||||
try report.document.addReflowingText(" is used as an expression (to produce a value), it must have an ");
|
||||
try report.document.addReflowingText(" is used as an expression (to evaluate to a value), it must have an ");
|
||||
try report.document.addKeyword("else");
|
||||
try report.document.addReflowingText(" branch to handle the case when the condition is false.");
|
||||
try report.document.addReflowingText(" branch to specify what value to use when the condition is ");
|
||||
try report.document.addKeyword("False");
|
||||
try report.document.addReflowingText(".");
|
||||
},
|
||||
else => {
|
||||
const tag_name = @tagName(diagnostic.tag);
|
||||
|
|
|
|||
|
|
@ -1168,29 +1168,65 @@ fn parseStmtByType(self: *Parser, statementType: StatementType) Error!?AST.State
|
|||
// continue to parse final expression
|
||||
}
|
||||
},
|
||||
// Expect to parse a Type Annotation, e.g. `Foo a : (a,a)`
|
||||
// Could be a Type Annotation (e.g. `Foo a : (a,a)`) or a pattern assignment (e.g. `Pair(x, y) = expr`)
|
||||
.UpperIdent => {
|
||||
const start = self.pos;
|
||||
if (statementType == .top_level) {
|
||||
const header = try self.parseTypeHeader();
|
||||
if (self.peek() != .OpColon and self.peek() != .OpColonEqual) {
|
||||
// Point to the unexpected token (e.g., "U8" in "List U8")
|
||||
return try self.pushMalformed(AST.Statement.Idx, .expected_colon_after_type_annotation, self.pos);
|
||||
// Look ahead to determine if this is a type declaration or pattern assignment
|
||||
// We need to check what comes after the identifier and any parentheses
|
||||
var lookahead_pos = self.pos + 1;
|
||||
var paren_depth: u32 = 0;
|
||||
|
||||
// Skip past any parentheses to find what operator follows
|
||||
while (lookahead_pos < self.tok_buf.tokens.len) {
|
||||
const tok = self.tok_buf.tokens.items(.tag)[lookahead_pos];
|
||||
if (tok == .OpenRound or tok == .NoSpaceOpenRound) {
|
||||
paren_depth += 1;
|
||||
} else if (tok == .CloseRound) {
|
||||
if (paren_depth == 0) break;
|
||||
paren_depth -= 1;
|
||||
if (paren_depth == 0) {
|
||||
lookahead_pos += 1;
|
||||
break;
|
||||
}
|
||||
} else if (paren_depth == 0) {
|
||||
// We're not in parentheses, so check what token we have
|
||||
break;
|
||||
}
|
||||
lookahead_pos += 1;
|
||||
}
|
||||
|
||||
// Check what token follows the identifier (and any parentheses)
|
||||
const next_tok = if (lookahead_pos < self.tok_buf.tokens.len)
|
||||
self.tok_buf.tokens.items(.tag)[lookahead_pos]
|
||||
else
|
||||
.EndOfFile;
|
||||
|
||||
// If it's OpAssign, this is a pattern assignment, not a type declaration
|
||||
if (next_tok == .OpAssign) {
|
||||
// Fall through to parse as a pattern assignment
|
||||
} else {
|
||||
// Parse as a type declaration
|
||||
const header = try self.parseTypeHeader();
|
||||
if (self.peek() != .OpColon and self.peek() != .OpColonEqual) {
|
||||
// Point to the unexpected token (e.g., "U8" in "List U8")
|
||||
return try self.pushMalformed(AST.Statement.Idx, .expected_colon_after_type_annotation, self.pos);
|
||||
}
|
||||
const kind: AST.TypeDeclKind = if (self.peek() == .OpColonEqual) .nominal else .alias;
|
||||
self.advance();
|
||||
const anno = try self.parseTypeAnno(.not_looking_for_args);
|
||||
const where_clause = try self.parseWhereConstraint();
|
||||
// Use the type annotation's end position if there's no where clause,
|
||||
// otherwise use the current position (after parsing where clause)
|
||||
const statement_idx = try self.store.addStatement(.{ .type_decl = .{
|
||||
.header = header,
|
||||
.anno = anno,
|
||||
.where = where_clause,
|
||||
.kind = kind,
|
||||
.region = .{ .start = start, .end = self.pos },
|
||||
} });
|
||||
return statement_idx;
|
||||
}
|
||||
const kind: AST.TypeDeclKind = if (self.peek() == .OpColonEqual) .nominal else .alias;
|
||||
self.advance();
|
||||
const anno = try self.parseTypeAnno(.not_looking_for_args);
|
||||
const where_clause = try self.parseWhereConstraint();
|
||||
// Use the type annotation's end position if there's no where clause,
|
||||
// otherwise use the current position (after parsing where clause)
|
||||
const statement_idx = try self.store.addStatement(.{ .type_decl = .{
|
||||
.header = header,
|
||||
.anno = anno,
|
||||
.where = where_clause,
|
||||
.kind = kind,
|
||||
.region = .{ .start = start, .end = self.pos },
|
||||
} });
|
||||
return statement_idx;
|
||||
}
|
||||
},
|
||||
.OpenCurly, .OpenRound => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ UNKNOWN OPERATOR - expr_if_missing_else.md:3:7:3:15
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**expr_if_missing_else.md:3:7:3:9:**
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ Pair2(_, y) = Pair(0, 1)
|
|||
Pair3(_, _) = Pair(0, 1)
|
||||
~~~
|
||||
# EXPECTED
|
||||
PARSE ERROR - underscore_type_decl.md:5:1:5:6
|
||||
PARSE ERROR - underscore_type_decl.md:5:6:5:7
|
||||
PARSE ERROR - underscore_type_decl.md:5:7:5:8
|
||||
PARSE ERROR - underscore_type_decl.md:5:8:5:9
|
||||
PARSE ERROR - underscore_type_decl.md:5:10:5:11
|
||||
PARSE ERROR - underscore_type_decl.md:5:11:5:12
|
||||
PARSE ERROR - underscore_type_decl.md:5:13:5:14
|
||||
PARSE ERROR - underscore_type_decl.md:5:20:5:21
|
||||
PARSE ERROR - underscore_type_decl.md:5:23:5:24
|
||||
|
|
@ -39,20 +45,80 @@ PARSE ERROR - underscore_type_decl.md:7:25:7:25
|
|||
MODULE NOT FOUND - underscore_type_decl.md:3:1:3:30
|
||||
# PROBLEMS
|
||||
**PARSE ERROR**
|
||||
Type applications require parentheses around their type arguments.
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
I found a type followed by what looks like a type argument, but they need to be connected with parentheses.
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:1:5:6:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^^^^^
|
||||
|
||||
Instead of:
|
||||
**List U8**
|
||||
|
||||
Use:
|
||||
**List(U8)**
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Other valid examples:
|
||||
`Dict(Str, Num)`
|
||||
`Result(a, Str)`
|
||||
`Maybe(List(U64))`
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:6:5:7:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^
|
||||
|
||||
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:7:5:8:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^
|
||||
|
||||
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:8:5:9:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^
|
||||
|
||||
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:10:5:11:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^
|
||||
|
||||
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:11:5:12:**
|
||||
```roc
|
||||
Pair1(x, _) = Pair(0, 1)
|
||||
```
|
||||
^
|
||||
|
||||
|
||||
**PARSE ERROR**
|
||||
A parsing error occurred: `statement_unexpected_token`
|
||||
This is an unexpected parsing error. Please check your syntax.
|
||||
|
||||
Here is the problematic code:
|
||||
**underscore_type_decl.md:5:13:5:14:**
|
||||
|
|
@ -378,7 +444,13 @@ UpperIdent(7:1-7:6),NoSpaceOpenRound(7:6-7:7),Underscore(7:7-7:8),Comma(7:8-7:9)
|
|||
(s-import @3.1-3.30 (raw "Module")
|
||||
(exposing
|
||||
(exposed-upper-ident @3.25-3.29 (text "Pair"))))
|
||||
(s-malformed @5.13-5.14 (tag "expected_colon_after_type_annotation"))
|
||||
(s-malformed @5.1-5.6 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.6-5.7 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.7-5.8 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.8-5.9 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.10-5.11 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.11-5.12 (tag "statement_unexpected_token"))
|
||||
(s-malformed @5.13-5.14 (tag "statement_unexpected_token"))
|
||||
(s-malformed @6.1-6.6 (tag "expected_colon_after_type_annotation"))
|
||||
(s-malformed @6.6-6.7 (tag "statement_unexpected_token"))
|
||||
(s-malformed @6.7-6.8 (tag "statement_unexpected_token"))
|
||||
|
|
@ -403,6 +475,7 @@ import Module exposing [Pair]
|
|||
|
||||
|
||||
|
||||
|
||||
~~~
|
||||
# CANONICALIZE
|
||||
~~~clojure
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Here is the problematic code:
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**guards_1.md:2:7:2:9:**
|
||||
|
|
@ -212,7 +212,7 @@ Here is the problematic code:
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**guards_1.md:3:7:3:9:**
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Here is the problematic code:
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**guards_2.md:2:25:2:27:**
|
||||
|
|
@ -213,7 +213,7 @@ Here is the problematic code:
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**guards_2.md:3:12:3:14:**
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ Here is the problematic code:
|
|||
**IF WITHOUT ELSE**
|
||||
This `if` is being used as an expression, but it doesn't have an `else`.
|
||||
|
||||
When `if` is used as an expression (to produce a value), it must have an `else` branch to handle the case when the condition is false.
|
||||
When `if` is used as an expression (to evaluate to a value), it must have an `else` branch to specify what value to use when the condition is `False`.
|
||||
|
||||
Here is the problematic code:
|
||||
**record_different_fields_reserved_error.md:2:5:2:7:**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue