Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix relationship between Kind::Binding and Kind::TypedValue #662

Merged
merged 17 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions debug-fir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl<T, F: Fn(&T) -> String> FirDebug<T, F> {
let str = match kind {
Kind::Constant(_) => "Constant".blue(),
Kind::TypeReference(_) => "TypeReference".blue(),
Kind::TypedValue { .. } => "TypedValue".blue(),
Kind::NodeRef { .. } => "NodeRef".blue(),
Kind::Generic { .. } => "Generic".blue(),
Kind::RecordType { .. } => "RecordType".blue(),
Kind::UnionType { .. } => "UnionType".blue(),
Expand All @@ -107,9 +107,7 @@ impl<T, F: Fn(&T) -> String> FirDebug<T, F> {
let content = match kind {
Kind::Constant(r) => format!("0: {}", fmt_r(r)),
Kind::TypeReference(r) => format!("0: {}", fmt_r(r)),
Kind::TypedValue { value, ty } => {
format!("value: {}\n\t\tty: {}", fmt_r(value), fmt_r(ty))
}
Kind::NodeRef(to) => format!("0: {}", fmt_r(to)),
Kind::Generic { default } => format!("default: {}", fmt_opt(default)),
Kind::RecordType { generics, fields } => format!(
"generics: {}\n\t\tfields: {}",
Expand All @@ -133,7 +131,7 @@ impl<T, F: Fn(&T) -> String> FirDebug<T, F> {
fmt_opt(return_type),
fmt_opt(block)
),
Kind::Binding { to } => format!("to: {}", fmt_r(to)),
Kind::Binding { to, ty } => format!("to: {}\n\t\tty: {}", fmt_opt(to), fmt_opt(ty)),
Kind::Assignment { to, from } => {
format!("to: {}\n\t\tfrom: {}", fmt_r(to), fmt_r(from))
}
Expand Down
34 changes: 13 additions & 21 deletions fir/src/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,14 @@ impl<T: Debug> Fir<T> {
// point to an if-else expression. Basically, to anything that's an expression actually.
// Should we split the fir::Kind into fir::Kind::Stmt and fir::Kind::Expr? Or does that not make sense?
Kind::Constant(r) => check!(r => Kind::RecordType { .. }, node),
Kind::TypedValue { value, ty } => {
// FIXME: Is pointing to `Type` here valid?
check!(ty => Kind::UnionType { .. } | Kind::RecordType { .. } | Kind::TypeReference(_), node);
// `value` can link to basically anything
check!(value => Kind::Call { .. }
| Kind::Constant(_)
| Kind::Instantiation { .. }
| Kind::TypedValue { .. }
| Kind::Binding { .. }
| Kind::RecordType { .. } // for empty types // FIXME: Is that allowed?
, node);
Kind::NodeRef(_to) => {
// `to` can link to basically anything, so there is nothing to do
}
// FIXME: Is that okay?
Kind::TypeReference(to) => check!(to => Kind::RecordType { .. } | Kind::UnionType { .. } | Kind::Generic { .. } | Kind::TypeReference(_), node),
Kind::TypeReference(to) => check!(to => Kind::RecordType { .. } | Kind::UnionType { .. } | Kind::Generic { .. } | Kind::TypeReference(_), node),
Kind::Generic {
default: Some(default),
} => check!(default => Kind::TypeReference { .. }, node),
} => check!(default => Kind::TypeReference(_), node),
Kind::Function {
generics,
args,
Expand All @@ -88,7 +79,7 @@ impl<T: Debug> Fir<T> {
} => {
check!(@generics => Kind::Generic { .. }, node);
check!(@args => Kind::Binding { .. }, node);
check!(return_type => Some(Kind::TypeReference { .. } | Kind::UnionType { .. }), node);
check!(return_type => Some(Kind::TypeReference(_) | Kind::UnionType { .. }), node);
check!(block => Some(Kind::Statements(_)), node);
}
Kind::Call {
Expand All @@ -97,8 +88,8 @@ impl<T: Debug> Fir<T> {
args,
} => {
check!(to => Kind::Function { .. }, node);
check!(@generics => Kind::TypeReference { .. }, node);
check!(@args => Kind::TypedValue { .. } | Kind::Constant(_) | Kind::Call { .. }, node);
check!(@generics => Kind::TypeReference(_), node);
check!(@args => Kind::NodeRef { .. } | Kind::Constant(_) | Kind::Call { .. }, node);
}
Kind::RecordType {
generics,
Expand All @@ -112,13 +103,14 @@ impl<T: Debug> Fir<T> {
variants,
} => {
check!(@generics => Kind::Generic { .. }, node);
check!(@variants => Kind::TypeReference { .. }, node);
check!(@variants => Kind::TypeReference(_), node);
}
Kind::Binding { to: _ } => {
// FIXME: Check `to` as well
Kind::Binding { to: _, ty } => {
// `to` can point to anything, correct?
check!(ty => Some(Kind::TypeReference(_) | Kind::UnionType { .. }), node)
}
Kind::Assignment { to, from: _ } => {
check!(to => Kind::TypedValue { .. } | Kind::Binding { .. }, node);
check!(to => Kind::NodeRef { .. } | Kind::Binding { .. }, node);
// FIXME: Check `from` as well
}
Kind::Instantiation {
Expand All @@ -127,7 +119,7 @@ impl<T: Debug> Fir<T> {
fields,
} => {
check!(to => Kind::RecordType { .. }, node);
check!(@generics => Kind::TypeReference { .. }, node);
check!(@generics => Kind::TypeReference(_), node);
check!(@fields => Kind::Assignment { .. }, node);
}
Kind::TypeOffset { instance: _, .. } => {
Expand Down
26 changes: 12 additions & 14 deletions fir/src/iter/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,11 @@ pub trait Mapper<T, U: From<T>, E> {
})
}

fn map_typed_value(
&mut self,
data: T,
origin: OriginIdx,
value: RefIdx,
ty: RefIdx,
) -> Result<Node<U>, E> {
fn map_node_ref(&mut self, data: T, origin: OriginIdx, to: RefIdx) -> Result<Node<U>, E> {
Ok(Node {
data: U::from(data),
origin,
kind: Kind::TypedValue { value, ty },
kind: Kind::NodeRef(to),
})
}

Expand Down Expand Up @@ -98,11 +92,17 @@ pub trait Mapper<T, U: From<T>, E> {
})
}

fn map_binding(&mut self, data: T, origin: OriginIdx, to: RefIdx) -> Result<Node<U>, E> {
fn map_binding(
&mut self,
data: T,
origin: OriginIdx,
to: Option<RefIdx>,
ty: Option<RefIdx>,
) -> Result<Node<U>, E> {
Ok(Node {
data: U::from(data),
origin,
kind: Kind::Binding { to },
kind: Kind::Binding { to, ty },
})
}

Expand Down Expand Up @@ -231,9 +231,7 @@ pub trait Mapper<T, U: From<T>, E> {
match node.kind {
Kind::Constant(c) => self.map_constant(node.data, node.origin, c),
Kind::TypeReference(r) => self.map_type_reference(node.data, node.origin, r),
Kind::TypedValue { value, ty } => {
self.map_typed_value(node.data, node.origin, value, ty)
}
Kind::NodeRef(to) => self.map_node_ref(node.data, node.origin, to),
Kind::Generic { default } => self.map_generic(node.data, node.origin, default),
Kind::RecordType { generics, fields } => {
self.map_record_type(node.data, node.origin, generics, fields)
Expand All @@ -247,7 +245,7 @@ pub trait Mapper<T, U: From<T>, E> {
return_type,
block,
} => self.map_function(node.data, node.origin, generics, args, return_type, block),
Kind::Binding { to } => self.map_binding(node.data, node.origin, to),
Kind::Binding { to, ty } => self.map_binding(node.data, node.origin, to, ty),
Kind::Instantiation {
to,
generics,
Expand Down
26 changes: 12 additions & 14 deletions fir/src/iter/multi_mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,11 @@ pub trait MultiMapper<T, U: Default + From<T>, E> {
}])
}

fn map_typed_value(
&mut self,
_data: T,
origin: OriginIdx,
value: RefIdx,
ty: RefIdx,
) -> Result<Vec<Node<U>>, E> {
fn map_node_ref(&mut self, _data: T, origin: OriginIdx, to: RefIdx) -> Result<Vec<Node<U>>, E> {
Ok(vec![Node {
data: U::from(_data),
origin,
kind: Kind::TypedValue { value, ty },
kind: Kind::NodeRef(to),
}])
}

Expand Down Expand Up @@ -108,11 +102,17 @@ pub trait MultiMapper<T, U: Default + From<T>, E> {
}])
}

fn map_binding(&mut self, _data: T, origin: OriginIdx, to: RefIdx) -> Result<Vec<Node<U>>, E> {
fn map_binding(
&mut self,
_data: T,
origin: OriginIdx,
to: Option<RefIdx>,
ty: Option<RefIdx>,
) -> Result<Vec<Node<U>>, E> {
Ok(vec![Node {
data: U::from(_data),
origin,
kind: Kind::Binding { to },
kind: Kind::Binding { to, ty },
}])
}

Expand Down Expand Up @@ -241,9 +241,7 @@ pub trait MultiMapper<T, U: Default + From<T>, E> {
match node.kind {
Kind::Constant(c) => self.map_constant(node.data, node.origin, c),
Kind::TypeReference(r) => self.map_type_reference(node.data, node.origin, r),
Kind::TypedValue { value, ty } => {
self.map_typed_value(node.data, node.origin, value, ty)
}
Kind::NodeRef(to) => self.map_node_ref(node.data, node.origin, to),
Kind::Generic { default } => self.map_generic(node.data, node.origin, default),
Kind::RecordType { generics, fields } => {
self.map_record_type(node.data, node.origin, generics, fields)
Expand All @@ -257,7 +255,7 @@ pub trait MultiMapper<T, U: Default + From<T>, E> {
return_type,
block,
} => self.map_function(node.data, node.origin, generics, args, return_type, block),
Kind::Binding { to } => self.map_binding(node.data, node.origin, to),
Kind::Binding { to, ty } => self.map_binding(node.data, node.origin, to, ty),
Kind::Instantiation {
to,
generics,
Expand Down
17 changes: 11 additions & 6 deletions fir/src/iter/traverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ pub trait Traversal<T, E> {
Ok(())
}

fn traverse_typed_value(
fn traverse_node_reference(
&mut self,
_fir: &Fir<T>,
_node: &Node<T>,
_value: &RefIdx,
_ty: &RefIdx,
_to: &RefIdx,
) -> Fallible<E> {
Ok(())
}
Expand Down Expand Up @@ -72,7 +71,13 @@ pub trait Traversal<T, E> {
Ok(())
}

fn traverse_binding(&mut self, _fir: &Fir<T>, _node: &Node<T>, _to: &RefIdx) -> Fallible<E> {
fn traverse_binding(
&mut self,
_fir: &Fir<T>,
_node: &Node<T>,
_to: &Option<RefIdx>,
_ty: &Option<RefIdx>,
) -> Fallible<E> {
Ok(())
}

Expand Down Expand Up @@ -161,7 +166,7 @@ pub trait Traversal<T, E> {
match &node.kind {
Kind::Constant(c) => self.traverse_constant(fir, node, c),
Kind::TypeReference(r) => self.traverse_type_reference(fir, node, r),
Kind::TypedValue { value, ty } => self.traverse_typed_value(fir, node, value, ty),
Kind::NodeRef(to) => self.traverse_node_reference(fir, node, to),
Kind::Generic { default } => self.traverse_generic(fir, node, default),
Kind::RecordType { generics, fields } => {
self.traverse_record_type(fir, node, generics, fields)
Expand All @@ -176,7 +181,7 @@ pub trait Traversal<T, E> {
block,
} => self.traverse_function(fir, node, generics, args, return_type, block),
Kind::Assignment { to, from } => self.traverse_assignment(fir, node, to, from),
Kind::Binding { to } => self.traverse_binding(fir, node, to),
Kind::Binding { to, ty } => self.traverse_binding(fir, node, to, ty),
Kind::Instantiation {
to,
generics,
Expand Down
24 changes: 17 additions & 7 deletions fir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,6 @@ pub enum Kind {
// TODO: Do we want newtype patterns so that references can only point to certain types? i.e TypeRef(RefIdx)
Constant(RefIdx), // to Kind::TypeReference, // FIXME: Is TypeReference the play? Yes, but really that way?
TypeReference(RefIdx), // to Kind::{Type, Generic}
TypedValue {
value: RefIdx, // to Kind::{Call, Instantiation, TypedValue, Constant}
ty: RefIdx, // to Kind::Type
},
Generic {
default: Option<RefIdx>, // to Kind::Type
},
Expand All @@ -200,10 +196,20 @@ pub enum Kind {
return_type: Option<RefIdx>, // to Kind::Type,
block: Option<RefIdx>, // to Kind::Statements
},
/// A binding is immutable, however there can be multiple bindings. Assigning to a mutable
/// variable can be thought of a second binding.
/// A binding is an immutable declaration point, with or without a value and with or without a specified type.
/// In the following code example, both the variable declaration and function argument are bindings.
/// ```ignore
/// where b = 15;
/// ^
///
/// /* or */
///
/// foo(a: int)
/// ^^^^^^
/// ```
Binding {
to: RefIdx, // to Kind::{TypedValue, Instantiation, any expr?},
to: Option<RefIdx>, // to Kind::{TypedValue, Instantiation, any expr?},
ty: Option<RefIdx>, // to Kind::{TypeReference, UnionType}
},
Assignment {
to: RefIdx, // to Kind::TypedValue
Expand Down Expand Up @@ -234,6 +240,10 @@ pub enum Kind {
},
Statements(Vec<RefIdx>), // to any kind
Return(Option<RefIdx>), // to any kind
/// Reference to another node, possibly unresolved. This is the same as a
/// raw [`RefIdx`], but is useful if you need an actual node to manipulate and modify.
/// This means that you can handle this node as you would a regular [`RefIdx`]
NodeRef(RefIdx),
}

impl<T> Index<&RefIdx> for Fir<T> {
Expand Down
Loading
Loading