Skip to content

Commit

Permalink
Made instantiation of modules with errors illegal
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jan 4, 2024
1 parent 6de82e7 commit e746ec5
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 97 deletions.
2 changes: 1 addition & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


use crate::{tokenizer::{TokenTypeIdx, get_token_type_name}, linker::{NamedUUID, FileUUID, Linker}, flattening::{FlattenedModule, FlattenedInterface}, arena_alloc::{UUIDMarker, UUID, FlatAlloc}, instantiation::InstantiationList, value::Value};
use crate::{tokenizer::{TokenTypeIdx, get_token_type_name}, linker::{NamedUUID, FileUUID, Linker}, flattening::FlattenedModule, arena_alloc::{UUIDMarker, UUID, FlatAlloc}, instantiation::InstantiationList, value::Value};
use core::ops::Range;
use std::{fmt::Display, ops::Deref, cell::RefCell};

Expand Down
4 changes: 2 additions & 2 deletions src/codegen_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ pub fn value_to_str(value : &Value) -> String {
}

pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule) -> String {
assert!(!instance.errors.did_error(), "Module cannot have experienced an error");
assert!(!instance.errors.did_error.get(), "Module cannot have experienced an error");
let mut program_text : String = format!("module {}(\n\tinput clk, \n", md.link_info.name);
let submodule_interface = instance.interface.as_ref().unwrap();
let flattened_borrow = md.flattened.borrow();
for (port_idx, (port, real_port)) in zip(flattened_borrow.interface.interface_wires.iter(), submodule_interface).enumerate() {
for (port_idx, real_port) in submodule_interface.iter().enumerate() {
let wire = &instance.wires[*real_port];
program_text.push_str(if port_idx < flattened_borrow.interface.outputs_start {"\tinput"} else {"\toutput /*mux_wire*/ reg"});
program_text.push_str(&typ_to_verilog_array(&wire.typ));
Expand Down
6 changes: 1 addition & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub fn join_expected_list(expected : &[TokenTypeIdx]) -> String {
#[derive(Debug,Clone)]
pub struct ErrorCollector {
errors : RefCell<Vec<CompileError>>,
did_error : Cell<bool>,
pub did_error : Cell<bool>,
pub file : FileUUID,
}

Expand Down Expand Up @@ -143,8 +143,4 @@ impl ErrorCollector {
assert!(self.file == source.file);
self.errors.borrow_mut().extend_from_slice(&source.errors.borrow());
}

pub fn did_error(&self) -> bool {
self.did_error.get()
}
}
127 changes: 77 additions & 50 deletions src/flattening.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{ops::{Deref, Range}, iter::zip, collections::VecDeque};
use std::{ops::{Deref, Range}, iter::zip};

use crate::{
ast::{Span, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, GlobalReference, TypeExpression, DeclIDMarker},
ast::{Span, Module, Expression, SpanExpression, LocalOrGlobal, Operator, AssignableExpression, SpanAssignableExpression, Statement, CodeBlock, IdentifierType, GlobalReference, TypeExpression, DeclIDMarker, SignalDeclaration},
linker::{Linker, Named, Linkable, get_builtin_uuid, FileUUID, NamedUUID},
errors::{ErrorCollector, error_info}, arena_alloc::{ListAllocator, UUID, UUIDMarker, FlatAlloc}, tokenizer::kw, typing::{Type, typecheck_unary_operator, get_binary_operator_types, typecheck, typecheck_is_array_indexer}, value::Value
};
Expand Down Expand Up @@ -104,8 +104,7 @@ pub enum Instantiation {
SubModule(SubModuleInstance),
WireDeclaration(WireDeclaration),
Wire(WireInstance),
Connection(Connection),
Error
Connection(Connection)
}

impl Instantiation {
Expand All @@ -119,6 +118,19 @@ impl Instantiation {
let Self::WireDeclaration(w) = self else {panic!("extract_wire on not a WireDeclaration! Found {self:?}")};
w
}

pub fn for_each_embedded_type<F : FnMut(&Type, Span)>(&self, f : &mut F) {
match self {
Instantiation::SubModule(_) => {}
Instantiation::Connection(_) => {}
Instantiation::WireDeclaration(decl) => {
f(&decl.typ, decl.typ_span);
}
Instantiation::Wire(w) => {
f(&w.typ, w.span);
}
}
}
}

struct FlatteningContext<'l, 'm, 'fl> {
Expand Down Expand Up @@ -155,7 +167,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
}
}
}
fn alloc_module_interface(&self, name : Box<str>, module : &Module, module_uuid : NamedUUID, typ_span : Span) -> Instantiation {
fn alloc_module_interface(&self, name : Box<str>, module : &Module, module_uuid : NamedUUID, typ_span : Span) -> FlatID {
let flattened_borrow = module.flattened.borrow();
let local_wires : Vec<FlatID> = flattened_borrow.interface.interface_wires.iter().enumerate().map(|(port_idx, port)| {
self.instantiations.alloc(Instantiation::WireDeclaration(WireDeclaration{
Expand All @@ -168,7 +180,13 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
}))
}).collect();

Instantiation::SubModule(SubModuleInstance{name, module_uuid, typ_span, outputs_start : flattened_borrow.interface.outputs_start, local_wires : local_wires.into_boxed_slice()})
self.instantiations.alloc(Instantiation::SubModule(SubModuleInstance{
name,
module_uuid,
typ_span,
outputs_start : flattened_borrow.interface.outputs_start,
local_wires : local_wires.into_boxed_slice()
}))
}
fn desugar_func_call(&self, func_and_args : &[SpanExpression], closing_bracket_pos : usize, condition : Option<FlatID>) -> Option<(&Module, &[FlatID])> {
let (name_expr, name_expr_span) = &func_and_args[0]; // Function name is always there
Expand All @@ -180,8 +198,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
let module_ref = self.module.link_info.global_references[*g];

let dependency = self.linker.try_get_module(module_ref, &self.errors)?;
let new_module_interface = self.alloc_module_interface(dependency.link_info.name.clone(), dependency, module_ref.1?, *name_expr_span);
self.instantiations.alloc(new_module_interface)
self.alloc_module_interface(dependency.link_info.name.clone(), dependency, module_ref.1?, *name_expr_span)
}
_other => {
self.errors.error_basic(*name_expr_span, "Function call name cannot be an expression");
Expand Down Expand Up @@ -227,7 +244,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
let (is_compiletime, source) = match expr {
Expression::Named(LocalOrGlobal::Local(l)) => {
let from_wire = self.decl_to_flat_map[*l].unwrap();
let WireDeclaration { typ, typ_span:_, read_only:_, identifier_type, name:_, name_token:_ } = self.instantiations[from_wire].extract_wire_declaration();
let WireDeclaration { typ: _, typ_span:_, read_only:_, identifier_type, name:_, name_token:_ } = self.instantiations[from_wire].extract_wire_declaration();
(*identifier_type == IdentifierType::Generative, WireSource::WireRead{from_wire})
}
Expression::Named(LocalOrGlobal::Global(g)) => {
Expand Down Expand Up @@ -280,7 +297,6 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Some(match expr {
AssignableExpression::Named{local_idx} => {
let root = self.decl_to_flat_map[*local_idx].unwrap();
if let Instantiation::Error = &self.instantiations[root] {return None}; // TODO, remove Error variant. Just a quick fix so it works again
let decl = self.instantiations[root].extract_wire_declaration();

if decl.read_only {
Expand Down Expand Up @@ -315,47 +331,51 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
additional_condition
}
}
fn flatten_declaration(&mut self, decl : &SignalDeclaration) -> FlatID {
assert!(decl.identifier_type != IdentifierType::Input);
assert!(decl.identifier_type != IdentifierType::Output);

let parsed_typ_expr = self.map_to_type(&decl.typ.0, &self.module.link_info.global_references);
let typ_span = decl.typ.1;

let typ = if let Some(root_ref) = parsed_typ_expr.get_root() {
match &self.linker.links.globals[root_ref] {
Named::Module(md) => {
if let Type::Named(name) = parsed_typ_expr {
return self.alloc_module_interface(decl.name.clone(), md, name, typ_span)
} else {
todo!("Implement submodule arrays");
//Instantiation::Error
}
}
Named::Constant(c) => {
self.errors.error_basic(typ_span, format!("This should be the type of a declaration, but it refers to the constant '{}'", c.get_full_name()));
Type::Error
}
Named::Type(_) => {
parsed_typ_expr
}
}
} else {
// Error report handled by linker
Type::Error
};
self.instantiations.alloc(Instantiation::WireDeclaration(WireDeclaration{
typ,
typ_span,
read_only : false,
identifier_type : decl.identifier_type,
name : decl.name.clone(),
name_token : Some(decl.name_token)
}))
}
fn flatten_code(&mut self, code : &CodeBlock, condition : Option<FlatID>) {
for (stmt, stmt_span) in &code.statements {
match stmt {
Statement::Declaration(decl_id) => {
let decl = &self.module.declarations[*decl_id];
let wire_id = self.flatten_declaration(decl);

let typ = self.map_to_type(&decl.typ.0, &self.module.link_info.global_references);
let typ_span = decl.typ.1;

let inst = if let Some(root_ref) = typ.get_root() {
match &self.linker.links.globals[root_ref] {
Named::Constant(c) => {
self.errors.error_basic(typ_span, format!("This should be the type of a declaration, but it refers to the constant '{}'", c.get_full_name()));
Instantiation::Error
}
Named::Module(md) => {
if let Type::Named(name) = typ {
self.alloc_module_interface(decl.name.clone(), md, name, typ_span)
} else {
todo!("Implement submodule arrays");
//Instantiation::Error
}
}
Named::Type(_) => {
assert!(decl.identifier_type != IdentifierType::Input);
assert!(decl.identifier_type != IdentifierType::Output);
Instantiation::WireDeclaration(WireDeclaration{
typ,
typ_span,
read_only : false,
identifier_type : decl.identifier_type,
name : decl.name.clone(),
name_token : Some(decl.name_token)
})
}
}
} else {
Instantiation::Error // Error's covered by linker
};

let wire_id = self.instantiations.alloc(inst);
self.decl_to_flat_map[*decl_id] = Some(wire_id);
}
Statement::If{condition : condition_expr, then, els} => {
Expand Down Expand Up @@ -478,9 +498,10 @@ impl FlattenedModule {
The Generating Structure of the code is not yet executed.
It is template-preserving
*/
pub fn initialize(linker : &Linker, module : &Module) -> FlattenedModule {
pub fn initialize(linker : &Linker, module : &Module, starts_with_errors : bool) -> FlattenedModule {
let instantiations = ListAllocator::new();
let errors = ErrorCollector::new(module.link_info.file);
errors.did_error.set(starts_with_errors);

let mut context = FlatteningContext{
decl_to_flat_map: module.declarations.iter().map(|_| None).collect(),
Expand Down Expand Up @@ -605,7 +626,7 @@ impl FlattenedModule {
self.errors.error_with_info(from_wire.span, "Assignments to compile-time variables must themselves be known at compile time", vec![decl_info]);
}

// Typecheck the value with where it is stored
// Typecheck the value with target type
if let Some(target_type) = write_to_type {
self.typecheck_wire_is_of_type(from_wire, &target_type, "connection", linker);
}
Expand All @@ -616,11 +637,18 @@ impl FlattenedModule {
self.typecheck_wire_is_of_type(condition_wire, &Type::Named(get_builtin_uuid("bool")), "assignment condition", linker);
}
}
Instantiation::Error => {}
}
}
}

// Post type application. Flag any remaining Type::Unknown
for (_id, inst) in &self.instantiations {
inst.for_each_embedded_type(&mut |typ, span| {
if typ.contains_error_or_unknown::<false, true>() {
self.errors.error_basic(span, format!("Unresolved Type: {}", typ.to_string(linker)))
}
});
}
}

/* Additional Warnings */
pub fn find_unused_variables(&self) {
Expand Down Expand Up @@ -672,7 +700,6 @@ impl FlattenedModule {
}
}
Instantiation::Connection(_) => {unreachable!()}
Instantiation::Error => {}
}
for from in &connection_fanin[item] {
if !is_instance_used_map[*from] {
Expand Down
2 changes: 1 addition & 1 deletion src/instantiation/latency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl LatencyComputer {
// Wire to wire Fanin
let mut fanins : FlatAlloc<Vec<FanInOut>, WireIDMarker> = wires.iter().map(|(id, wire)| {
let mut fanin = Vec::new();
wire.source.iter_sources_with_min_latency(|from, delta_latency| {
wire.source.iter_sources_with_min_latency(&mut |from, delta_latency| {
fanin.push(FanInOut{other : from, delta_latency});
});
fanin
Expand Down
31 changes: 14 additions & 17 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{rc::Rc, ops::Deref, cell::RefCell};

use num::BigInt;

use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Operator, Module, IdentifierType, Span}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWritePathElement, WireSource, WireInstance, Connection, ConnectionWritePathElementComputed, WireDeclaration, SubModuleInstance, FlattenedModule}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid}, value::{Value, compute_unary_op, compute_binary_op}};
use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Operator, IdentifierType, Span}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWritePathElement, WireSource, WireInstance, Connection, ConnectionWritePathElementComputed, FlattenedModule}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid}, value::{Value, compute_unary_op, compute_binary_op}};

pub mod latency;

Expand Down Expand Up @@ -54,7 +54,7 @@ pub enum RealWireDataSource {
}

impl RealWireDataSource {
fn iter_sources_with_min_latency<F : FnMut(WireID, i64) -> ()>(&self, mut f : F) {
fn iter_sources_with_min_latency<F : FnMut(WireID, i64)>(&self, f : &mut F) {
match self {
RealWireDataSource::ReadOnly => {}
RealWireDataSource::Multiplexer { is_state: _, sources } => {
Expand Down Expand Up @@ -163,22 +163,15 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
let Value::Integer(val) = val else {self.errors.error_basic(span, format!("Value is not an int, it is {val:?} instead")); return None};
match IntT::try_from(val) {
Ok(val) => Some(val),
Err(e) => {
Err(_) => {
self.errors.error_basic(span, format!("Generative integer does not fit in {}: {val}", std::any::type_name::<IntT>()));
None
}
}
}
fn concretize_type(&self, typ : &Type, span : Span) -> Option<ConcreteType> {
match typ {
Type::Error => {
self.errors.error_basic(span, "Type is {error}".to_owned());
None
}
Type::Unknown => {
self.errors.error_basic(span, "Type is {unknown}".to_owned());
None
}
Type::Error | Type::Unknown => unreachable!("Bad types should be caught in flattening: {}", typ.to_string(self.linker)),
Type::Named(n) => {
Some(ConcreteType::Named(*n))
}
Expand Down Expand Up @@ -368,12 +361,12 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
fn instantiate_flattened_module(&mut self) {
for (original_wire, inst) in &self.flattened.instantiations {
let instance_to_add : SubModuleOrWire = match inst {
Instantiation::SubModule(SubModuleInstance{module_uuid, name, typ_span, outputs_start, local_wires}) => {
let Some(instance) = self.linker.instantiate(*module_uuid) else {continue}; // Avoid error from submodule
let interface_real_wires = local_wires.iter().map(|port| {
Instantiation::SubModule(submodule) => {
let Some(instance) = self.linker.instantiate(submodule.module_uuid) else {continue}; // Avoid error from submodule
let interface_real_wires = submodule.local_wires.iter().map(|port| {
self.generation_state[*port].extract_wire()
}).collect();
SubModuleOrWire::SubModule(self.submodules.alloc(SubModule { original_flat: original_wire, instance, wires : interface_real_wires, name : name.clone()}))
SubModuleOrWire::SubModule(self.submodules.alloc(SubModule { original_flat: original_wire, instance, wires : interface_real_wires, name : submodule.name.clone()}))
}
Instantiation::WireDeclaration(wire_decl) => {
let Some(typ) = self.concretize_type(&wire_decl.typ, wire_decl.typ_span) else {
Expand Down Expand Up @@ -415,7 +408,6 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
self.process_connection(conn, original_wire);
continue;
}
Instantiation::Error => {continue}, // TODO Remove Instantiation::Error
};
self.generation_state[original_wire] = instance_to_add;
}
Expand Down Expand Up @@ -453,14 +445,19 @@ impl InstantiationList {
}

pub fn instantiate(&self, name : &str, flattened : &FlattenedModule, linker : &Linker) -> Option<Rc<InstantiatedModule>> {
if flattened.errors.did_error() {
if flattened.errors.did_error.get() {
return None;// Don't instantiate modules that already errored. Otherwise instantiator may crash
}

let mut cache_borrow = self.cache.borrow_mut();

// Temporary, no template arguments yet
if cache_borrow.is_empty() {
for (_id, inst) in &flattened.instantiations {
inst.for_each_embedded_type(&mut |typ,_span| {
assert!(!typ.contains_error_or_unknown::<true,true>(), "Types brought into instantiation may not contain 'bad types': {typ:?} in {inst:?}");
})
}
let mut context = InstantiationContext{
generation_state : flattened.instantiations.iter().map(|(_, _)| SubModuleOrWire::Unnasigned).collect(),
wires : FlatAlloc::new(),
Expand Down
Loading

0 comments on commit e746ec5

Please sign in to comment.