[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> {
|
fn type_of_conditional(&self, tree: &Tree) -> Option<Type> {
|
||||||
assert_eq!(tree.kind, TreeKind::ConditionalExpression);
|
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 then_type = self.type_of(tree.nth_tree(2)?);
|
||||||
|
|
||||||
let has_else = tree
|
let has_else = tree
|
||||||
|
|
@ -1647,38 +1645,18 @@ impl<'a> Semantics<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.can_convert(&cond_type, &Type::Bool) {
|
match (then_type, else_type) {
|
||||||
if !cond_type.is_error() {
|
(Type::Error, _) => Some(Type::Error),
|
||||||
self.report_error_tree_ref(cond_tree, "conditions must yield a boolean");
|
(_, Some(Type::Error)) => Some(Type::Error),
|
||||||
}
|
|
||||||
Some(Type::Error)
|
|
||||||
} else {
|
|
||||||
match (then_type, else_type) {
|
|
||||||
(Type::Error, _) => Some(Type::Error),
|
|
||||||
(_, Some(Type::Error)) => Some(Type::Error),
|
|
||||||
|
|
||||||
(Type::Unreachable, None) => Some(Type::Nothing),
|
(Type::Unreachable, None) => Some(Type::Nothing),
|
||||||
(Type::Unreachable, Some(t)) => Some(t),
|
(Type::Unreachable, Some(t)) => Some(t),
|
||||||
(t, Some(Type::Unreachable)) => Some(t),
|
(t, Some(Type::Unreachable)) => Some(t),
|
||||||
|
|
||||||
(then_type, else_type) => {
|
(then_type, else_type) => {
|
||||||
let else_type = else_type.unwrap_or(Type::Nothing);
|
let else_type = else_type.unwrap_or(Type::Nothing);
|
||||||
if self.can_convert(&then_type, &else_type) {
|
|
||||||
Some(else_type)
|
Some(self.build_alternate(&then_type, &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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2097,7 +2075,7 @@ impl<'a> Semantics<'a> {
|
||||||
// New lowest-common-denominator type
|
// New lowest-common-denominator type
|
||||||
actual_type = arm_type;
|
actual_type = arm_type;
|
||||||
} else {
|
} 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::LiteralExpression
|
||||||
| TreeKind::GroupingExpression
|
| TreeKind::GroupingExpression
|
||||||
| TreeKind::UnaryExpression
|
| TreeKind::UnaryExpression
|
||||||
| TreeKind::ConditionalExpression
|
|
||||||
| TreeKind::BinaryExpression
|
| TreeKind::BinaryExpression
|
||||||
| TreeKind::MemberAccess => {
|
| TreeKind::MemberAccess => {
|
||||||
let _ = s.type_of(t);
|
let _ = s.type_of(t);
|
||||||
}
|
}
|
||||||
|
TreeKind::ConditionalExpression => check_conditional(s, tree),
|
||||||
TreeKind::CallExpression => {
|
TreeKind::CallExpression => {
|
||||||
let _ = s.type_of(t);
|
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) {
|
fn check_function_decl(s: &Semantics, t: TreeRef, tree: &Tree) {
|
||||||
assert_eq!(tree.kind, TreeKind::FunctionDecl);
|
assert_eq!(tree.kind, TreeKind::FunctionDecl);
|
||||||
let _ = s.environment_of(t);
|
let _ = s.environment_of(t);
|
||||||
|
|
@ -2576,7 +2569,7 @@ fn check_pattern(s: &Semantics, tree: &Tree) {
|
||||||
// TODO: TEST
|
// TODO: TEST
|
||||||
s.report_error_tree_ref(
|
s.report_error_tree_ref(
|
||||||
pred,
|
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) {
|
if !s.can_convert(&expr_type, &Type::Bool) {
|
||||||
s.report_error_tree_ref(
|
s.report_error_tree_ref(
|
||||||
expr,
|
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.
|
// like the above.
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ignore WIP
|
/// @ignore WIP
|
||||||
// @no-errors
|
// @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" }
|
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 }
|
if (if false { true }) { 32 } else { 23 }
|
||||||
|
|
||||||
// @expect-errors:
|
// @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:
|
// @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