diff --git a/src/codegen_fallback.rs b/src/codegen_fallback.rs index cb2fc9a..86741a2 100644 --- a/src/codegen_fallback.rs +++ b/src/codegen_fallback.rs @@ -46,7 +46,7 @@ fn typ_to_declaration(mut typ: &ConcreteType, var_name: &str) -> String { } match typ { ConcreteType::Named(id) => { - let sz = get_type_name_size(*id); + let sz = get_type_name_size(id.id); if sz == 1 { format!("{array_string} {var_name}") } else { @@ -83,7 +83,7 @@ struct CodeGenerationContext<'g, 'out, Stream: std::fmt::Write> { use_latency: bool, - needed_untils : FlatAlloc + needed_untils: FlatAlloc, } impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> { @@ -128,7 +128,11 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> result } - fn add_latency_registers(&mut self, wire_id: WireID, w: &RealWire) -> Result<(), std::fmt::Error> { + fn add_latency_registers( + &mut self, + wire_id: WireID, + w: &RealWire, + ) -> Result<(), std::fmt::Error> { if self.use_latency { // Can do 0 iterations, when w.needed_until == w.absolute_latency. Meaning it's only needed this cycle assert!(w.absolute_latency != CALCULATE_LATENCY_LATER); @@ -170,10 +174,15 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> } } - fn write_module_signature(&mut self, commented_out : bool) { + fn write_module_signature(&mut self, commented_out: bool) { let comment_text = if commented_out { "// " } else { "" }; // First output the interface of the module - write!(self.program_text, "{comment_text}module {}(\n{comment_text}\tinput clk", mangle(&self.instance.name)).unwrap(); + write!( + self.program_text, + "{comment_text}module {}(\n{comment_text}\tinput clk", + mangle(&self.instance.name) + ) + .unwrap(); for (_id, port) in self.instance.interface_ports.iter_valids() { let port_wire = &self.instance.wires[port.wire]; let input_or_output = if port.is_input { "input" } else { "output" }; @@ -183,7 +192,8 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> write!( self.program_text, ",\n{comment_text}\t{input_or_output} {wire_doc} {wire_decl}" - ).unwrap(); + ) + .unwrap(); } write!(self.program_text, "\n{comment_text});\n\n").unwrap(); @@ -196,7 +206,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> } /// Pass a `to` parameter to say to what the constant should be assigned. - fn write_constant(&mut self, to : &str, value : &Value) { + fn write_constant(&mut self, to: &str, value: &Value) { match value { Value::Bool(_) | Value::Integer(_) | Value::Unset => { let v_str = value.inline_constant_to_string(); @@ -218,7 +228,7 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> if self.can_inline(w) { continue; } - + if let Instruction::Declaration(wire_decl) = &self.md.link_info.instructions[w.original_instruction] { @@ -228,11 +238,11 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> } } let wire_or_reg = w.source.wire_or_reg(); - + let wire_name = wire_name_self_latency(w, self.use_latency); let wire_decl = typ_to_declaration(&w.typ, &wire_name); write!(self.program_text, "{wire_or_reg} {wire_decl}").unwrap(); - + match &w.source { RealWireDataSource::Select { root, path } => { let wire_name = self.wire_name(*root, w.absolute_latency); @@ -245,7 +255,8 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> " = {}{};", op.op_text(), self.wire_name(*right, w.absolute_latency) - ).unwrap(); + ) + .unwrap(); } RealWireDataSource::BinaryOp { op, left, right } => { writeln!( @@ -254,7 +265,8 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> self.wire_name(*left, w.absolute_latency), op.op_text(), self.wire_name(*right, w.absolute_latency) - ).unwrap(); + ) + .unwrap(); } RealWireDataSource::Constant { value } => { // Trivial constants (bools & ints) should have been inlined already @@ -323,17 +335,21 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> self.write_constant(&tabbed_name, &invalid_val); "=" }; - + for s in sources { let path = self.wire_ref_path_to_string(&s.to_path, w.absolute_latency); let from_name = self.wire_name(s.from.from, w.absolute_latency); self.program_text.write_char('\t').unwrap(); for cond in s.from.condition.iter() { let cond_name = self.wire_name(cond.condition_wire, w.absolute_latency); - let invert = if cond.inverse {"!"} else {""}; + let invert = if cond.inverse { "!" } else { "" }; write!(self.program_text, "if({invert}{cond_name}) ").unwrap(); } - writeln!(self.program_text, "{output_name}{path} {arrow_str} {from_name};").unwrap(); + writeln!( + self.program_text, + "{output_name}{path} {arrow_str} {from_name};" + ) + .unwrap(); } writeln!(self.program_text, "end").unwrap(); } @@ -349,35 +365,53 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> } } } - - /// TODO probably best to have some smarter system for this in the future. + + /// TODO probably best to have some smarter system for this in the future. fn write_builtins(&mut self) { match self.md.link_info.name.as_str() { "LatencyOffset" => { - let _in_port = self.md.unwrap_port(PortID::from_hidden_value(0), true, "in"); - let _out_port = self.md.unwrap_port(PortID::from_hidden_value(1), false, "out"); + let _in_port = self + .md + .unwrap_port(PortID::from_hidden_value(0), true, "in"); + let _out_port = self + .md + .unwrap_port(PortID::from_hidden_value(1), false, "out"); self.program_text.write_str("\tassign out = in;\n").unwrap(); } "CrossDomain" => { - let _in_port = self.md.unwrap_port(PortID::from_hidden_value(0), true, "in"); - let _out_port = self.md.unwrap_port(PortID::from_hidden_value(1), false, "out"); + let _in_port = self + .md + .unwrap_port(PortID::from_hidden_value(0), true, "in"); + let _out_port = self + .md + .unwrap_port(PortID::from_hidden_value(1), false, "out"); self.program_text.write_str("\tassign out = in;\n").unwrap(); } "IntToBits" => { - let _value_port = self.md.unwrap_port(PortID::from_hidden_value(0), true, "value"); - let _bits_port = self.md.unwrap_port(PortID::from_hidden_value(1), false, "bits"); + let _value_port = self + .md + .unwrap_port(PortID::from_hidden_value(0), true, "value"); + let _bits_port = self + .md + .unwrap_port(PortID::from_hidden_value(1), false, "bits"); for i in 0..32 { write!(self.program_text, "\tassign bits[{i}] = value[{i}];\n").unwrap(); } } "BitsToInt" => { - let _bits_port = self.md.unwrap_port(PortID::from_hidden_value(0), true, "bits"); - let _value_port = self.md.unwrap_port(PortID::from_hidden_value(1), false, "value"); + let _bits_port = self + .md + .unwrap_port(PortID::from_hidden_value(0), true, "bits"); + let _value_port = self + .md + .unwrap_port(PortID::from_hidden_value(1), false, "value"); for i in 0..32 { write!(self.program_text, "\tassign value[{i}] = bits[{i}];\n").unwrap(); } } - other => panic!("Unknown Builtin: \"{other}\"! Do not mark modules as __builtin__ yourself!") + other => { + panic!("Unknown Builtin: \"{other}\"! Do not mark modules as __builtin__ yourself!") + } } } @@ -389,15 +423,9 @@ impl<'g, 'out, Stream: std::fmt::Write> CodeGenerationContext<'g, 'out, Stream> impl Value { fn inline_constant_to_string(&self) -> Cow { match self { - Value::Bool(b) => { - Cow::Borrowed(if *b { "1'b1" } else { "1'b0" }) - } - Value::Integer(v) => { - Cow::Owned(format!("{v}")) - } - Value::Unset => { - Cow::Borrowed("'x") - } + Value::Bool(b) => Cow::Borrowed(if *b { "1'b1" } else { "1'b0" }), + Value::Integer(v) => Cow::Owned(format!("{v}")), + Value::Unset => Cow::Borrowed("'x"), Value::Array(_) => unreachable!("Not an inline constant!"), Value::Error => unreachable!("Error values should never have reached codegen!"), } @@ -405,14 +433,14 @@ impl Value { } impl Module { - fn unwrap_port(&self, port_id : PortID, is_input : bool, name : &str) -> &Port { + fn unwrap_port(&self, port_id: PortID, is_input: bool, name: &str) -> &Port { let result = &self.ports[port_id]; assert_eq!(result.name, name); assert_eq!(result.is_input, is_input); result - } + } } impl RealWireDataSource { @@ -439,7 +467,7 @@ pub fn gen_verilog_code(md: &Module, instance: &InstantiatedModule, use_latency: instance, program_text: &mut program_text, use_latency, - needed_untils: instance.compute_needed_untils() + needed_untils: instance.compute_needed_untils(), }; ctx.write_verilog_code(); diff --git a/src/dev_aid/lsp/hover_info.rs b/src/dev_aid/lsp/hover_info.rs index aa75635..a933bd3 100644 --- a/src/dev_aid/lsp/hover_info.rs +++ b/src/dev_aid/lsp/hover_info.rs @@ -60,7 +60,7 @@ impl<'l> HoverCollector<'l> { if wire.original_instruction != id { continue; } - let typ_str = wire.typ.to_string(&self.linker.types); + let typ_str = wire.typ.display(&self.linker.types); let name_str = &wire.name; let latency_str = if wire.absolute_latency != CALCULATE_LATENCY_LATER { format!("{}", wire.absolute_latency) @@ -126,7 +126,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec Vec { hover.sus_code( - typ.to_string(&linker.types, &link_info.template_arguments), + typ.display(&linker.types, &link_info.template_arguments).to_string(), ); } LocationInfo::TemplateInput(in_obj, link_info, _template_id, template_arg) => { @@ -207,7 +207,7 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec InstantiationContext<'fl, 'l> { fn finalize(&mut self) { for (_id, w) in &mut self.wires { if w.typ.fully_substitute(&self.type_substitutor) == false { - let typ_as_str = w.typ.to_string(&self.linker.types); + let typ_as_str = w.typ.display(&self.linker.types); let span = self.md.get_instruction_span(w.original_instruction); self.errors.error(span, format!("Could not finalize this type, some parameters were still unknown: {typ_as_str}")); @@ -122,8 +122,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let _ = found.fully_substitute(&self.type_substitutor); let _ = expected.fully_substitute(&self.type_substitutor); - let expected_name = expected.to_string(&self.linker.types); - let found_name = found.to_string(&self.linker.types); + let expected_name = expected.display(&self.linker.types).to_string(); + let found_name = found.display(&self.linker.types).to_string(); self.errors .error(span, format!("Typing Error: {context} expects a {expected_name} but was given a {found_name}")) .add_info_list(infos); diff --git a/src/instantiation/execute.rs b/src/instantiation/execute.rs index b258b6b..c857497 100644 --- a/src/instantiation/execute.rs +++ b/src/instantiation/execute.rs @@ -8,13 +8,14 @@ use std::ops::{Deref, Index, IndexMut}; use crate::linker::{get_builtin_type, IsExtern}; use crate::prelude::*; +use crate::typing::concrete_type::ConcreteGlobalReference; use crate::typing::template::{GlobalReference, HowDoWeKnowTheTemplateArg}; use num::BigInt; use crate::flattening::*; -use crate::value::{compute_binary_op, compute_unary_op, TypedValue, Value}; use crate::util::add_to_small_set; +use crate::value::{compute_binary_op, compute_unary_op, TypedValue, Value}; use crate::typing::{ abstract_type::DomainType, @@ -159,12 +160,39 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { fn concretize_type(&self, typ: &WrittenType) -> ExecutionResult { Ok(match typ { WrittenType::Error(_) => caught_by_typecheck!("Error Type"), - WrittenType::TemplateVariable(_, template_id) => self.template_args[*template_id].unwrap_type().clone(), - WrittenType::Named(named_type) => ConcreteType::Named(named_type.id), + WrittenType::TemplateVariable(_, template_id) => { + self.template_args[*template_id].unwrap_type().clone() + } + WrittenType::Named(named_type) => { + let template_args = + named_type + .template_args + .map(|template_arg| match template_arg.1 { + Some(template_arg) => match &template_arg.kind { + TemplateArgKind::Type(written_type) => ConcreteTemplateArg::Type( + self.concretize_type(&written_type).unwrap(), + HowDoWeKnowTheTemplateArg::Given, + ), + TemplateArgKind::Value(uuid) => ConcreteTemplateArg::Value( + self.generation_state[*uuid] + .unwrap_generation_value() + .clone(), + HowDoWeKnowTheTemplateArg::Given, + ), + }, + None => ConcreteTemplateArg::NotProvided, + }); + ConcreteType::Named(ConcreteGlobalReference { + id: named_type.id, + template_args, + }) + } WrittenType::Array(_, arr_box) => { let (arr_content_typ, arr_size_wire, _bracket_span) = arr_box.deref(); let inner_typ = self.concretize_type(arr_content_typ)?; - let arr_size = self.generation_state.get_generation_integer(*arr_size_wire)?; + let arr_size = self + .generation_state + .get_generation_integer(*arr_size_wire)?; ConcreteType::Array(Box::new(( inner_typ, ConcreteType::Value(Value::Integer(arr_size.clone())), @@ -193,13 +221,25 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { if linker_cst.link_info.is_extern == IsExtern::Builtin { match linker_cst.link_info.name.as_str() { - "true" => TypedValue{value: Value::Bool(true), typ: ConcreteType::Named(get_builtin_type("bool"))}, - "false" => TypedValue{value: Value::Bool(false), typ: ConcreteType::Named(get_builtin_type("bool"))}, + "true" => TypedValue { + value: Value::Bool(true), + typ: ConcreteType::Named(ConcreteGlobalReference { + id: get_builtin_type("bool"), + template_args: FlatAlloc::new(), + }), + }, + "false" => TypedValue { + value: Value::Bool(false), + typ: ConcreteType::Named(ConcreteGlobalReference { + id: get_builtin_type("bool"), + template_args: FlatAlloc::new(), + }), + }, "__crash_compiler" => { cst_ref.get_total_span().debug(); panic!("__crash_compiler Intentional ICE. This is for debugging the compiler and LSP.") } - other => unreachable!("{other} is not a known builtin constant") + other => unreachable!("{other} is not a known builtin constant"), } } else { todo!("Custom Constants"); @@ -268,7 +308,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let from = ConnectFrom { num_regs, from, - condition : self.condition_stack.clone().into_boxed_slice(), + condition: self.condition_stack.clone().into_boxed_slice(), original_connection: original_instruction, }; @@ -371,9 +411,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { &WireReferenceRoot::LocalDecl(decl_id, _span) => { self.generation_state.get_generation_value(decl_id)?.clone() } - WireReferenceRoot::NamedConstant(cst) => { - self.get_named_constant_value(cst) - } + WireReferenceRoot::NamedConstant(cst) => self.get_named_constant_value(cst), &WireReferenceRoot::SubModulePort(_) => { todo!("Don't yet support compile time functions") } @@ -474,8 +512,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { wire_found.maps_to_wire } else { let port_data = &self.linker.modules[submod_instance.module_uuid].ports[port_id]; - let submodule_instruction = - self.md.link_info.instructions[submod_instance.original_instruction].unwrap_submodule(); + let submodule_instruction = self.md.link_info.instructions + [submod_instance.original_instruction] + .unwrap_submodule(); let source = if port_data.is_input { RealWireDataSource::Multiplexer { is_state: None, @@ -490,7 +529,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { original_instruction: submod_instance.original_instruction, domain: domain.unwrap_physical(), typ: ConcreteType::Unknown(self.type_substitutor.alloc()), - name: self.unique_name_producer.get_unique_name(format!("{}_{}", submod_instance.name, port_data.name)), + name: self + .unique_name_producer + .get_unique_name(format!("{}_{}", submod_instance.name, port_data.name)), specified_latency: CALCULATE_LATENCY_LATER, absolute_latency: CALCULATE_LATENCY_LATER, }); @@ -569,7 +610,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } }; Ok(self.wires.alloc(RealWire { - name : self.unique_name_producer.get_unique_name(""), + name: self.unique_name_producer.get_unique_name(""), typ: ConcreteType::Unknown(self.type_substitutor.alloc()), original_instruction, domain, @@ -587,7 +628,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let typ = self.concretize_type(&wire_decl.typ_expr)?; Ok(if wire_decl.identifier_type == IdentifierType::Generative { - let value = if let DeclarationPortInfo::GenerativeInput(template_id) = wire_decl.is_port { + let value = if let DeclarationPortInfo::GenerativeInput(template_id) = wire_decl.is_port + { self.template_args[template_id].unwrap_value().clone() } else { typ.get_initial_typed_val() @@ -626,10 +668,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { }) } - fn instantiate_code_block( - &mut self, - block_range: FlatIDRange, - ) -> ExecutionResult<()> { + fn instantiate_code_block(&mut self, block_range: FlatIDRange) -> ExecutionResult<()> { let mut instruction_range = block_range.into_iter(); while let Some(original_instruction) = instruction_range.next() { let instr = &self.md.link_info.instructions[original_instruction]; @@ -638,7 +677,11 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Instruction::SubModule(submodule) => { let sub_module = &self.linker.modules[submodule.module_ref.id]; - let name_origin = if let Some((name, _span)) = &submodule.name {name} else {""}; + let name_origin = if let Some((name, _span)) = &submodule.name { + name + } else { + "" + }; let port_map = sub_module.ports.map(|_| None); let interface_call_sites = sub_module.interfaces.map(|_| Vec::new()); let mut template_args = @@ -649,11 +692,11 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Some(arg) => match &arg.kind { TemplateArgKind::Type(typ) => ConcreteTemplateArg::Type( self.concretize_type(typ)?, - HowDoWeKnowTheTemplateArg::Given + HowDoWeKnowTheTemplateArg::Given, ), TemplateArgKind::Value(v) => ConcreteTemplateArg::Value( self.generation_state.get_generation_value(*v)?.clone(), - HowDoWeKnowTheTemplateArg::Given + HowDoWeKnowTheTemplateArg::Given, ), }, None => ConcreteTemplateArg::NotProvided, @@ -664,7 +707,7 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { instance: OnceCell::new(), port_map, interface_call_sites, - name : self.unique_name_producer.get_unique_name(name_origin), + name: self.unique_name_producer.get_unique_name(name_origin), module_uuid: submodule.module_ref.id, template_args, })) @@ -681,7 +724,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { let wire_found = self.wire_to_real_wire(w, original_instruction, domain)?; SubModuleOrWire::Wire(wire_found) } - DomainType::DomainVariable(_) => unreachable!("Domain variables have been eliminated by type checking") + DomainType::DomainVariable(_) => { + unreachable!("Domain variables have been eliminated by type checking") + } }, Instruction::Write(conn) => { self.instantiate_connection( @@ -712,7 +757,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { for (port, arg) in std::iter::zip(fc.func_call_inputs.iter(), fc.arguments.iter()) { - let from = self.get_wire_or_constant_as_wire(*arg, domain.unwrap_physical()); + let from = + self.get_wire_or_constant_as_wire(*arg, domain.unwrap_physical()); let port_wire = self.get_submodule_port(submod_id, port, None); self.instantiate_write_to_wire( port_wire, @@ -728,7 +774,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { Instruction::IfStatement(stm) => { let then_range = FlatIDRange::new(stm.then_start, stm.then_end_else_start); let else_range = FlatIDRange::new(stm.then_end_else_start, stm.else_end); - let if_condition_wire = self.md.link_info.instructions[stm.condition].unwrap_wire(); + let if_condition_wire = + self.md.link_info.instructions[stm.condition].unwrap_wire(); match if_condition_wire.typ.domain { DomainType::Generative => { let condition_val = @@ -742,7 +789,10 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { } DomainType::Physical(_domain) => { let condition_wire = self.generation_state[stm.condition].unwrap_wire(); - self.condition_stack.push(ConditionStackElem{condition_wire, inverse : false}); + self.condition_stack.push(ConditionStackElem { + condition_wire, + inverse: false, + }); self.instantiate_code_block(then_range)?; if !else_range.is_empty() { @@ -753,7 +803,9 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> { // Get rid of the condition let _ = self.condition_stack.pop().unwrap(); } - DomainType::DomainVariable(_) => unreachable!("Domain variables have been eliminated by type checking") + DomainType::DomainVariable(_) => { + unreachable!("Domain variables have been eliminated by type checking") + } } instruction_range.skip_to(stm.else_end); continue; diff --git a/src/to_string.rs b/src/to_string.rs index 3f33184..1de25a5 100644 --- a/src/to_string.rs +++ b/src/to_string.rs @@ -1,15 +1,16 @@ use crate::prelude::*; +use crate::typing::template::HowDoWeKnowTheTemplateArg; use crate::{file_position::FileText, pretty_print_many_spans, value::Value}; -use crate::flattening::{DomainInfo, Interface, InterfaceToDomainMap, Module, StructType, WrittenType}; +use crate::flattening::{ + DomainInfo, Interface, InterfaceToDomainMap, Module, StructType, WrittenType, +}; use crate::linker::{FileData, LinkInfo}; use crate::typing::{ abstract_type::{AbstractType, DomainType}, concrete_type::ConcreteType, - template::{ - ConcreteTemplateArg, ConcreteTemplateArgs, TemplateInputs, - }, + template::{ConcreteTemplateArg, ConcreteTemplateArgs, TemplateInputs}, }; use std::{ @@ -39,61 +40,200 @@ impl TemplateNameGetter for TemplateInputs { } } +#[derive(Debug)] +struct WrittenTypeDisplay< + 'a, + TypVec: Index, + TemplateVec: TemplateNameGetter, +> { + written_type: &'a WrittenType, + linker_types: &'a TypVec, + template_names: &'a TemplateVec, +} + +impl<'a, TypVec: Index, TemplateVec: TemplateNameGetter> Display + for WrittenTypeDisplay<'a, TypVec, TemplateVec> +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.written_type { + WrittenType::Error(_) => f.write_str("{error"), + WrittenType::TemplateVariable(_, id) => { + f.write_str(self.template_names.get_template_name(*id)) + } + WrittenType::Named(named_type) => { + f.write_str(&self.linker_types[named_type.id].link_info.get_full_name()) + } + WrittenType::Array(_, sub) => { + write!( + f, + "{}[]", + sub.deref() + .0 + .display(self.linker_types, self.template_names) + ) + } + } + } +} + impl WrittenType { - pub fn to_string< + pub fn display< + 'a, TypVec: Index, TemplateVec: TemplateNameGetter, >( - &self, - linker_types: &TypVec, - template_names: &TemplateVec, - ) -> String { - match self { - WrittenType::Error(_) => "{error}".to_owned(), - WrittenType::TemplateVariable(_, id) => template_names.get_template_name(*id).to_owned(), - WrittenType::Named(named_type) => linker_types[named_type.id].link_info.get_full_name(), - WrittenType::Array(_, sub) => { - sub.deref().0.to_string(linker_types, template_names) + "[]" - } + &'a self, + linker_types: &'a TypVec, + template_names: &'a TemplateVec, + ) -> impl Display + 'a { + WrittenTypeDisplay { + written_type: self, + linker_types, + template_names, + } + } +} + +#[derive(Debug)] +struct AbstractTypeDisplay< + 'a, + TypVec: Index, + TemplateVec: TemplateNameGetter, +> { + abstract_type: &'a AbstractType, + linker_types: &'a TypVec, + template_names: &'a TemplateVec, +} + +impl<'a, TypVec: Index, TemplateVec: TemplateNameGetter> Display + for AbstractTypeDisplay<'a, TypVec, TemplateVec> +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.abstract_type { + AbstractType::Unknown(id) => write!(f, "{id:?}"), + AbstractType::Template(id) => f.write_str(self.template_names.get_template_name(*id)), + AbstractType::Named(id) => f.write_str(&self.linker_types[*id].link_info.get_full_name()), + AbstractType::Array(sub) => write!(f, "{}[]", sub.deref().display(self.linker_types, self.template_names)), } } } impl AbstractType { - pub fn to_string< + pub fn display< + 'a, TypVec: Index, TemplateVec: TemplateNameGetter, >( - &self, - linker_types: &TypVec, - template_names: &TemplateVec, - ) -> String { - match self { - AbstractType::Unknown(id) => format!("{id:?}"), - AbstractType::Template(id) => template_names.get_template_name(*id).to_owned(), - AbstractType::Named(id) => linker_types[*id].link_info.get_full_name(), - AbstractType::Array(sub) => sub.deref().to_string(linker_types, template_names) + "[]", + &'a self, + linker_types: &'a TypVec, + template_names: &'a TemplateVec, + ) -> impl Display + 'a { + AbstractTypeDisplay { + abstract_type: self, + linker_types, + template_names, } } } -impl ConcreteType { - pub fn to_string>( - &self, - linker_types: &TypVec, - ) -> String { +impl Display for HowDoWeKnowTheTemplateArg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - ConcreteType::Named(name) => linker_types[*name].link_info.get_full_name(), + HowDoWeKnowTheTemplateArg::Given => f.write_str("given"), + HowDoWeKnowTheTemplateArg::Inferred => f.write_str("inferred"), + } + } +} + +#[derive(Debug)] +struct ConcreteTypeDisplay<'a, TypVec: Index> { + concrete_type: &'a ConcreteType, + linker_types: &'a TypVec, +} + +impl<'a, TypVec: Index> Display for ConcreteTypeDisplay<'a, TypVec> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.concrete_type { + ConcreteType::Named(name) => { + f.write_str(&self.linker_types[name.id].link_info.get_full_name())?; + f.write_char('(')?; + let mut template_args_it = name.template_args.iter().peekable(); + while let Some((_, template_arg)) = template_args_it.next() { + template_arg.display(self.linker_types).fmt(f)?; + if template_args_it.peek().is_some() { + f.write_str(", ")?; + } + } + f.write_char(')') + } ConcreteType::Array(arr_box) => { let (elem_typ, arr_size) = arr_box.deref(); - format!( + write!( + f, "{}[{}]", - elem_typ.to_string(linker_types), + elem_typ.display(self.linker_types), arr_size.unwrap_value().unwrap_integer() ) } - ConcreteType::Value(v) => format!("{{concrete_type_{v}}}"), - ConcreteType::Unknown(u) => format!("{{{u:?}}}"), + ConcreteType::Value(v) => write!(f, "{{concrete_type_{v}}}"), + ConcreteType::Unknown(u) => write!(f, "{{{u:?}}}"), + } + } +} + +impl ConcreteType { + pub fn display<'a, TypVec: Index>( + &'a self, + linker_types: &'a TypVec, + ) -> impl Display + 'a { + ConcreteTypeDisplay { + concrete_type: self, + linker_types, + } + } +} + +#[derive(Debug)] +struct ConcreteTemplateArgDisplay<'a, TypVec: Index> { + concrete_template_arg: &'a ConcreteTemplateArg, + linker_types: &'a TypVec, +} + +impl<'a, TypVec: Index> Display + for ConcreteTemplateArgDisplay<'a, TypVec> +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.concrete_template_arg { + ConcreteTemplateArg::Type(concrete_type, how_do_we_know_the_template_arg) => { + write!( + f, + "{}, {}", + concrete_type.display(self.linker_types), + how_do_we_know_the_template_arg + ) + } + ConcreteTemplateArg::Value(typed_value, how_do_we_know_the_template_arg) => { + write!( + f, + "{}, {}", + typed_value.value, how_do_we_know_the_template_arg + ) + } + ConcreteTemplateArg::NotProvided => { + write!(f, "not provided") + } + } + } +} + +impl ConcreteTemplateArg { + pub fn display<'a, TypVec: Index>( + &'a self, + linker_types: &'a TypVec, + ) -> impl Display + 'a { + ConcreteTemplateArgDisplay { + concrete_template_arg: self, + linker_types, } } } @@ -224,26 +364,38 @@ impl Module { pub fn pretty_print_concrete_instance( target_link_info: &LinkInfo, given_template_args: &ConcreteTemplateArgs, - linker_types: &TypVec + linker_types: &TypVec, ) -> String -where TypVec: Index { +where + TypVec: Index, +{ assert!(given_template_args.len() == target_link_info.template_arguments.len()); let object_full_name = target_link_info.get_full_name(); if given_template_args.len() == 0 { return format!("{object_full_name} #()"); } - use std::fmt::Write; let mut result = format!("{object_full_name} #(\n"); for (id, arg) in given_template_args { let arg_in_target = &target_link_info.template_arguments[id]; write!(result, " {}: ", arg_in_target.name).unwrap(); match arg { ConcreteTemplateArg::Type(concrete_type, how_do_we_know_the_template_arg) => { - write!(result, "type {} /* {} */,\n", concrete_type.to_string(linker_types), how_do_we_know_the_template_arg.to_str()).unwrap(); + write!( + result, + "type {} /* {} */,\n", + concrete_type.display(linker_types), + how_do_we_know_the_template_arg + ) + .unwrap(); } ConcreteTemplateArg::Value(typed_value, how_do_we_know_the_template_arg) => { - write!(result, "{} /* {} */,\n", typed_value.value.to_string(), how_do_we_know_the_template_arg.to_str()).unwrap(); + write!( + result, + "{} /* {} */,\n", + typed_value.value, how_do_we_know_the_template_arg + ) + .unwrap(); } ConcreteTemplateArg::NotProvided => { write!(result, "/* Could not infer */\n").unwrap(); diff --git a/src/typing/abstract_type.rs b/src/typing/abstract_type.rs index 071923b..b890284 100644 --- a/src/typing/abstract_type.rs +++ b/src/typing/abstract_type.rs @@ -322,7 +322,7 @@ impl TypeUnifier { pub fn finalize_abstract_type(&mut self, types: &ArenaAllocator, typ: &mut AbstractType, span: Span, errors: &ErrorCollector) { use super::type_inference::HindleyMilner; if typ.fully_substitute(&self.type_substitutor) == false { - let typ_as_string = typ.to_string(types, &self.template_type_names); + let typ_as_string = typ.display(types, &self.template_type_names); errors.error(span, format!("Could not fully figure out the type of this object. {typ_as_string}")); } } diff --git a/src/typing/concrete_type.rs b/src/typing/concrete_type.rs index 8c462b8..ddb0362 100644 --- a/src/typing/concrete_type.rs +++ b/src/typing/concrete_type.rs @@ -3,21 +3,32 @@ use crate::prelude::*; use std::ops::Deref; use crate::linker::get_builtin_type; -use crate:: - value::Value -; +use crate::value::Value; +use super::template::ConcreteTemplateArgs; 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")); +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 { + pub id: ID, + pub template_args: ConcreteTemplateArgs, +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ConcreteType { - Named(TypeUUID), + Named(ConcreteGlobalReference), Value(Value), Array(Box<(ConcreteType, ConcreteType)>), - Unknown(ConcreteTypeVariableID) + Unknown(ConcreteTypeVariableID), } impl ConcreteType { diff --git a/src/typing/template.rs b/src/typing/template.rs index b8747f8..c0423fa 100644 --- a/src/typing/template.rs +++ b/src/typing/template.rs @@ -1,7 +1,6 @@ use crate::prelude::*; - -use super::{abstract_type::AbstractType, concrete_type::ConcreteType}; use crate::{flattening::WrittenType, value::TypedValue}; +use super::{abstract_type::AbstractType, concrete_type::ConcreteType}; #[derive(Debug)] pub struct GlobalReference { @@ -98,15 +97,6 @@ pub enum HowDoWeKnowTheTemplateArg { Inferred, } -impl HowDoWeKnowTheTemplateArg { - pub fn to_str(&self) -> &'static str { - match self { - HowDoWeKnowTheTemplateArg::Given => "given", - HowDoWeKnowTheTemplateArg::Inferred => "inferred", - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ConcreteTemplateArg { Type(ConcreteType, HowDoWeKnowTheTemplateArg), diff --git a/src/typing/type_inference.rs b/src/typing/type_inference.rs index 374c428..a67c46c 100644 --- a/src/typing/type_inference.rs +++ b/src/typing/type_inference.rs @@ -1,4 +1,4 @@ -//! Implements the Hindley-Milner algorithm for Type Inference. +//! Implements the Hindley-Milner algorithm for Type Inference. use std::cell::{OnceCell, RefCell}; use std::fmt::Debug; @@ -39,19 +39,21 @@ pub struct FailedUnification { pub expected: MyType, pub span: Span, pub context: String, - pub infos: Vec + pub infos: Vec, } /// Pretty big block size so for most typing needs we only need one -const BLOCK_SIZE : usize = 512; +const BLOCK_SIZE: usize = 512; -pub struct TypeSubstitutor, VariableIDMarker : UUIDMarker> { +pub struct TypeSubstitutor, VariableIDMarker: UUIDMarker> { substitution_map: BlockVec, BLOCK_SIZE>, failed_unifications: RefCell>>, - _ph: PhantomData + _ph: PhantomData, } -impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMarker> IntoIterator for &'v TypeSubstitutor { +impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMarker> IntoIterator + for &'v TypeSubstitutor +{ type Item = &'v OnceCell; type IntoIter = BlockVecIter<'v, OnceCell, BLOCK_SIZE>; @@ -61,7 +63,9 @@ impl<'v, MyType: HindleyMilner + 'v, VariableIDMarker: UUIDMar } } -impl, VariableIDMarker : UUIDMarker> Index> for TypeSubstitutor { +impl, VariableIDMarker: UUIDMarker> + Index> for TypeSubstitutor +{ type Output = OnceCell; fn index(&self, index: UUID) -> &Self::Output { @@ -78,28 +82,31 @@ impl<'s> UnifyErrorReport for &'s str { (self.to_string(), Vec::new()) } } -impl (String, Vec)> UnifyErrorReport for F { +impl (String, Vec)> UnifyErrorReport for F { fn report(self) -> (String, Vec) { self() } } - - -impl+Clone, VariableIDMarker : UUIDMarker> TypeSubstitutor { +impl + Clone, VariableIDMarker: UUIDMarker> + TypeSubstitutor +{ pub fn new() -> Self { Self { substitution_map: BlockVec::new(), failed_unifications: RefCell::new(Vec::new()), - _ph: PhantomData + _ph: PhantomData, } } - - pub fn init(variable_alloc : &UUIDAllocator) -> Self { + + pub fn init(variable_alloc: &UUIDAllocator) -> Self { Self { - substitution_map: variable_alloc.into_iter().map(|_| OnceCell::new()).collect(), + substitution_map: variable_alloc + .into_iter() + .map(|_| OnceCell::new()) + .collect(), failed_unifications: RefCell::new(Vec::new()), - _ph: PhantomData + _ph: PhantomData, } } @@ -111,19 +118,15 @@ impl+Clone, VariableIDMarker : UUIDMark #[must_use] fn unify(&self, a: &MyType, b: &MyType) -> bool { match a.get_hm_info() { - HindleyMilnerInfo::TypeFunc(tf_a) => { - match b.get_hm_info() { - HindleyMilnerInfo::TypeFunc(tf_b) => { - if tf_a != tf_b { - return false; - } - MyType::unify_all_args(a, b, &mut |arg_a, arg_b| { - self.unify(arg_a, arg_b) - }) + HindleyMilnerInfo::TypeFunc(tf_a) => match b.get_hm_info() { + HindleyMilnerInfo::TypeFunc(tf_b) => { + if tf_a != tf_b { + return false; } - HindleyMilnerInfo::TypeVar(_) => self.unify(b, a) + MyType::unify_all_args(a, b, &mut |arg_a, arg_b| self.unify(arg_a, arg_b)) } - } + HindleyMilnerInfo::TypeVar(_) => self.unify(b, a), + }, HindleyMilnerInfo::TypeVar(var) => { if let HindleyMilnerInfo::TypeVar(var2) = b.get_hm_info() { if var == var2 { @@ -141,18 +144,29 @@ impl+Clone, VariableIDMarker : UUIDMark } } pub fn unify_must_succeed(&self, a: &MyType, b: &MyType) { - assert!(self.unify(a, b), "This unification cannot fail. Usually because we're unifying with a Written Type"); + assert!( + self.unify(a, b), + "This unification cannot fail. Usually because we're unifying with a Written Type" + ); } - pub fn unify_report_error(&self, found: &MyType, expected: &MyType, span: Span, reporter: Report) { + pub fn unify_report_error( + &self, + found: &MyType, + expected: &MyType, + span: Span, + reporter: Report, + ) { if !self.unify(found, expected) { let (context, infos) = reporter.report(); - self.failed_unifications.borrow_mut().push(FailedUnification { - found: found.clone(), - expected: expected.clone(), - span, - context, - infos - }); + self.failed_unifications + .borrow_mut() + .push(FailedUnification { + found: found.clone(), + expected: expected.clone(), + span, + context, + infos, + }); } } pub fn extract_errors(&mut self) -> Vec> { @@ -164,43 +178,55 @@ impl+Clone, VariableIDMarker : UUIDMark } } -impl, VariableIDMarker: UUIDMarker> Drop for TypeSubstitutor { +impl, VariableIDMarker: UUIDMarker> Drop + for TypeSubstitutor +{ fn drop(&mut self) { - assert!(self.failed_unifications.borrow().is_empty(), "Errors were not extracted before dropping!"); + assert!( + self.failed_unifications.borrow().is_empty(), + "Errors were not extracted before dropping!" + ); } } #[derive(Debug, Clone, Copy)] -pub enum HindleyMilnerInfo { +pub enum HindleyMilnerInfo { /// Just a marker. Use [HindleyMilner::unify_all_args] TypeFunc(TypeFuncIdent), - TypeVar(UUID) + TypeVar(UUID), } -pub trait HindleyMilner : Sized { - type TypeFuncIdent<'slf> : Eq where Self : 'slf; +pub trait HindleyMilner: Sized { + type TypeFuncIdent<'slf>: Eq + where + Self: 'slf; - fn get_hm_info<'slf>(&'slf self) -> HindleyMilnerInfo, VariableIDMarker>; + fn get_hm_info<'slf>( + &'slf self, + ) -> HindleyMilnerInfo, VariableIDMarker>; /// Iterate through all arguments and unify them - /// + /// /// If any pair couldn't be unified, return false - /// + /// /// This is never called by the user, only by [TypeSubstitutor::unify] - fn unify_all_args bool>(left : &Self, right : &Self, unify : &mut F) -> bool; + fn unify_all_args bool>( + left: &Self, + right: &Self, + unify: &mut F, + ) -> bool; /// Has to be implemented separately per type - /// + /// /// Returns true when no Unknowns remain fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool; } - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AbstractTypeHMInfo { Template(TemplateID), Named(TypeUUID), - Array + Array, } impl HindleyMilner for AbstractType { @@ -209,29 +235,49 @@ impl HindleyMilner for AbstractType { fn get_hm_info(&self) -> HindleyMilnerInfo { match self { AbstractType::Unknown(var_id) => HindleyMilnerInfo::TypeVar(*var_id), - AbstractType::Template(template_id) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Template(*template_id)), - AbstractType::Named(named_id) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Named(*named_id)), + AbstractType::Template(template_id) => { + HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Template(*template_id)) + } + AbstractType::Named(named_id) => { + HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Named(*named_id)) + } AbstractType::Array(_) => HindleyMilnerInfo::TypeFunc(AbstractTypeHMInfo::Array), } } - fn unify_all_args bool>(left : &Self, right : &Self, unify : &mut F) -> bool { + fn unify_all_args bool>( + left: &Self, + right: &Self, + unify: &mut F, + ) -> bool { match (left, right) { - (AbstractType::Template(na), AbstractType::Template(nb)) => {assert!(*na == *nb); true}, // Already covered by get_hm_info - (AbstractType::Named(na), AbstractType::Named(nb)) => {assert!(*na == *nb); true}, // Already covered by get_hm_info - (AbstractType::Array(arr_typ), AbstractType::Array(arr_typ_2)) => unify(arr_typ, arr_typ_2), - (_, _) => unreachable!("All others should have been eliminated by get_hm_info check") + (AbstractType::Template(na), AbstractType::Template(nb)) => { + assert!(*na == *nb); + true + } // Already covered by get_hm_info + (AbstractType::Named(na), AbstractType::Named(nb)) => { + assert!(*na == *nb); + true + } // Already covered by get_hm_info + (AbstractType::Array(arr_typ), AbstractType::Array(arr_typ_2)) => { + unify(arr_typ, arr_typ_2) + } + (_, _) => unreachable!("All others should have been eliminated by get_hm_info check"), } } - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { AbstractType::Named(_) | AbstractType::Template(_) => true, // Template Name & Name is included in get_hm_info - AbstractType::Array(arr_typ) => { - arr_typ.fully_substitute(substitutor) - }, + AbstractType::Array(arr_typ) => arr_typ.fully_substitute(substitutor), AbstractType::Unknown(var) => { - let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() else {return false}; + let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() + else { + return false; + }; *self = replacement.clone(); self.fully_substitute(substitutor) } @@ -250,13 +296,20 @@ impl HindleyMilner for DomainType { } } - fn unify_all_args bool>(_left : &Self, _right : &Self, _unify : &mut F) -> bool { + fn unify_all_args bool>( + _left: &Self, + _right: &Self, + _unify: &mut F, + ) -> bool { // No sub-args true } /// For domains, always returns true. Or rather it should, since any leftover unconnected domains should be assigned an ID of their own by the type checker - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { DomainType::Generative | DomainType::Physical(_) => true, // Do nothing, These are done already DomainType::DomainVariable(var) => { @@ -267,50 +320,65 @@ impl HindleyMilner for DomainType { } } - #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConcreteTypeHMInfo<'slf> { Named(TypeUUID), Value(&'slf Value), - Array + 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::Named(named_id) => { + HindleyMilnerInfo::TypeFunc(ConcreteTypeHMInfo::Named(named_id.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 { + 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::Value(v_1), ConcreteType::Value(v_2)) => {assert!(*v_1 == *v_2); true} // Already covered by get_hm_info + (ConcreteType::Named(na), ConcreteType::Named(nb)) => { + assert!(*na == *nb); + true + } // Already covered by get_hm_info + (ConcreteType::Value(v_1), ConcreteType::Value(v_2)) => { + assert!(*v_1 == *v_2); + 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") + (_, _) => unreachable!("All others should have been eliminated by get_hm_info check"), } } - fn fully_substitute(&mut self, substitutor: &TypeSubstitutor) -> bool { + fn fully_substitute( + &mut self, + substitutor: &TypeSubstitutor, + ) -> bool { match self { ConcreteType::Named(_) | ConcreteType::Value(_) => true, // Don't need to do anything, this is already final ConcreteType::Array(arr_typ) => { let (arr_typ, arr_sz) = arr_typ.deref_mut(); - arr_typ.fully_substitute(substitutor) && - arr_sz.fully_substitute(substitutor) - }, + arr_typ.fully_substitute(substitutor) && arr_sz.fully_substitute(substitutor) + } ConcreteType::Unknown(var) => { - let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() else {return false}; + let Some(replacement) = substitutor.substitution_map[var.get_hidden_value()].get() + else { + return false; + }; *self = replacement.clone(); self.fully_substitute(substitutor) } diff --git a/stl/core.sus b/stl/core.sus index 8b4f970..a23e876 100644 --- a/stl/core.sus +++ b/stl/core.sus @@ -24,7 +24,7 @@ __builtin__ module BitsToInt { // The decider of truth and falsity __builtin__ struct bool {} -// An integer of variable size. Right now it's not implemented yet, so this is just a 32-bit int. +// An integer of variable size. Right now it's not implemented yet, so this is just a 32-bit int. __builtin__ struct int {} // For intentionally triggering an ICE for debugging. It is a constant that crashes the compiler when it is evaluated