[fine] Conditionals produce alternates (yikes!)
This commit is contained in:
parent
8b9a69b898
commit
b43947b6f1
6 changed files with 35 additions and 44 deletions
|
|
@ -1633,8 +1633,6 @@ impl<'a> Semantics<'a> {
|
|||
fn type_of_conditional(&self, tree: &Tree) -> Option<Type> {
|
||||
assert_eq!(tree.kind, TreeKind::ConditionalExpression);
|
||||
|
||||
let cond_tree = tree.nth_tree(1)?;
|
||||
let cond_type = self.type_of(cond_tree);
|
||||
let then_type = self.type_of(tree.nth_tree(2)?);
|
||||
|
||||
let has_else = tree
|
||||
|
|
@ -1647,38 +1645,18 @@ impl<'a> Semantics<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
if !self.can_convert(&cond_type, &Type::Bool) {
|
||||
if !cond_type.is_error() {
|
||||
self.report_error_tree_ref(cond_tree, "conditions must yield a boolean");
|
||||
}
|
||||
Some(Type::Error)
|
||||
} else {
|
||||
match (then_type, else_type) {
|
||||
(Type::Error, _) => Some(Type::Error),
|
||||
(_, Some(Type::Error)) => Some(Type::Error),
|
||||
match (then_type, else_type) {
|
||||
(Type::Error, _) => Some(Type::Error),
|
||||
(_, Some(Type::Error)) => Some(Type::Error),
|
||||
|
||||
(Type::Unreachable, None) => Some(Type::Nothing),
|
||||
(Type::Unreachable, Some(t)) => Some(t),
|
||||
(t, Some(Type::Unreachable)) => Some(t),
|
||||
(Type::Unreachable, None) => Some(Type::Nothing),
|
||||
(Type::Unreachable, Some(t)) => Some(t),
|
||||
(t, Some(Type::Unreachable)) => Some(t),
|
||||
|
||||
(then_type, else_type) => {
|
||||
let else_type = else_type.unwrap_or(Type::Nothing);
|
||||
if self.can_convert(&then_type, &else_type) {
|
||||
Some(else_type)
|
||||
// I know, I know, as of this writing there is no real
|
||||
// reason to ever check this, because this relationship
|
||||
// is symmetrical. But someday it won't be, and you'll be
|
||||
// glad I had the forethought to be thorough.
|
||||
} else if self.can_convert(&else_type, &then_type) {
|
||||
Some(then_type)
|
||||
} else {
|
||||
self.report_error_tree(
|
||||
tree,
|
||||
format!("the type of the 'then' branch ('{then_type}') must match the type of the 'else' branch ('{else_type}')"),
|
||||
);
|
||||
Some(Type::Error)
|
||||
}
|
||||
}
|
||||
(then_type, else_type) => {
|
||||
let else_type = else_type.unwrap_or(Type::Nothing);
|
||||
|
||||
Some(self.build_alternate(&then_type, &else_type))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2097,7 +2075,7 @@ impl<'a> Semantics<'a> {
|
|||
// New lowest-common-denominator type
|
||||
actual_type = arm_type;
|
||||
} else {
|
||||
self.report_error_tree_ref(*arm, format!("this arm produces a value of type {arm_type} which is incompatible with the general result type {actual_type}"));
|
||||
self.report_error_tree_ref(*arm, format!("this arm produces a value of type '{arm_type}' which is incompatible with the general result type {actual_type}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2342,11 +2320,11 @@ pub fn check(s: &Semantics) {
|
|||
| TreeKind::LiteralExpression
|
||||
| TreeKind::GroupingExpression
|
||||
| TreeKind::UnaryExpression
|
||||
| TreeKind::ConditionalExpression
|
||||
| TreeKind::BinaryExpression
|
||||
| TreeKind::MemberAccess => {
|
||||
let _ = s.type_of(t);
|
||||
}
|
||||
TreeKind::ConditionalExpression => check_conditional(s, tree),
|
||||
TreeKind::CallExpression => {
|
||||
let _ = s.type_of(t);
|
||||
}
|
||||
|
|
@ -2392,6 +2370,21 @@ pub fn check(s: &Semantics) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_conditional(s: &Semantics, tree: &Tree) {
|
||||
let Some(cond_tree) = tree.nth_tree(1) else {
|
||||
return;
|
||||
};
|
||||
let cond_type = s.type_of(cond_tree);
|
||||
if !s.can_convert(&cond_type, &Type::Bool) {
|
||||
if !cond_type.is_error() {
|
||||
s.report_error_tree_ref(
|
||||
cond_tree,
|
||||
format!("this condition produces '{cond_type}', but must produce bool"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_function_decl(s: &Semantics, t: TreeRef, tree: &Tree) {
|
||||
assert_eq!(tree.kind, TreeKind::FunctionDecl);
|
||||
let _ = s.environment_of(t);
|
||||
|
|
@ -2576,7 +2569,7 @@ fn check_pattern(s: &Semantics, tree: &Tree) {
|
|||
// TODO: TEST
|
||||
s.report_error_tree_ref(
|
||||
pred,
|
||||
format!("this predicate produces {predicate_type}, but must produce a boolean"),
|
||||
format!("this predicate produces '{predicate_type}', but must produce bool"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2609,7 +2602,7 @@ fn check_while_statement(s: &Semantics, tree: &Tree) {
|
|||
if !s.can_convert(&expr_type, &Type::Bool) {
|
||||
s.report_error_tree_ref(
|
||||
expr,
|
||||
"the condition of the while loop must produce a boolean",
|
||||
format!("this condition produces '{expr_type}', but must produce bool"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,5 +127,5 @@ fun test() -> f64 {
|
|||
// like the above.
|
||||
}
|
||||
|
||||
// @ignore WIP
|
||||
/// @ignore WIP
|
||||
// @no-errors
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
if true { "blarg" } else { 23 }
|
||||
|
||||
// @expect-errors:
|
||||
// | 1:0: the type of the 'then' branch ('string') must match the type of the 'else' branch ('f64')
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
if 23 { "what" } else { "the" }
|
||||
// @type-error: 0 conditions must yield a boolean
|
||||
|
||||
// @expect-errors:
|
||||
// | 1:3: this condition produces 'f64', but must produce bool
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
if (if false { true }) { 32 } else { 23 }
|
||||
|
||||
// @expect-errors:
|
||||
// | 1:4: the type of the 'then' branch ('bool') must match the type of the 'else' branch ('nothing')
|
||||
// | 1:3: this condition produces 'nothing or bool', but must produce bool
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ fun test() {
|
|||
}
|
||||
|
||||
// @expect-errors:
|
||||
// | 2:8: the condition of the while loop must produce a boolean
|
||||
// | 2:8: this condition produces 'f64', but must produce bool
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue