[fine] A lot more typing/environmenting, doing better on example
Time to start actual tests
This commit is contained in:
parent
28ec6b5e85
commit
a8ab907eee
1 changed files with 104 additions and 11 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue