Give an error instead of panicking on an empty tuple type

This commit is contained in:
Joshua Warner 2024-12-08 10:11:15 -08:00
parent 861f9c5d47
commit cbd6d50584
No known key found for this signature in database
GPG key ID: 89AD497003F93FDD
5 changed files with 35 additions and 25 deletions

View file

@ -887,7 +887,9 @@ fn can_annotation_help(
"tuples should never be implicitly inferred open"
);
debug_assert!(!elems.is_empty()); // We don't allow empty tuples
if elems.is_empty() {
env.problem(roc_problem::can::Problem::EmptyTupleType(region));
}
let elem_types = can_assigned_tuple_elems(
env,

View file

@ -9,7 +9,7 @@ use crate::scope::{PendingAbilitiesInScope, Scope};
use roc_exhaustive::ListArity;
use roc_module::ident::{Ident, Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_parse::ast::{self, StrLiteral, StrSegment};
use roc_parse::ast::{self, ExtractSpaces, StrLiteral, StrSegment};
use roc_parse::pattern::PatternType;
use roc_problem::can::{MalformedPatternProblem, Problem, RuntimeError, ShadowKind};
use roc_region::all::{Loc, Region};
@ -476,7 +476,14 @@ pub fn canonicalize_pattern<'a>(
Pattern::OpaqueNotInScope(Loc::at(tag.region, name.into()))
}
},
_ => unreachable!("Other patterns cannot be applied"),
_ => {
env.problem(Problem::RuntimeError(RuntimeError::MalformedPattern(
MalformedPatternProblem::CantApplyPattern,
tag.region,
)));
Pattern::UnsupportedPattern(region)
}
}
}
@ -817,7 +824,7 @@ pub fn canonicalize_record_destructs<'a>(
let mut opt_erroneous = None;
for loc_pattern in patterns.iter() {
match loc_pattern.value {
match loc_pattern.value.extract_spaces().item {
Identifier { ident: label } => {
match scope.introduce(label.into(), region) {
Ok(symbol) => {

View file

@ -255,6 +255,7 @@ pub enum Problem {
StmtAfterExpr(Region),
UnsuffixedEffectfulRecordField(Region),
SuffixedPureRecordField(Region),
EmptyTupleType(Region),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -343,6 +344,7 @@ impl Problem {
Problem::UnsuffixedEffectfulRecordField(_) | Problem::SuffixedPureRecordField(..) => {
Warning
}
Problem::EmptyTupleType(_) => Warning,
}
}
@ -455,6 +457,7 @@ impl Problem {
| Problem::RuntimeError(RuntimeError::ReadIngestedFileError { region, .. })
| Problem::InvalidAliasRigid { region, .. }
| Problem::InvalidInterpolation(region)
| Problem::EmptyTupleType(region)
| Problem::InvalidHexadecimal(region)
| Problem::InvalidUnicodeCodePt(region)
| Problem::NestedDatatype {
@ -791,4 +794,5 @@ pub enum MalformedPatternProblem {
EmptySingleQuote,
MultipleCharsInSingleQuote,
DuplicateListRestPattern,
CantApplyPattern,
}

View file

@ -705,26 +705,10 @@ mod test_snapshots {
// We should be driving these down to zero over time.
// Adding this protection in now to avoid accidentally adding more.
"all_the_bangs"
| "ann_record_pat_with_comment"
| "comment_indent_in_parens"
| "crazy_annotation_left"
| "crazy_annotation_left2"
| "crazy_pat_ann"
| "import_in_closure_with_curlies_after"
| "inline_import"
| "mega_parens_pat"
| "multiline_str_in_pat"
| "newline_before_import_curlies"
| "pattern_comma_newlines"
| "pattern_record_apply_comment"
| "triple_paren_pat_ann" => true,
| "newline_before_import_curlies" => true,
"annotation_tuple_comment"
| "annotation_tuple_parens_newlines"
| "comment_in_tuple_ext" => {
// These tests all hit `debug_assert!(!elems.is_empty());`
cfg!(debug_assertions)
}
// When adding new snapshot tests, strongly prefer fixing any canonicalization panics
// they may run into rather than adding them to this list.
_ => false,

View file

@ -67,6 +67,7 @@ const INCOMPLETE_ABILITY_IMPLEMENTATION: &str = "INCOMPLETE ABILITY IMPLEMENTATI
const STATEMENT_AFTER_EXPRESSION: &str = "STATEMENT AFTER EXPRESSION";
const MISSING_EXCLAMATION: &str = "MISSING EXCLAMATION";
const UNNECESSARY_EXCLAMATION: &str = "UNNECESSARY EXCLAMATION";
const EMPTY_TUPLE_TYPE: &str = "EMPTY TUPLE TYPE";
pub fn can_problem<'b>(
alloc: &'b RocDocAllocator<'b>,
@ -1472,6 +1473,16 @@ pub fn can_problem<'b>(
title = UNNECESSARY_EXCLAMATION.to_string();
}
Problem::EmptyTupleType(region) => {
doc = alloc.stack([
alloc.reflow("This tuple type is empty:"),
alloc.region(lines.convert_region(region), severity),
alloc.reflow("Empty tuple types are not allowed in Roc."),
]);
title = EMPTY_TUPLE_TYPE.to_string();
}
};
Report {
@ -2092,7 +2103,7 @@ fn pretty_runtime_error<'b>(
return (doc, title);
}
Unknown => " ",
Unknown | CantApplyPattern => " ",
QualifiedIdentifier => " qualified ",
EmptySingleQuote => " empty character literal ",
MultipleCharsInSingleQuote => " overfull literal ",
@ -2103,9 +2114,11 @@ fn pretty_runtime_error<'b>(
MalformedInt | MalformedFloat | MalformedBase(_) => alloc
.tip()
.append(alloc.reflow("Learn more about number literals at TODO")),
EmptySingleQuote | MultipleCharsInSingleQuote | Unknown | BadIdent(_) => {
alloc.nil()
}
EmptySingleQuote
| MultipleCharsInSingleQuote
| Unknown
| BadIdent(_)
| CantApplyPattern => alloc.nil(),
QualifiedIdentifier => alloc
.tip()
.append(alloc.reflow("In patterns, only tags can be qualified")),