-
Notifications
You must be signed in to change notification settings - Fork 5
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
Ranged Integers #66
base: master
Are you sure you want to change the base?
Ranged Integers #66
Changes from 5 commits
88210fe
cec2fce
2ac9db2
77cc284
d1fb001
84c9684
6b671d8
940b99f
109a867
1d34f31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
use std::ops::Deref; | ||
|
||
use crate::alloc::{zip_eq, zip_eq3}; | ||
use sus_proc_macro::get_builtin_type; | ||
|
||
use crate::alloc::{zip_eq, zip_eq3, UUID}; | ||
use crate::errors::ErrorInfoObject; | ||
use crate::flattening::{DeclarationKind, ExpressionSource, WireReferenceRoot, WrittenType}; | ||
use crate::linker::LinkInfo; | ||
use crate::typing::concrete_type::ConcreteGlobalReference; | ||
use crate::typing::template::TemplateArgKind; | ||
use crate::typing::{ | ||
concrete_type::{ConcreteType, BOOL_CONCRETE_TYPE, INT_CONCRETE_TYPE}, | ||
concrete_type::{ConcreteType, BOOL_CONCRETE_TYPE}, | ||
type_inference::{ | ||
DelayedConstraint, DelayedConstraintStatus, DelayedConstraintsList, FailedUnification, | ||
}, | ||
|
@@ -52,7 +54,7 @@ impl InstantiationContext<'_, '_> { | |
))) | ||
} | ||
|
||
fn typecheck_all_wires(&self) { | ||
fn typecheck_all_wires(&self, delayed_constraints: &mut DelayedConstraintsList<Self>) { | ||
for this_wire_id in self.wires.id_range() { | ||
let this_wire = &self.wires[this_wire_id]; | ||
let span = self.md.get_instruction_span(this_wire.original_instruction); | ||
|
@@ -80,12 +82,12 @@ impl InstantiationContext<'_, '_> { | |
// TODO overloading | ||
let (input_typ, output_typ) = match op { | ||
UnaryOperator::Not => (BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), | ||
UnaryOperator::Negate => (INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), | ||
UnaryOperator::Negate => (self.new_int_type(), self.new_int_type()), | ||
UnaryOperator::And | UnaryOperator::Or | UnaryOperator::Xor => { | ||
(self.make_array_of(BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
UnaryOperator::Sum | UnaryOperator::Product => { | ||
(self.make_array_of(INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
(self.make_array_of(self.new_int_type()), self.new_int_type()) | ||
} | ||
}; | ||
|
||
|
@@ -104,6 +106,7 @@ impl InstantiationContext<'_, '_> { | |
} | ||
&RealWireDataSource::BinaryOp { op, left, right } => { | ||
// TODO overloading | ||
// Typecheck generic INT | ||
let ((in_left, in_right), out) = match op { | ||
BinaryOperator::And => { | ||
((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
|
@@ -114,39 +117,44 @@ impl InstantiationContext<'_, '_> { | |
BinaryOperator::Xor => { | ||
((BOOL_CONCRETE_TYPE, BOOL_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Add => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Subtract => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Multiply => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Divide => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Modulo => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), INT_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Equals => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::NotEquals => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::GreaterEq => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Greater => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::LesserEq => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
} | ||
BinaryOperator::Lesser => { | ||
((INT_CONCRETE_TYPE, INT_CONCRETE_TYPE), BOOL_CONCRETE_TYPE) | ||
BinaryOperator::Add | ||
| BinaryOperator::Subtract | ||
| BinaryOperator::Multiply | ||
| BinaryOperator::Divide | ||
| BinaryOperator::Modulo => { | ||
delayed_constraints.push(BinaryOpTypecheckConstraint::new( | ||
op, | ||
left, | ||
right, | ||
this_wire_id, | ||
span, | ||
)); | ||
continue; | ||
} | ||
BinaryOperator::Equals => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
BinaryOperator::NotEquals => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
BinaryOperator::GreaterEq => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
BinaryOperator::Greater => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
BinaryOperator::LesserEq => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
BinaryOperator::Lesser => ( | ||
(self.new_int_type(), self.new_int_type()), | ||
BOOL_CONCRETE_TYPE, | ||
), | ||
}; | ||
self.type_substitutor.unify_report_error( | ||
&self.wires[this_wire_id].typ, | ||
|
@@ -249,7 +257,7 @@ impl InstantiationContext<'_, '_> { | |
delayed_constraints.push(SubmoduleTypecheckConstraint { sm_id }); | ||
} | ||
|
||
self.typecheck_all_wires(); | ||
self.typecheck_all_wires(&mut delayed_constraints); | ||
|
||
delayed_constraints.resolve_delayed_constraints(self); | ||
|
||
|
@@ -500,3 +508,89 @@ impl DelayedConstraint<InstantiationContext<'_, '_>> for SubmoduleTypecheckConst | |
.error(submod_instr.get_most_relevant_span(), message); | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct BinaryOpTypecheckConstraint { | ||
op: BinaryOperator, | ||
left: UUID<WireIDMarker>, | ||
right: UUID<WireIDMarker>, | ||
out: UUID<WireIDMarker>, | ||
span: Span, | ||
} | ||
|
||
impl BinaryOpTypecheckConstraint { | ||
fn new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant |
||
op: BinaryOperator, | ||
left: UUID<WireIDMarker>, | ||
right: UUID<WireIDMarker>, | ||
out: UUID<WireIDMarker>, | ||
span: Span, | ||
) -> Self { | ||
Self { | ||
op, | ||
left, | ||
right, | ||
out, | ||
span, | ||
} | ||
} | ||
} | ||
|
||
impl DelayedConstraint<InstantiationContext<'_, '_>> for BinaryOpTypecheckConstraint { | ||
fn try_apply(&mut self, context: &mut InstantiationContext<'_, '_>) -> DelayedConstraintStatus { | ||
if context.wires[self.left].typ.contains_unknown() | ||
|| context.wires[self.right].typ.contains_unknown() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You must call |
||
{ | ||
return DelayedConstraintStatus::NoProgress; | ||
} | ||
let left_complete_type = context.wires[self.left] | ||
.typ | ||
.try_fully_substitute(&context.type_substitutor) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see you're already doing a |
||
.unwrap(); | ||
let left_size = left_complete_type.unwrap_named().template_args[UUID::from_hidden_value(0)] | ||
.unwrap_value() | ||
.unwrap_integer(); | ||
let right_complete_type = context.wires[self.right] | ||
.typ | ||
.try_fully_substitute(&context.type_substitutor) | ||
.unwrap(); | ||
#[rustfmt::skip] | ||
let right_size = right_complete_type.unwrap_named().template_args[UUID::from_hidden_value(0)] | ||
.unwrap_value() | ||
.unwrap_integer(); | ||
let out_size = match self.op { | ||
BinaryOperator::Add => left_size + right_size, | ||
BinaryOperator::Subtract => left_size.clone(), | ||
BinaryOperator::Multiply => left_size * right_size, | ||
BinaryOperator::Divide => left_size.clone(), | ||
BinaryOperator::Modulo => right_size.clone(), | ||
_ => { | ||
unreachable!("The BinaryOpTypecheckConstraint should only check arithmetic operation but got {}", self.op); | ||
} | ||
}; | ||
let mut template_args: FlatAlloc<ConcreteType, TemplateIDMarker> = FlatAlloc::new(); | ||
template_args.alloc(ConcreteType::new_int(out_size)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be combined with ConcreteType::new_int_type |
||
let expected_out = ConcreteType::Named(ConcreteGlobalReference { | ||
id: get_builtin_type!("int"), | ||
template_args, | ||
}); | ||
|
||
context.type_substitutor.unify_report_error( | ||
&context.wires[self.out].typ, | ||
&expected_out, | ||
self.span, | ||
"binary output", | ||
); | ||
|
||
DelayedConstraintStatus::Resolved | ||
} | ||
|
||
fn report_could_not_resolve_error(&self, context: &InstantiationContext<'_, '_>) { | ||
let message = format!( | ||
"Failed to Typecheck {:?} = {:?} {} {:?}", | ||
self.out, self.right, self.op, self.left | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should |
||
); | ||
|
||
context.errors.error(self.span, message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -426,3 +426,9 @@ fn perform_instantiation( | |
|
||
context.extract() | ||
} | ||
|
||
impl InstantiationContext<'_, '_> { | ||
pub fn new_int_type(&self) -> ConcreteType { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant |
||
self.type_substitutor.new_int_type() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,8 +140,12 @@ pub struct ConcreteTypeDisplay<'a, T: Index<TypeUUID, Output = StructType>> { | |
impl<T: Index<TypeUUID, Output = StructType>> Display for ConcreteTypeDisplay<'_, T> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
match self.inner { | ||
ConcreteType::Named(name) => { | ||
f.write_str(&self.linker_types[name.id].link_info.get_full_name()) | ||
ConcreteType::Named(global_ref) => { | ||
f.write_str(&self.linker_types[global_ref.id].link_info.get_full_name())?; | ||
for template_arg in global_ref.template_args.iter() { | ||
write!(f, "{}", template_arg.1.display(self.linker_types))?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should add the field names. Actually, there is a function that does this already: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where do I get the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
Ok(()) | ||
} | ||
ConcreteType::Array(arr_box) => { | ||
let (elem_typ, arr_size) = arr_box.deref(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,17 +9,15 @@ use crate::value::Value; | |
use super::template::TVec; | ||
|
||
use super::type_inference::ConcreteTypeVariableID; | ||
use super::type_inference::ConcreteTypeVariableIDMarker; | ||
use super::type_inference::HindleyMilner; | ||
use super::type_inference::TypeSubstitutor; | ||
|
||
pub const BOOL_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(ConcreteGlobalReference { | ||
id: get_builtin_type!("bool"), | ||
template_args: FlatAlloc::new(), | ||
}); | ||
|
||
pub const INT_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(ConcreteGlobalReference { | ||
id: get_builtin_type!("int"), | ||
template_args: FlatAlloc::new(), | ||
}); | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub struct ConcreteGlobalReference<ID> { | ||
pub id: ID, | ||
|
@@ -47,13 +45,30 @@ pub enum ConcreteType { | |
} | ||
|
||
impl ConcreteType { | ||
pub fn new_int(int: BigInt) -> Self { | ||
Self::Value(Value::Integer(int)) | ||
} | ||
#[track_caller] | ||
pub fn unwrap_value(&self) -> &Value { | ||
let ConcreteType::Value(v) = self else { | ||
unreachable!("unwrap_value on {self:?}") | ||
}; | ||
v | ||
} | ||
#[track_caller] | ||
pub fn unwrap_named(&self) -> &ConcreteGlobalReference<TypeUUID> { | ||
let ConcreteType::Named(v) = self else { | ||
unreachable!("unwrap_named") | ||
}; | ||
v | ||
} | ||
pub fn down_array(&self) -> &ConcreteType { | ||
let ConcreteType::Array(arr_box) = self else { | ||
unreachable!("Must be an array!") | ||
}; | ||
let (sub, _sz) = arr_box.deref(); | ||
sub | ||
} | ||
pub fn contains_unknown(&self) -> bool { | ||
match self { | ||
ConcreteType::Named(global_ref) => global_ref | ||
|
@@ -103,4 +118,16 @@ impl ConcreteType { | |
1 // todo!() // Named structs are not implemented yet | ||
} | ||
} | ||
pub fn try_fully_substitute( | ||
&self, | ||
substitutor: &TypeSubstitutor<Self, ConcreteTypeVariableIDMarker>, | ||
) -> Option<Self> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation is incorrect. |
||
if self.contains_unknown() { | ||
None | ||
} else { | ||
let mut self_clone = self.clone(); | ||
self_clone.fully_substitute(substitutor); | ||
Some(self_clone) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, it's not something that should concern us too badly, but maybe the boolean comparison ops should
unify(left, right)
. Maybe, maybe not.