Skip to content

Commit

Permalink
WIP: More dependency analysis for incremental type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
osa1 committed Feb 5, 2024
1 parent 28c31ab commit cf731e9
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 22 deletions.
38 changes: 38 additions & 0 deletions crates/h10/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,44 @@ pub enum Type_ {
}

impl Type_ {
pub fn vars_borrowed(&self) -> Set<&Id> {
let mut vars: Set<&Id> = Default::default();
self.vars_borrowed_(&mut vars);
vars
}

fn vars_borrowed_<'a>(&'a self, vars: &mut Set<&'a Id>) {
match self {
Type_::Tuple(tys) => {
for ty in tys {
ty.node.vars_borrowed_(vars);
}
}

Type_::List(ty) => {
ty.node.vars_borrowed_(vars);
}

Type_::Arrow(ty1, ty2) => {
ty1.node.vars_borrowed_(vars);
ty2.node.vars_borrowed_(vars);
}

Type_::App(ty1, tys) => {
ty1.node.vars_borrowed_(vars);
for ty in tys {
ty.node.vars_borrowed_(vars);
}
}

Type_::Con(_) => {}

Type_::Var(id) => {
vars.insert(id);
}
}
}

pub fn vars(&self) -> Set<Id> {
let mut vars: Set<Id> = Default::default();
self.vars_(&mut vars);
Expand Down
156 changes: 134 additions & 22 deletions crates/h10/src/decl_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ impl DeclInfo {
};

match top_decl {
ast::TopDeclKind::Value(value) => analyze_value(value, &mut info),
ast::TopDeclKind::Value(value) => {
analyze_value(value, &mut info, &mut Default::default())
}
ast::TopDeclKind::Type(ty) => analyze_ty_syn(ty, &mut info),
ast::TopDeclKind::KindSig(kind_sig) => analyze_kind_sig(kind_sig, &mut info),
ast::TopDeclKind::Data(data) => analyze_data(data, &mut info),
Expand Down Expand Up @@ -83,23 +85,39 @@ impl Uses {
}
}

fn analyze_value<'a, 'b>(value: &'a ast::ValueDecl, info: &'b mut DeclInfo) {
fn analyze_value<'a, 'b, 'c>(
value: &'a ast::ValueDecl,
info: &'b mut DeclInfo,
bound_ty_vars: &'c mut ScopeSet<&'a Id>,
) {
match &value.node {
ast::ValueDecl_::TypeSig {
vars,
foralls,
context,
ty,
} => {
let bound_ty_vars: Set<&'a Id> = foralls.iter().map(|forall| &forall.node.id).collect();
bound_ty_vars.enter();

for ast::TypeBinder_ { id, ty: _ } in foralls.iter().map(|binder| &binder.node) {
bound_ty_vars.bind(id);
}

for ast::TypeBinder_ { id: _, ty } in foralls.iter().map(|binder| &binder.node) {
if let Some(ty) = ty {
analyze_ty(ty, info, bound_ty_vars)
}
}

info.defines.values.extend(vars.iter().cloned());

for ty in context {
analyze_ty(ty, info, &bound_ty_vars);
analyze_ty(ty, info, bound_ty_vars);
}

analyze_ty(ty, info, &bound_ty_vars);
analyze_ty(ty, info, bound_ty_vars);

bound_ty_vars.exit();
}

ast::ValueDecl_::Fixity {
Expand All @@ -113,14 +131,15 @@ fn analyze_value<'a, 'b>(value: &'a ast::ValueDecl, info: &'b mut DeclInfo) {
}

ast::ValueDecl_::Value { lhs, rhs } => {
// TODO: Pass bound type vars with scoped type vars.
let mut local_bound_vars: ScopeSet<&'a Id> = Default::default();
analyze_lhs(lhs, info, &mut local_bound_vars);
analyze_rhs(rhs, info, &mut local_bound_vars);
}
}
}

fn analyze_ty(ty: &ast::Type, info: &mut DeclInfo, bound_ty_vars: &Set<&Id>) {
fn analyze_ty(ty: &ast::Type, info: &mut DeclInfo, bound_ty_vars: &ScopeSet<&Id>) {
match &ty.node {
ast::Type_::Tuple(tys) => tys
.iter()
Expand All @@ -142,17 +161,17 @@ fn analyze_ty(ty: &ast::Type, info: &mut DeclInfo, bound_ty_vars: &Set<&Id>) {
ast::Type_::Con(ty_con) => analyze_ty_con(ty_con, info, bound_ty_vars),

ast::Type_::Var(var) => {
if !bound_ty_vars.contains(var) {
if !bound_ty_vars.is_bound(var) {
info.uses.tys.insert(var.clone());
}
}
}
}

fn analyze_ty_con(ty_con: &ast::TyCon, info: &mut DeclInfo, bound_ty_vars: &Set<&Id>) {
fn analyze_ty_con(ty_con: &ast::TyCon, info: &mut DeclInfo, bound_ty_vars: &ScopeSet<&Id>) {
match &ty_con.node {
ast::TyCon_::Id(id) => {
if !bound_ty_vars.contains(id) {
if !bound_ty_vars.is_bound(id) {
info.uses.tys.insert(id.clone());
}
}
Expand Down Expand Up @@ -225,9 +244,39 @@ fn analyze_rhs<'a>(
let where_decls = rhs.node.where_decls();
collect_local_binders(where_decls, info, local_bound_vars);

todo!();
match &rhs.node {
ast::Rhs_::GuardedRhs {
rhss,
where_decls: _,
} => {
for rhs in rhss {
analyze_guarded_rhs(rhs, info, local_bound_vars);
}
}

ast::Rhs_::Rhs {
rhs,
where_decls: _,
} => analyze_exp(rhs, info, local_bound_vars),
}

// local_bound_vars.exit();
local_bound_vars.exit();
}

fn analyze_exp<'a>(
_exp: &'a ast::Exp,
_info: &mut DeclInfo,
_local_bound_vars: &mut ScopeSet<&'a Id>,
) {
todo!()
}

fn analyze_guarded_rhs<'a>(
_rhs: &'a ast::GuardedRhs,
_info: &mut DeclInfo,
_local_bound_vars: &mut ScopeSet<&'a Id>,
) {
todo!()
}

/// Bind left-hand side variables as locally bound (in [`local_bound_vars`]) and used types (in
Expand Down Expand Up @@ -273,21 +322,24 @@ fn collect_local_binders<'a>(
fn analyze_ty_syn<'a, 'b>(ty_decl: &'a ast::TypeDecl, info: &'b mut DeclInfo) {
let ast::TypeDecl_ { ty, vars, rhs } = &ty_decl.node;
info.defines.tys.insert(ty.clone());
let bound_ty_vars: Set<&'a Id> = vars.iter().collect();
let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();
for var in vars {
bound_ty_vars.bind(var);
}
analyze_ty(rhs, info, &bound_ty_vars);
}

fn analyze_kind_sig<'a, 'b>(kind_sig: &'a ast::KindSigDecl, info: &'b mut DeclInfo) {
let ast::KindSigDecl_ { ty, foralls, sig } = &kind_sig.node;
info.defines.tys.insert(ty.clone());

let mut bound_ty_vars: Set<&'a Id> = Default::default();
let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();
for ast::AstNode {
node: ast::TypeBinder_ { id, ty },
..
} in foralls
{
bound_ty_vars.insert(id);
bound_ty_vars.bind(id);

// NB. Type of a binder can refer to previous binders.
if let Some(ty) = ty {
Expand All @@ -311,21 +363,24 @@ fn analyze_data<'a, 'b>(data: &'a ast::DataDecl, info: &'b mut DeclInfo) {

info.defines.tys.insert(ty_con.clone());

let bound_ty_vars: Set<&'a Id> = ty_args.iter().collect();
let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();
for ty_arg in ty_args {
bound_ty_vars.bind(ty_arg);
}

cons.iter()
.for_each(|con| analyze_con(con, info, &bound_ty_vars));
}

fn analyze_con(con: &ast::Con, info: &mut DeclInfo, bound_ty_vars: &Set<&Id>) {
fn analyze_con(con: &ast::Con, info: &mut DeclInfo, bound_ty_vars: &ScopeSet<&Id>) {
let ast::Con_ { con, fields } = &con.node;
info.defines.values.insert(con.clone());
fields
.iter()
.for_each(|field| analyze_field(field, info, bound_ty_vars));
}

fn analyze_field(field: &ast::FieldDecl, info: &mut DeclInfo, bound_ty_vars: &Set<&Id>) {
fn analyze_field(field: &ast::FieldDecl, info: &mut DeclInfo, bound_ty_vars: &ScopeSet<&Id>) {
let ast::FieldDecl_ { vars, ty } = &field.node;
vars.iter().for_each(|field_var| {
info.defines.values.insert(field_var.clone());
Expand All @@ -345,17 +400,74 @@ fn analyze_newtype<'a, 'b>(newty: &'a ast::NewtypeDecl, info: &'b mut DeclInfo)

info.defines.tys.insert(ty_con.clone());

let bound_ty_vars: Set<&'a Id> = ty_args.iter().collect();
let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();
for ty_arg in ty_args {
bound_ty_vars.bind(ty_arg);
}

analyze_con(con, info, &bound_ty_vars);
}

fn analyze_class(_value: &ast::ClassDecl, _info: &mut DeclInfo) {
todo!()
fn analyze_class<'a, 'b>(class: &'a ast::ClassDecl, info: &'b mut DeclInfo) {
let ast::ClassDecl_ {
context,
ty_con,
ty_arg,
decls,
} = &class.node;

info.defines.tys.insert(ty_con.clone());

let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();
bound_ty_vars.bind(ty_con);
bound_ty_vars.bind(ty_arg);

// Bind type variables in context.
for ty in context {
for var in ty.node.vars_borrowed() {
bound_ty_vars.bind(var);
}
}

// Add other types in context as dependencies.
for ty in context {
analyze_ty(ty, info, &bound_ty_vars);
}

for decl in decls {
analyze_value(decl, info, &mut bound_ty_vars);
}
}

fn analyze_instance(_value: &ast::InstanceDecl, _info: &mut DeclInfo) {
todo!()
fn analyze_instance<'a, 'b>(instance: &'a ast::InstanceDecl, info: &'b mut DeclInfo) {
let ast::InstanceDecl_ {
context,
ty_con,
ty,
decls,
} = &instance.node;

let mut bound_ty_vars: ScopeSet<&'a Id> = Default::default();

// Bind type variables in context.
for ty in context {
for var in ty.node.vars_borrowed() {
bound_ty_vars.bind(var);
}
}

// Add other types in context as dependencies.
for ty in context {
analyze_ty(ty, info, &bound_ty_vars);
}

info.uses.tys.insert(ty_con.clone());

analyze_ty(ty, info, &bound_ty_vars);

for decl in decls {
analyze_value(decl, info, &mut bound_ty_vars);
}
}

fn analyze_default(_value: &ast::DefaultDecl, _info: &mut DeclInfo) {
Expand Down

0 comments on commit cf731e9

Please sign in to comment.