Skip to content

Commit

Permalink
[lang] Type checking support for if-let syntax (#1095)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamChou19815 authored Sep 30, 2023
1 parent ee91bbc commit 98053b6
Show file tree
Hide file tree
Showing 15 changed files with 1,026 additions and 125 deletions.
22 changes: 14 additions & 8 deletions crates/samlang-core/src/ast/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ pub(crate) mod pattern {
pub(crate) enum DestructuringPattern<T: Clone> {
Tuple(Location, Vec<TuplePatternElement<DestructuringPattern<T>, T>>),
Object(Location, Vec<ObjectPatternElement<DestructuringPattern<T>, T>>),
Id(Id),
Id(Id, T),
Wildcard(Location),
}

Expand All @@ -228,7 +228,7 @@ pub(crate) mod pattern {
match self {
Self::Tuple(loc, _)
| Self::Object(loc, _)
| Self::Id(Id { loc, .. })
| Self::Id(Id { loc, .. }, _)
| Self::Wildcard(loc) => loc,
}
}
Expand All @@ -239,16 +239,16 @@ pub(crate) mod pattern {
pub(crate) loc: Location,
pub(crate) tag_order: usize,
pub(crate) tag: Id,
pub(crate) data_variables: Vec<MatchingPattern<T>>,
pub(crate) data_variables: Vec<(MatchingPattern<T>, T)>,
pub(crate) type_: T,
}

#[derive(Clone, PartialEq, Eq)]
pub(crate) enum MatchingPattern<T: Clone> {
Tuple(Location, Vec<TuplePatternElement<DestructuringPattern<T>, T>>),
Object(Location, Vec<ObjectPatternElement<DestructuringPattern<T>, T>>),
Tuple(Location, Vec<TuplePatternElement<MatchingPattern<T>, T>>),
Object(Location, Vec<ObjectPatternElement<MatchingPattern<T>, T>>),
Variant(VariantPattern<T>),
Id(Id),
Id(Id, T),
Wildcard(Location),
}

Expand All @@ -258,7 +258,7 @@ pub(crate) mod pattern {
Self::Tuple(loc, _)
| Self::Object(loc, _)
| Self::Variant(VariantPattern { loc, .. })
| Self::Id(Id { loc, .. })
| Self::Id(Id { loc, .. }, _)
| Self::Wildcard(loc) => loc,
}
}
Expand Down Expand Up @@ -424,10 +424,16 @@ pub(crate) mod expr {
pub(crate) e2: Box<E<T>>,
}

#[derive(Clone, PartialEq, Eq)]
pub(crate) enum IfElseCondition<T: Clone> {
Expression(E<T>),
Guard(super::pattern::MatchingPattern<T>, E<T>),
}

#[derive(Clone, PartialEq, Eq)]
pub(crate) struct IfElse<T: Clone> {
pub(crate) common: ExpressionCommon<T>,
pub(crate) condition: Box<E<T>>,
pub(crate) condition: Box<IfElseCondition<T>>,
pub(crate) e1: Box<E<T>>,
pub(crate) e2: Box<E<T>>,
}
Expand Down
31 changes: 21 additions & 10 deletions crates/samlang-core/src/ast/source_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ mod tests {
assert_eq!(*destructuring_pattern.loc(), Location::dummy());
destructuring_pattern = pattern::DestructuringPattern::Tuple(Location::dummy(), vec![]);
assert_eq!(*destructuring_pattern.loc(), Location::dummy());
destructuring_pattern = pattern::DestructuringPattern::Id(Id::from(PStr::LOWER_A));
destructuring_pattern = pattern::DestructuringPattern::Id(Id::from(PStr::LOWER_A), ());
assert_eq!(*destructuring_pattern.loc(), Location::dummy());
destructuring_pattern = pattern::DestructuringPattern::Wildcard(Location::dummy());
assert_eq!(*destructuring_pattern.loc(), Location::dummy());
Expand All @@ -63,7 +63,7 @@ mod tests {
type_: (),
});
assert_eq!(*matching_pattern.clone().loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Id(Id::from(PStr::LOWER_A));
matching_pattern = pattern::MatchingPattern::Id(Id::from(PStr::LOWER_A), ());
assert_eq!(*matching_pattern.loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Wildcard(Location::dummy());
assert_eq!(*matching_pattern.loc(), Location::dummy());
Expand Down Expand Up @@ -205,7 +205,16 @@ mod tests {
}));
coverage_hack_for_expr(E::IfElse(IfElse {
common: common.clone(),
condition: Box::new(zero_expr.clone()),
condition: Box::new(IfElseCondition::Expression(zero_expr.clone())),
e1: Box::new(zero_expr.clone()),
e2: Box::new(zero_expr.clone()),
}));
coverage_hack_for_expr(E::IfElse(IfElse {
common: common.clone(),
condition: Box::new(IfElseCondition::Guard(
pattern::MatchingPattern::Wildcard(Location::dummy()),
zero_expr.clone(),
)),
e1: Box::new(zero_expr.clone()),
e2: Box::new(zero_expr.clone()),
}));
Expand Down Expand Up @@ -242,9 +251,10 @@ mod tests {
loc: Location::dummy(),
field_order: 0,
field_name: Id::from(heap.alloc_str_for_test("name")),
pattern: Box::new(pattern::DestructuringPattern::Id(Id::from(
heap.alloc_str_for_test("name"),
))),
pattern: Box::new(pattern::DestructuringPattern::Id(
Id::from(heap.alloc_str_for_test("name")),
(),
)),
shorthand: true,
type_: (),
}],
Expand All @@ -262,9 +272,10 @@ mod tests {
pattern: pattern::DestructuringPattern::Tuple(
Location::dummy(),
vec![pattern::TuplePatternElement {
pattern: Box::new(pattern::DestructuringPattern::Id(Id::from(
heap.alloc_str_for_test("name"),
))),
pattern: Box::new(pattern::DestructuringPattern::Id(
Id::from(heap.alloc_str_for_test("name")),
(),
)),
type_: (),
}],
),
Expand All @@ -289,7 +300,7 @@ mod tests {
expr::DeclarationStatement {
loc: Location::dummy(),
associated_comments: NO_COMMENT_REFERENCE,
pattern: pattern::DestructuringPattern::Id(Id::from(heap.alloc_str_for_test("s"))),
pattern: pattern::DestructuringPattern::Id(Id::from(heap.alloc_str_for_test("s")), ()),
annotation: Some(annotation::T::Fn(annotation::Function {
location: Location::dummy(),
associated_comments: NO_COMMENT_REFERENCE,
Expand Down
83 changes: 83 additions & 0 deletions crates/samlang-core/src/checker/checker_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2586,11 +2586,21 @@ Found 1 error.
"{ let _ = (b: bool, t: int, f: int) -> if b then t else f; }",
&builder.unit_type(),
);
assert_checks(
heap,
"{ let _ = (t: Test) -> if let {foo, bar as _} = t then 1 else 2; }",
&builder.unit_type(),
);
assert_checks(
heap,
"{ let _ = (t: Test2) -> match (t) { Foo(_) -> 1, Bar(s) -> 2 }; }",
&builder.unit_type(),
);
assert_checks(
heap,
"{ let _ = (t: Test2) -> if let Foo(_) = t then 1 else 2; }",
&builder.unit_type(),
);
assert_errors_full_customization(
heap,
"{ let _ = (t: Test2) -> match (t) { Foo(_) -> 1, Bar(s) -> 2 }; }",
Expand Down Expand Up @@ -2716,6 +2726,79 @@ Error ---------------------------------- DUMMY.sam:3:22-3:23
Found 1 error.
"#,
);
assert_errors_full_customization(
heap,
"{ let _ = (t: Test) -> if let [a, b, _] = [1, 2] then 1 else 2; }",
&builder.unit_type(),
r#"
Error ---------------------------------- DUMMY.sam:1:38-1:39
Cannot access member of `Pair<int, int>` at index 2.
1| { let _ = (t: Test) -> if let [a, b, _] = [1, 2] then 1 else 2; }
^
Found 1 error.
"#,
"Test",
true,
);
assert_errors_full_customization(
heap,
r#"{ let _ = (t: Test) -> if let {bar, boo} = t then 1 else 2;
let _ = (t: Test) -> if let [_, bar] = t then 1 else 2;
let _ = (t: Test2) -> if let Foo(_) = t then 1 else 2;
let _ = (t: Test2) -> if let Foo(_, _) = t then 1 else 2;
let _ = (t: Test2) -> if let Foo111(_) = t then 1 else 2;
}"#,
&builder.unit_type(),
r#"
Error ---------------------------------- DUMMY.sam:1:32-1:35
Cannot find member `bar` on `Test`.
1| { let _ = (t: Test) -> if let {bar, boo} = t then 1 else 2;
^^^
Error ---------------------------------- DUMMY.sam:1:37-1:40
Cannot find member `boo` on `Test`.
1| { let _ = (t: Test) -> if let {bar, boo} = t then 1 else 2;
^^^
Error ---------------------------------- DUMMY.sam:2:33-2:36
Cannot access member of `Test` at index 1.
2| let _ = (t: Test) -> if let [_, bar] = t then 1 else 2;
^^^
Error ---------------------------------- DUMMY.sam:4:37-4:38
Cannot access member of `Test2` at index 1.
4| let _ = (t: Test2) -> if let Foo(_, _) = t then 1 else 2;
^
Error ---------------------------------- DUMMY.sam:5:30-5:36
Cannot find member `Foo111` on `Test2`.
5| let _ = (t: Test2) -> if let Foo111(_) = t then 1 else 2;
^^^^^^
Found 5 errors.
"#,
"Test2",
false,
);
assert_errors(
heap,
"match (3) { Foo(_) -> 1, Bar(s) -> 2 }",
Expand Down
Loading

0 comments on commit 98053b6

Please sign in to comment.