Skip to content

Commit

Permalink
[WIP] ty_check: pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Feb 1, 2024
1 parent 735dd19 commit 7362e3f
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 34 deletions.
139 changes: 107 additions & 32 deletions crates/hir-analysis/src/ty/ty_check/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
mod env;

use env::ThCheckEnv;
use hir::hir_def::{Body, Expr, ExprId, Func, LitKind, Partial, PatId, Stmt, StmtId};
use hir::{
hir_def::{Body, Expr, ExprId, Func, LitKind, Partial, Pat, PatId, Stmt, StmtId},
span::DynLazySpan,
};
use rustc_hash::FxHashMap;

use super::{
diagnostics::{FuncBodyDiagAccumulator, TyCheckDiag},
ty_def::{InvalidCause, Kind, TyId, TyVarUniverse},
ty_def::{InvalidCause, Kind, TyId, TyVar, TyVarUniverse},
ty_lower::lower_hir_ty,
unify::{UnificationError, UnificationTable},
};
Expand Down Expand Up @@ -75,15 +78,7 @@ impl<'db> TyChecker<'db> {
};

let actual = match expr_data {
Expr::Lit(lit) => match lit {
LitKind::Bool(_) => TyId::bool(self.db),
LitKind::Int(_) => self.table.new_var(TyVarUniverse::Integral, &Kind::Star),
LitKind::String(s) => {
let len_bytes = s.len_bytes(self.db.as_hir_db());
self.table
.new_var(TyVarUniverse::String(len_bytes), &Kind::Star)
}
},
Expr::Lit(lit) => self.lit_ty(lit),

Expr::Block(stmts) => {
if stmts.is_empty() {
Expand Down Expand Up @@ -115,20 +110,98 @@ impl<'db> TyChecker<'db> {
Expr::Match(..) => todo!(),
};

self.unify_ty(expr, actual, expected)
}

fn check_stmt(&mut self, stmt: StmtId, expected: TyId) -> TyId {
let Partial::Present(stmt_data) = self.env.stmt_data(stmt) else {
return TyId::invalid(self.db, InvalidCause::Other);
};

match stmt_data {
Stmt::Let(..) => todo!(),
Stmt::Assign(..) => todo!(),
Stmt::For(..) => todo!(),
Stmt::While(..) => todo!(),
Stmt::Continue => todo!(),
Stmt::Break => todo!(),
Stmt::Return(..) => todo!(),
Stmt::Expr(expr) => self.check_expr_ty(*expr, expected),
}
}

fn check_pat(&mut self, pat: PatId, expected: TyId) -> TyId {
let Partial::Present(pat_data) = pat.data(self.db.as_hir_db(), self.env.body()) else {
let actual = TyId::invalid(self.db, InvalidCause::Other);
return self.unify_ty(pat, actual, expected);
};

match pat_data {
Pat::WildCard => {
let ty_var = self.table.new_var(TyVarUniverse::General, &Kind::Star);
self.unify_ty(pat, ty_var, expected)
}

Pat::Rest => todo!(),

Pat::Lit(lit) => {
let actual = match lit {
Partial::Present(lit) => self.lit_ty(lit),
Partial::Absent => TyId::invalid(self.db, InvalidCause::Other),
};
self.unify_ty(pat, actual, expected)
}

Pat::Tuple(tup) => {
let len = tup.len();
todo!()
}

Pat::Path(path) => todo!(),

Pat::PathTuple(pat, tup) => todo!(),

Pat::Record(path, fields) => todo!(),

Pat::Or(lhs, rhs) => {
self.check_pat(*lhs, expected);
self.check_pat(*rhs, expected)
}
}
}

fn lit_ty(&mut self, lit: &LitKind) -> TyId {
match lit {
LitKind::Bool(_) => TyId::bool(self.db),
LitKind::Int(_) => self.table.new_var(TyVarUniverse::Integral, &Kind::Star),
LitKind::String(s) => {
let len_bytes = s.len_bytes(self.db.as_hir_db());
self.table
.new_var(TyVarUniverse::String(len_bytes), &Kind::Star)
}
}
}

fn unify_ty<T>(&mut self, t: T, actual: TyId, expected: TyId) -> TyId
where
T: Into<Typeable>,
{
let t = t.into();

let actual = match self.table.unify(expected, actual) {
Ok(()) => {
let actual = actual.apply_subst(self.db, &mut self.table);
self.env.type_expr(expr, actual);
actual
}

Err(UnificationError::TypeMismatch) => {
let actual = actual.apply_subst(self.db, &mut self.table);
let expected = expected.apply_subst(self.db, &mut self.table);
FuncBodyDiagAccumulator::push(
self.db,
TyCheckDiag::type_mismatch(
self.db,
expr.lazy_span(self.env.body()).into(),
t.lazy_span(self.env.body()),
expected,
actual,
)
Expand All @@ -140,32 +213,19 @@ impl<'db> TyChecker<'db> {
Err(UnificationError::OccursCheckFailed) => {
FuncBodyDiagAccumulator::push(
self.db,
TyCheckDiag::InfiniteOccurrence(expr.lazy_span(self.env.body()).into()).into(),
TyCheckDiag::InfiniteOccurrence(t.lazy_span(self.env.body())).into(),
);

TyId::invalid(self.db, InvalidCause::Other)
}
};

self.env.type_expr(expr, actual);
actual
}

fn check_stmt(&mut self, stmt: StmtId, expected: TyId) -> TyId {
let Partial::Present(stmt_data) = self.env.stmt_data(stmt) else {
return TyId::invalid(self.db, InvalidCause::Other);
};

match stmt_data {
Stmt::Let(..) => todo!(),
Stmt::Assign(..) => todo!(),
Stmt::For(..) => todo!(),
Stmt::While(..) => todo!(),
Stmt::Continue => todo!(),
Stmt::Break => todo!(),
Stmt::Return(..) => todo!(),
Stmt::Expr(expr) => self.check_expr_ty(*expr, expected),
match t {
Typeable::Expr(expr) => self.env.type_expr(expr, actual),
Typeable::Pat(pat) => self.env.type_pat(pat, actual),
}

actual
}
}

Expand Down Expand Up @@ -199,3 +259,18 @@ impl TypedBody {
}
}
}

#[derive(Clone, Copy, PartialEq, Eq, derive_more::From)]
enum Typeable {
Expr(ExprId),
Pat(PatId),
}

impl Typeable {
fn lazy_span(self, body: Body) -> DynLazySpan {
match self {
Self::Expr(expr) => expr.lazy_span(body).into(),
Self::Pat(pat) => pat.lazy_span(body).into(),
}
}
}
8 changes: 6 additions & 2 deletions crates/hir/src/hir_def/pat.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use cranelift_entity::entity_impl;

use crate::{span::pat::LazyPatSpan, HirDb};

use super::{Body, IdentId, LitKind, Partial, PathId};
use crate::{span::pat::LazyPatSpan, HirDb};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Pat {
Expand Down Expand Up @@ -53,3 +52,8 @@ pub struct RecordPatField {
pub label: Partial<IdentId>,
pub pat: PatId,
}

pub enum Bar {
X(i32),
Y(i32),
}

0 comments on commit 7362e3f

Please sign in to comment.