[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 {
|
let result = match tree.kind {
|
||||||
TreeKind::IsExpression => self.environment_of_is_expression(parent, tree),
|
|
||||||
TreeKind::Block => self.environment_of_block(parent, tree),
|
TreeKind::Block => self.environment_of_block(parent, tree),
|
||||||
TreeKind::File => self.environment_of_file(parent, tree),
|
TreeKind::File => self.environment_of_file(parent, tree),
|
||||||
TreeKind::ForStatement => self.environment_of_for(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::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::MemberAccess => self.environment_of_member_access(tree),
|
||||||
TreeKind::ParamList => self.environment_of_paramlist(parent, tree),
|
TreeKind::ParamList => self.environment_of_paramlist(parent, tree),
|
||||||
|
|
||||||
|
|
@ -865,6 +866,45 @@ impl<'a> Semantics<'a> {
|
||||||
self.environment_of_pattern(parent, pattern, lhs)
|
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.
|
// NOTE: THIS IS CALLED DIRECTLY, NOT VIA `environment_of` TO AVOID CYCLES.
|
||||||
fn environment_of_pattern(
|
fn environment_of_pattern(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -1061,6 +1101,11 @@ impl<'a> Semantics<'a> {
|
||||||
// Can... I... convert unreachable always? Is this sound?
|
// Can... I... convert unreachable always? Is this sound?
|
||||||
(Type::Unreachable, _) => true,
|
(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
|
// TODO: Unification on type variables! :D
|
||||||
(_, _) => false,
|
(_, _) => false,
|
||||||
}
|
}
|
||||||
|
|
@ -1120,6 +1165,10 @@ impl<'a> Semantics<'a> {
|
||||||
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
|
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
|
||||||
TreeKind::UnaryExpression => self.type_of_unary(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"),
|
_ => 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)))
|
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>) {
|
pub fn dump_compiler_state(&self, tr: Option<TreeRef>) {
|
||||||
eprintln!("Parsed the tree as:");
|
eprintln!("Parsed the tree as:");
|
||||||
eprintln!("\n{}", self.syntax_tree.dump(true));
|
eprintln!("\n{}", self.syntax_tree.dump(true));
|
||||||
|
|
@ -1949,13 +2033,13 @@ pub fn check(s: &Semantics) {
|
||||||
TreeKind::SelfParameter => {}
|
TreeKind::SelfParameter => {}
|
||||||
TreeKind::SelfReference => {}
|
TreeKind::SelfReference => {}
|
||||||
|
|
||||||
TreeKind::IsExpression => check_is_expression(s, tree),
|
TreeKind::IsExpression => {}
|
||||||
TreeKind::VariableBinding => check_variable_binding(s, tree),
|
TreeKind::VariableBinding => {}
|
||||||
TreeKind::Pattern => check_pattern(s, tree),
|
TreeKind::Pattern => check_pattern(s, tree),
|
||||||
TreeKind::WildcardPattern => {}
|
TreeKind::WildcardPattern => {}
|
||||||
|
|
||||||
TreeKind::MatchArm => {}
|
TreeKind::MatchArm => check_match_arm(s, tree),
|
||||||
TreeKind::MatchBody => {}
|
TreeKind::MatchBody => check_match_body(s, t, tree),
|
||||||
TreeKind::MatchExpression => {}
|
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) {
|
fn check_pattern(s: &Semantics, tree: &Tree) {
|
||||||
// If there's an AND then it must produce a boolean.
|
// If there's an AND then it must produce a boolean.
|
||||||
let and_index = tree.children.iter().position(|c| match c {
|
let and_index = tree.children.iter().position(|c| match c {
|
||||||
|
|
@ -2156,10 +2236,23 @@ fn check_pattern(s: &Semantics, tree: &Tree) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_variable_binding(_s: &Semantics, _tree: &Tree) {
|
fn check_match_body(s: &Semantics, t: TreeRef, tree: &Tree) {
|
||||||
// TODO
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue