Skip to content

Commit

Permalink
typeck: support units in let patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Sep 10, 2020
1 parent 7af00c0 commit 706196c
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 12 deletions.
20 changes: 13 additions & 7 deletions dora/src/error/msg.rs
Expand Up @@ -95,8 +95,9 @@ pub enum SemError {
ExpectedIdentifier(String),
ExpectedStringable(String),
ExpectedSomeIdentifier,
ExpectedTuple(String),
ExpectedTupleWithLength(String, usize, usize),
LetPatternExpectedTuple(String),
LetPatternShouldBeUnit,
LetPatternExpectedTupleWithLength(String, usize, usize),
MisplacedElse,
IoError,
ExpectedClassElement(String),
Expand Down Expand Up @@ -354,11 +355,16 @@ impl SemError {
format!("identifier expected but got {}.", tok)
}
SemError::ExpectedSomeIdentifier => "identifier expected".into(),
SemError::ExpectedTuple(ref ty) => format!("tuple expected but got type {}.", ty),
SemError::ExpectedTupleWithLength(ref ty, ty_length, pattern_length) => format!(
"tuple {} has {} elements but pattern has {}.",
ty, ty_length, pattern_length
),
SemError::LetPatternExpectedTuple(ref ty) => {
format!("tuple expected but got type {}.", ty)
}
SemError::LetPatternShouldBeUnit => format!("let pattern should be unit."),
SemError::LetPatternExpectedTupleWithLength(ref ty, ty_length, pattern_length) => {
format!(
"tuple {} has {} elements but pattern has {}.",
ty, ty_length, pattern_length
)
}
SemError::ExpectedTopLevelElement(ref token) => {
format!("expected function or class but got {}.", token)
}
Expand Down
8 changes: 8 additions & 0 deletions dora/src/ty.rs
Expand Up @@ -137,6 +137,14 @@ impl BuiltinType {
}
}

pub fn is_tuple_or_unit(&self) -> bool {
match self {
&BuiltinType::Tuple(_) => true,
&BuiltinType::Unit => true,
_ => false,
}
}

pub fn cls_id(&self, vm: &VM) -> Option<ClassId> {
match *self {
BuiltinType::Class(cls_id, _) => Some(cls_id),
Expand Down
22 changes: 19 additions & 3 deletions dora/src/typeck/expr.rs
Expand Up @@ -135,16 +135,28 @@ impl<'a, 'ast> TypeCheck<'a, 'ast> {
}

LetPattern::Tuple(ref tuple) => {
if !ty.is_tuple() {
if !ty.is_tuple_or_unit() {
let ty_name = ty.name(self.vm);
self.vm.diag.lock().report(
self.file,
tuple.pos,
SemError::ExpectedTuple(ty_name),
SemError::LetPatternExpectedTuple(ty_name),
);
return;
}

if ty.is_unit() {
// () doesn't have any subparts
if tuple.parts.len() != 0 {
self.vm.diag.lock().report(
self.file,
tuple.pos,
SemError::LetPatternShouldBeUnit,
);
}
return;
}

let tuple_id = ty.tuple_id().expect("type should be tuple");
let parts = self.vm.tuples.lock().get(tuple_id).len();

Expand All @@ -153,7 +165,11 @@ impl<'a, 'ast> TypeCheck<'a, 'ast> {
self.vm.diag.lock().report(
self.file,
tuple.pos,
SemError::ExpectedTupleWithLength(ty_name, parts, tuple.parts.len()),
SemError::LetPatternExpectedTupleWithLength(
ty_name,
parts,
tuple.parts.len(),
),
);
return;
}
Expand Down
21 changes: 19 additions & 2 deletions dora/src/typeck/tests.rs
Expand Up @@ -353,13 +353,30 @@ fn type_let() {
err(
"fun f() { let (a, b) = true; }",
pos(1, 15),
SemError::ExpectedTuple("Bool".into()),
SemError::LetPatternExpectedTuple("Bool".into()),
);

ok("fun f(value: ()) { let () = value; }");
err(
"fun f() { let () = true; }",
pos(1, 15),
SemError::LetPatternExpectedTuple("Bool".into()),
);
err(
"fun f() { let (a, b) = (); }",
pos(1, 15),
SemError::LetPatternShouldBeUnit,
);

err(
"fun f() { let (a, b) = (true,); }",
pos(1, 15),
SemError::ExpectedTupleWithLength("(Bool)".into(), 1, 2),
SemError::LetPatternExpectedTupleWithLength("(Bool)".into(), 1, 2),
);
err(
"fun f() { let () = (true,); }",
pos(1, 15),
SemError::LetPatternExpectedTupleWithLength("(Bool)".into(), 1, 0),
);

ok("fun f(value: (Int32, (Int32, Int32))) -> Int32 { let (a, (b, c)) = value; a+b+c }");
Expand Down

0 comments on commit 706196c

Please sign in to comment.