From 4db8d46a16ee6754034b1f82e0a24a2e9fcdb1c0 Mon Sep 17 00:00:00 2001 From: Lennart Van Hirtum Date: Thu, 7 Nov 2024 21:03:56 +0100 Subject: [PATCH] Preliminary work for ConcreteType Hindley-Milner --- src/codegen_fallback.rs | 2 +- src/instantiation/execute.rs | 5 ++- src/instantiation/mod.rs | 4 ++ src/to_string.rs | 2 +- src/typing/concrete_type.rs | 8 ++-- src/typing/type_inference.rs | 75 +++++++++++++++++++++++++++++++++--- src/value.rs | 2 +- test.sus_errors.txt | 42 ++++++++++---------- test.sus_output.txt | 2 +- 9 files changed, 107 insertions(+), 35 deletions(-) diff --git a/src/codegen_fallback.rs b/src/codegen_fallback.rs index ac21654..69c8e44 100644 --- a/src/codegen_fallback.rs +++ b/src/codegen_fallback.rs @@ -54,7 +54,7 @@ fn typ_to_declaration(mut typ: &ConcreteType, var_name: &str) -> String { } } ConcreteType::Array(_) => unreachable!("All arrays have been used up already"), - ConcreteType::Value(_) | ConcreteType::Unknown => unreachable!(), + ConcreteType::Value(_) | ConcreteType::Unknown(_) => unreachable!(), } } diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index fcddfd3..54a7bfa 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -193,6 +193,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } } + /// TODO make builtins that depend on parameters fn get_named_constant_value(&self, cst_ref: &GlobalReference) -> TypedValue { let linker_cst = &self.linker.constants[cst_ref.id]; @@ -489,7 +490,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { source, original_instruction: submod_instance.original_instruction, domain: domain.unwrap_physical(), - typ: ConcreteType::Unknown, + typ: ConcreteType::Unknown(self.type_substitutor.alloc()), name: self.unique_name_producer.get_unique_name(format!("{}_{}", submod_instance.name, port_data.name)), absolute_latency: CALCULATE_LATENCY_LATER, }); @@ -569,7 +570,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { }; Ok(self.wires.alloc(RealWire { name : self.unique_name_producer.get_unique_name(""), - typ: ConcreteType::Unknown, + typ: ConcreteType::Unknown(self.type_substitutor.alloc()), original_instruction, domain, source, diff --git a/src/instantiation/mod.rs b/src/instantiation/mod.rs index f29651d..57b7a61 100644 --- a/src/instantiation/mod.rs +++ b/src/instantiation/mod.rs @@ -8,6 +8,7 @@ mod unique_names; use unique_names::UniqueNames; use crate::prelude::*; +use crate::typing::type_inference::{ConcreteTypeVariableIDMarker, TypeSubstitutor}; use std::{cell::RefCell, collections::HashMap, rc::Rc}; @@ -277,6 +278,8 @@ struct InstantiationContext<'fl, 'l> { wires: FlatAlloc, submodules: FlatAlloc, + type_substitutor: TypeSubstitutor, + // Used for Execution unique_name_producer: UniqueNames, condition_stack : Vec, @@ -417,6 +420,7 @@ fn perform_instantiation( md, generation_state: md.link_info.instructions.map(|(_, _)| SubModuleOrWire::Unnasigned), }, + type_substitutor: TypeSubstitutor::new(), condition_stack: Vec::new(), wires: FlatAlloc::new(), submodules: FlatAlloc::new(), diff --git a/src/to_string.rs b/src/to_string.rs index 841f623..da8ea13 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -93,7 +93,7 @@ impl ConcreteType { ) } ConcreteType::Value(v) => format!("{{concrete_type_{v}}}"), - ConcreteType::Unknown => format!("{{concrete_type_unknown}}"), + ConcreteType::Unknown(u) => format!("{{{u:?}}}"), } } } diff --git a/src/typing/concrete_type.rs b/src/typing/concrete_type.rs index efc63ea..490b2fb 100644 --- a/src/typing/concrete_type.rs +++ b/src/typing/concrete_type.rs @@ -9,6 +9,8 @@ use crate::{ value::Value, }; +use super::type_inference::ConcreteTypeVariableID; + pub const BOOL_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(get_builtin_type("bool")); pub const INT_CONCRETE_TYPE: ConcreteType = ConcreteType::Named(get_builtin_type("int")); @@ -17,7 +19,7 @@ pub enum ConcreteType { Named(TypeUUID), Value(Value), Array(Box<(ConcreteType, ConcreteType)>), - Unknown + Unknown(ConcreteTypeVariableID) } /// Panics on Type Errors that should have been caught by [AbstractType] @@ -103,7 +105,7 @@ impl ConcreteType { && target_arr_size.type_compare(found_arr_size) } (ConcreteType::Value(lv), ConcreteType::Value(rv)) => lv == rv, - (ConcreteType::Unknown, _) | (_, ConcreteType::Unknown) => { + (ConcreteType::Unknown(_), _) | (_, ConcreteType::Unknown(_)) => { todo!("Type Unification {self:?} {found:?}") } _ => false, @@ -135,7 +137,7 @@ impl ConcreteType { linker_types: &TypVec, errors: &ErrorCollector, ) { - if *self == ConcreteType::Unknown { + if let ConcreteType::Unknown(_) = self { *self = source_type.clone(); } else { self.check_type(source_type, span, linker_types, errors); diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index fce3766..88ed15b 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -3,15 +3,17 @@ use std::cell::{OnceCell, RefCell}; use std::fmt::Debug; use std::marker::PhantomData; -use std::ops::Index; +use std::ops::{Deref, DerefMut, Index}; use crate::block_vector::{BlockVec, BlockVecIter}; use crate::prelude::*; use crate::alloc::{UUIDAllocator, UUIDMarker, UUID}; +use crate::value::Value; use super::abstract_type::AbstractType; use super::abstract_type::DomainType; +use super::concrete_type::ConcreteType; pub struct TypeVariableIDMarker; impl UUIDMarker for TypeVariableIDMarker { @@ -25,6 +27,12 @@ impl UUIDMarker for DomainVariableIDMarker { } pub type DomainVariableID = UUID; +pub struct ConcreteTypeVariableIDMarker; +impl UUIDMarker for ConcreteTypeVariableIDMarker { + const DISPLAY_NAME: &'static str = "concrete_type_variable_"; +} +pub type ConcreteTypeVariableID = UUID; + pub struct FailedUnification { pub found: MyType, pub expected: MyType, @@ -62,6 +70,14 @@ impl, VariableIDMarker : UUIDMarker> In impl+Clone, VariableIDMarker : UUIDMarker> TypeSubstitutor { + pub fn new() -> Self { + Self { + substitution_map: BlockVec::new(), + failed_unifications: RefCell::new(Vec::new()), + _ph: PhantomData + } + } + pub fn init(variable_alloc : &UUIDAllocator) -> Self { Self { substitution_map: variable_alloc.into_iter().map(|_| OnceCell::new()).collect(), @@ -143,9 +159,9 @@ pub enum HindleyMilnerInfo { } pub trait HindleyMilner : Sized { - type TypeFuncIdent : Eq; + type TypeFuncIdent<'slf> : Eq where Self : 'slf; - fn get_hm_info(&self) -> HindleyMilnerInfo; + fn get_hm_info<'slf>(&'slf self) -> HindleyMilnerInfo, VariableIDMarker>; /// Iterate through all arguments and unify them /// @@ -169,7 +185,7 @@ pub enum AbstractTypeHMInfo { } impl HindleyMilner for AbstractType { - type TypeFuncIdent = AbstractTypeHMInfo; + type TypeFuncIdent<'slf> = AbstractTypeHMInfo; fn get_hm_info(&self) -> HindleyMilnerInfo { match self { @@ -205,7 +221,7 @@ impl HindleyMilner for AbstractType { } impl HindleyMilner for DomainType { - type TypeFuncIdent = DomainID; + type TypeFuncIdent<'slf> = DomainID; fn get_hm_info(&self) -> HindleyMilnerInfo { match self { @@ -231,3 +247,52 @@ impl HindleyMilner for DomainType { } } } + + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ConcreteTypeHMInfo<'slf> { + Named(TypeUUID), + Value(&'slf Value), + Array +} + + +impl HindleyMilner for ConcreteType { + type TypeFuncIdent<'slf> = ConcreteTypeHMInfo<'slf>; + + fn get_hm_info(&self) -> HindleyMilnerInfo { + match self { + ConcreteType::Unknown(var_id) => HindleyMilnerInfo::TypeVar(*var_id), + ConcreteType::Named(named_id) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Named(*named_id)), + ConcreteType::Value(v) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Value(v)), + ConcreteType::Array(_) => HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Array), + } + } + + fn unify_all_args bool>(left : &Self, right : &Self, unify : &mut F) -> bool { + match (left, right) { + (ConcreteType::Named(na), ConcreteType::Named(nb)) => {assert!(*na == *nb); true}, // Already covered by get_hm_info + (ConcreteType::Array(arr_typ_1), ConcreteType::Array(arr_typ_2)) => { + let (arr_typ_1_arr, arr_typ_1_sz) = arr_typ_1.deref(); + let (arr_typ_2_arr, arr_typ_2_sz) = arr_typ_2.deref(); + unify(arr_typ_1_arr, arr_typ_2_arr) & unify(arr_typ_1_sz, arr_typ_2_sz) + } + (_, _) => unreachable!("All others should have been eliminated by get_hm_info check") + } + } + + fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> Result<(), ()> { + match self { + ConcreteType::Named(_) | ConcreteType::Value(_) => Ok(()), // Already included in get_hm_info + ConcreteType::Array(arr_typ) => { + let (arr_typ, arr_sz) = arr_typ.deref_mut(); + arr_typ.fully_substitute(substitutor)?; + arr_sz.fully_substitute(substitutor) + }, + ConcreteType::Unknown(var) => { + *self = substitutor.substitution_map[var.get_hidden_value()].get().ok_or(())?.clone(); + self.fully_substitute(substitutor) + } + } + } +} diff --git a/src/value.rs b/src/value.rs index 3e71a2b..f4a3703 100644 --- a/src/value.rs +++ b/src/value.rs @@ -211,7 +211,7 @@ impl ConcreteType { } Value::Array(arr.into_boxed_slice()) } - ConcreteType::Value(_) | ConcreteType::Unknown => unreachable!(), + ConcreteType::Value(_) | ConcreteType::Unknown(_) => unreachable!(), } } diff --git a/test.sus_errors.txt b/test.sus_errors.txt index a652cf4..e349de5 100644 --- a/test.sus_errors.txt +++ b/test.sus_errors.txt @@ -1,5 +1,5 @@ Warning: Unused port 'push' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 48 │ interface push : bool push'READY_SLACK, T data_in'READY_SLACK │ ──┬─ @@ -12,7 +12,7 @@ Warning: Unused port 'push' │ ╰── f declared here ────╯ Warning: Unused port 'data_in' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 48 │ interface push : bool push'READY_SLACK, T data_in'READY_SLACK │ ───┬─── @@ -25,7 +25,7 @@ Warning: Unused port 'data_in' │ ╰── f declared here ────╯ Warning: Unused port 'ready' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 50 │ output bool ready'0 │ ──┬── @@ -38,7 +38,7 @@ Warning: Unused port 'ready' │ ╰── f declared here ────╯ Warning: Unused port 'pop' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 53 │ interface pop : bool pop -> bool data_valid, T data_out │ ─┬─ @@ -51,7 +51,7 @@ Warning: Unused port 'pop' │ ╰── f declared here ────╯ Warning: Unused port 'data_valid' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 53 │ interface pop : bool pop -> bool data_valid, T data_out │ ─────┬──── @@ -64,7 +64,7 @@ Warning: Unused port 'data_valid' │ ╰── f declared here ────╯ Warning: Unused port 'data_out' - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:86:2] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:86:2] │ 53 │ interface pop : bool pop -> bool data_valid, T data_out │ ────┬─── @@ -77,49 +77,49 @@ Warning: Unused port 'data_out' │ ╰── f declared here ────╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:190:10] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:190:10] │ 190 │ int[20] arr │ ─┬─ │ ╰─── Unused Variable: This variable does not affect the output ports of this module ─────╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:192:9] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:192:9] │ 192 │ int[5] subArr = Slice #(SIZE: 20, OUT_SIZE: 5, FROM: 3, T: type int)(arr) │ ───┬── │ ╰──── Unused Variable: This variable does not affect the output ports of this module ─────╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:3:43] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:3:43] │ 3 │ __builtin__ module LatencyOffset #(T, int OFFSET) { │ ───┬── │ ╰──── Unused Variable: This variable does not affect the output ports of this module ───╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:4:33] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:4:33] │ 4 │ interface LatencyOffset : T in'0 -> T out'OFFSET │ ─┬ │ ╰── Unused Variable: This variable does not affect the output ports of this module ───╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:9:29] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:9:29] │ 9 │ interface in_domain : T in'0 │ ─┬ │ ╰── Unused Variable: This variable does not affect the output ports of this module ───╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:15:31] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:15:31] │ 15 │ interface IntToBits : int value'0 -> bool[32] bits'0 │ ──┬── │ ╰──── Unused Variable: This variable does not affect the output ports of this module ────╯ Warning: Unused Variable: This variable does not affect the output ports of this module - ╭─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:19:36] + ╭─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:19:36] │ 19 │ interface IntToBits : bool[32] bits'0 -> int value'0 │ ──┬─ @@ -628,7 +628,7 @@ Error: Could not instantiate ::FIFO because the template arguments 'T', 'DEPTH', │ ──┬─ │ ╰─── Could not instantiate ::FIFO because the template arguments 'T', 'DEPTH', 'READY_SLACK' were missing and no default was provided │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:36:2] + ├─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:36:2] │ 36 │ T, │ ┬ @@ -648,7 +648,7 @@ Error: MIN is not a valid template argument of ::int │ ─┬─ │ ╰─── MIN is not a valid template argument of ::int │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ @@ -661,7 +661,7 @@ Error: MAX is not a valid template argument of ::int │ ─┬─ │ ╰─── MAX is not a valid template argument of ::int │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ @@ -841,7 +841,7 @@ Error: beep is not a valid template argument of ::int │ ──┬─ │ ╰─── beep is not a valid template argument of ::int │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ @@ -854,7 +854,7 @@ Error: BEEP is not a valid template argument of ::int │ ──┬─ │ ╰─── BEEP is not a valid template argument of ::int │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ @@ -867,7 +867,7 @@ Error: ::int is not a named wire: local or constant, it is a Struct instead! │ ─┬─ │ ╰─── ::int is not a named wire: local or constant, it is a Struct instead! │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ @@ -887,7 +887,7 @@ Error: BITWIDTH is not a valid template argument of ::FIFO │ ────┬─── │ ╰───── BITWIDTH is not a valid template argument of ::FIFO │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/util.sus:35:8] + ├─[/home/lennart/.sus/0.2.0-devel/stl/util.sus:35:8] │ 35 │ module FIFO #( │ ──┬─ @@ -1200,7 +1200,7 @@ Error: ABC is not a valid template argument of ::int │ ─┬─ │ ╰─── ABC is not a valid template argument of ::int │ - ├─[/home/lennart/Desktop/sus-compiler/target/debug/share/sus_compiler/std/core.sus:28:20] + ├─[/home/lennart/.sus/0.2.0-devel/stl/core.sus:28:20] │ 28 │ __builtin__ struct int {} │ ─┬─ diff --git a/test.sus_output.txt b/test.sus_output.txt index e6632c8..f93f980 100644 --- a/test.sus_output.txt +++ b/test.sus_output.txt @@ -1,4 +1,4 @@ -Standard Library Directory: /home/lennart/Desktop/sus-compiler/target/debug/build/sus_compiler-75259068bf570e24/out/../../../share/sus_compiler/std +Standard Library Directory: /home/lennart/.sus/0.2.0-devel/stl TREE SITTER module! DualPortMem TREE SITTER module! UseDualPortMem TREE SITTER module! FIFO