[fine] A lot more typing/environmenting, doing better on example

Time to start actual tests
This commit is contained in:
John Doty 2024-02-04 20:19:08 -08:00
parent 28ec6b5e85
commit a8ab907eee

View file

@ -634,11 +634,12 @@ impl<'a> Semantics<'a> {
};
let result = match tree.kind {
TreeKind::IsExpression => self.environment_of_is_expression(parent, tree),
TreeKind::Block => self.environment_of_block(parent, tree),
TreeKind::File => self.environment_of_file(parent, tree),
TreeKind::ForStatement => self.environment_of_for(parent, tree),
TreeKind::IsExpression => self.environment_of_is_expression(parent, tree),
TreeKind::LetStatement => self.environment_of_let(parent, tree),
TreeKind::MatchArm => self.environment_of_match_arm(parent, t, tree),
TreeKind::MemberAccess => self.environment_of_member_access(tree),
TreeKind::ParamList => self.environment_of_paramlist(parent, tree),
@ -865,6 +866,45 @@ impl<'a> Semantics<'a> {
self.environment_of_pattern(parent, pattern, lhs)
}
fn environment_of_match_arm(
&self,
parent: EnvironmentRef,
t: TreeRef,
tree: &Tree,
) -> EnvironmentRef {
assert_eq!(tree.kind, TreeKind::MatchArm);
// The environment of a `match arm` expression is the environment produced by the pattern.
let Some(pattern) = tree.child_tree_of_kind(self.syntax_tree, TreeKind::Pattern) else {
// Should really have a pattern in there; otherwise there was a
// parse error, don't make more trouble.
return Environment::error();
};
// The expression in the match expression is the binding for the wildcard pattern.
// If we are somewhere weird then... uh....
let Some(match_body) = tree.parent else {
self.internal_compiler_error(Some(t), "no parent on match arm");
};
let match_body = &self.syntax_tree[match_body];
if match_body.kind != TreeKind::MatchBody {
self.internal_compiler_error(Some(t), "match arm parent not match body");
}
let Some(match_expression) = match_body.parent else {
self.internal_compiler_error(Some(t), "no parent on match body");
};
let match_expression = &self.syntax_tree[match_expression];
if match_expression.kind != TreeKind::MatchExpression {
self.internal_compiler_error(Some(t), "match body parent not match expression");
}
// The expression is the first tree child of match expression.
let Some(lhs) = tree.nth_tree(1) else {
return Environment::error();
};
self.environment_of_pattern(parent, pattern, lhs)
}
// NOTE: THIS IS CALLED DIRECTLY, NOT VIA `environment_of` TO AVOID CYCLES.
fn environment_of_pattern(
&self,
@ -1061,6 +1101,11 @@ impl<'a> Semantics<'a> {
// Can... I... convert unreachable always? Is this sound?
(Type::Unreachable, _) => true,
// Alternates convert if either side can convert.
(_, Type::Alternate(left, right)) => {
self.can_convert(from, left) || self.can_convert(from, right)
}
// TODO: Unification on type variables! :D
(_, _) => false,
}
@ -1120,6 +1165,10 @@ impl<'a> Semantics<'a> {
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
TreeKind::UnaryExpression => self.type_of_unary(tree),
TreeKind::MatchExpression => self.type_of_match_expression(tree),
TreeKind::MatchBody => self.type_of_match_body(tree),
TreeKind::MatchArm => self.type_of_match_arm(tree),
_ => self.internal_compiler_error(Some(t), "asking for a nonsense type"),
};
@ -1823,6 +1872,41 @@ impl<'a> Semantics<'a> {
Some(Type::Alternate(Box::new(left), Box::new(right)))
}
fn type_of_match_expression(&self, tree: &Tree) -> Option<Type> {
Some(self.type_of(tree.child_of_kind(self.syntax_tree, TreeKind::MatchBody)?))
}
fn type_of_match_body(&self, tree: &Tree) -> Option<Type> {
let arms: Vec<_> = tree
.children_of_kind(self.syntax_tree, TreeKind::MatchArm)
.collect();
if arms.len() == 0 {
self.report_error_tree(tree, "a match expression must have at least one arm");
Some(Type::Error)
} else {
let mut actual_type = self.type_of(arms[0]);
for arm in &arms[1..] {
let arm_type = self.type_of(*arm);
if !self.can_convert(&arm_type, &actual_type) {
if self.can_convert(&actual_type, &arm_type) {
// 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}"));
}
}
}
Some(actual_type)
}
}
fn type_of_match_arm(&self, tree: &Tree) -> Option<Type> {
// The type of a match arm is the type of the expression to the right.
Some(self.type_of(tree.nth_tree(2)?))
}
pub fn dump_compiler_state(&self, tr: Option<TreeRef>) {
eprintln!("Parsed the tree as:");
eprintln!("\n{}", self.syntax_tree.dump(true));
@ -1949,13 +2033,13 @@ pub fn check(s: &Semantics) {
TreeKind::SelfParameter => {}
TreeKind::SelfReference => {}
TreeKind::IsExpression => check_is_expression(s, tree),
TreeKind::VariableBinding => check_variable_binding(s, tree),
TreeKind::IsExpression => {}
TreeKind::VariableBinding => {}
TreeKind::Pattern => check_pattern(s, tree),
TreeKind::WildcardPattern => {}
TreeKind::MatchArm => {}
TreeKind::MatchBody => {}
TreeKind::MatchArm => check_match_arm(s, tree),
TreeKind::MatchBody => check_match_body(s, t, tree),
TreeKind::MatchExpression => {}
}
}
@ -2132,10 +2216,6 @@ fn check_class_declaration(s: &Semantics, tree: &Tree) {
}
}
fn check_is_expression(_s: &Semantics, _tree: &Tree) {
// TODO
}
fn check_pattern(s: &Semantics, tree: &Tree) {
// If there's an AND then it must produce a boolean.
let and_index = tree.children.iter().position(|c| match c {
@ -2156,9 +2236,22 @@ fn check_pattern(s: &Semantics, tree: &Tree) {
}
}
fn check_variable_binding(_s: &Semantics, _tree: &Tree) {
// TODO
fn check_match_body(s: &Semantics, t: TreeRef, tree: &Tree) {
let _ = s.type_of(t); // Checks arm count and compatibility.
let arms: Vec<_> = tree
.children_of_kind(s.syntax_tree, TreeKind::MatchArm)
.collect();
if arms.len() > 0 {
for arm in &arms[1..] {
// TODO: How do I know if it's complete?
// TODO: How do I know if it's redundant?
}
}
}
fn check_match_arm(s: &Semantics, tree: &Tree) {}
#[cfg(test)]
mod tests {