Skip to content

Commit

Permalink
Fixed typechecking on Type / Generative Arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jun 28, 2024
1 parent 6c9ed03 commit c28f087
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 74 deletions.
9 changes: 6 additions & 3 deletions src/abstract_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,14 @@ impl<'linker, 'errs> TypeUnifier<'linker, 'errs> {

// ===== Both =====

pub fn typecheck_and_generative<const MUST_BE_GENERATIVE : bool>(&self, found : &FullType, span : Span, expected : &AbstractType, context : &str) {
self.typecheck_abstr(&found.typ, span, &expected, context, None);
pub fn typecheck_and_generative<const MUST_BE_GENERATIVE : bool>(&self, found : &FullType, span : Span, expected : &AbstractType, context : &str, declared_here : Option<SpanFile>) {
self.typecheck_abstr(&found.typ, span, &expected, context, declared_here);

if MUST_BE_GENERATIVE && found.domain != DomainType::Generative {
self.errors.error(span, format!("A generative value is required in {context}"));
let err_ref = self.errors.error(span, format!("A generative value is required in {context}"));
if let Some(span_file) = declared_here {
err_ref.info(span_file, "Declared here");
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/dev_aid/lsp/hover_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Cow;
use lsp_types::{LanguageString, MarkedString};

use crate::{
abstract_type::DomainType, flattening::{DeclarationPortInfo, FlatID, IdentifierType, InterfaceToDomainMap, Module}, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, LinkInfo, Linker, NameElem}, parser::Documentation, template::TemplateInputKind
abstract_type::DomainType, flattening::{DeclarationPortInfo, FlatID, IdentifierType, InterfaceToDomainMap, Module}, instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER}, linker::{FileData, LinkInfo, Linker, NameElem}, parser::Documentation, template::{GenerativeTemplateInputKind, TemplateInputKind, TypeTemplateInputKind}
};

use super::tree_walk::{InModule, LocationInfo};
Expand Down Expand Up @@ -135,14 +135,14 @@ pub fn hover(info: LocationInfo, linker: &Linker, file_data: &FileData) -> Vec<M
}
LocationInfo::TemplateInput(in_obj, link_info, _template_id, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { default_value } => {
TemplateInputKind::Type(TypeTemplateInputKind { default_value }) => {
if let Some(default_typ) = default_value {
hover.monospace(format!("type param '{}' = {}", template_arg.name, default_typ.to_string(&linker.types, &link_info.template_arguments)));
} else {
hover.monospace(format!("type param '{}'", template_arg.name));
}
}
TemplateInputKind::Generative { decl_span:_, declaration_instruction } => {
TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) => {
let NameElem::Module(md_id) = in_obj else {todo!("Non-module template args")};
let md = &linker.modules[md_id];
let decl = md.instructions[*declaration_instruction].unwrap_wire_declaration();
Expand Down
4 changes: 2 additions & 2 deletions src/dev_aid/lsp/semantic_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ fn walk_name_color(file : &FileData, linker : &Linker) -> Vec<(Span, IDEIdentifi
LocationInfo::Type(_, _) => {return}
LocationInfo::TemplateInput(_id, _link_info, _, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { .. } => IDEIdentifierType::Type,
TemplateInputKind::Generative { .. } => IDEIdentifierType::Generative,
TemplateInputKind::Type(_) => IDEIdentifierType::Type,
TemplateInputKind::Generative(_) => IDEIdentifierType::Generative,
}
}
LocationInfo::Global(g) => {
Expand Down
8 changes: 4 additions & 4 deletions src/dev_aid/lsp/tree_walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::ops::Deref;

use crate::{
file_position::Span, flattening::{Declaration, DeclarationPortInfo, DomainID, FlatID, Instruction, Interface, Module, ModuleInterfaceReference, PortID, SubModuleInstance, WireInstance, WireReference, WireReferenceRoot, WireSource, WrittenType}, linker::{FileData, FileUUID, LinkInfo, Linker, ModuleUUID, NameElem}, template::{GlobalReference, TemplateArgKind, TemplateID, TemplateInput, TemplateInputKind}
file_position::Span, flattening::{Declaration, DeclarationPortInfo, DomainID, FlatID, Instruction, Interface, Module, ModuleInterfaceReference, PortID, SubModuleInstance, WireInstance, WireReference, WireReferenceRoot, WireSource, WrittenType}, linker::{FileData, FileUUID, LinkInfo, Linker, ModuleUUID, NameElem}, template::{GenerativeTemplateInputKind, GlobalReference, TemplateArgKind, TemplateID, TemplateInput, TemplateInputKind, TypeTemplateInputKind}
};

#[derive(Clone, Copy, Debug)]
Expand Down Expand Up @@ -68,8 +68,8 @@ impl<'linker> From<LocationInfo<'linker>> for RefersTo {
LocationInfo::Type(_, _) => {}
LocationInfo::TemplateInput(obj, _link_info, template_id, template_arg) => {
match &template_arg.kind {
TemplateInputKind::Type { default_value:_ } => {}
TemplateInputKind::Generative { decl_span:_, declaration_instruction } => {
TemplateInputKind::Type(TypeTemplateInputKind { default_value:_ }) => {}
TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) => {
let NameElem::Module(md_id) = obj else {unreachable!()}; // TODO, local names in types?
result.local = Some((md_id, *declaration_instruction));
}
Expand Down Expand Up @@ -249,7 +249,7 @@ impl<'linker, Visitor : FnMut(Span, LocationInfo<'linker>), Pruner : Fn(Span) ->
self.visit(md.link_info.name_span, LocationInfo::Global(NameElem::Module(md_id)));

for (template_id, template_arg) in &md.link_info.template_arguments {
if let TemplateInputKind::Type{default_value} = &template_arg.kind {
if let TemplateInputKind::Type(TypeTemplateInputKind{default_value}) = &template_arg.kind {
self.visit(template_arg.name_span, LocationInfo::TemplateInput(NameElem::Module(md_id), &md.link_info, template_id, template_arg));

if let Some(default_val) = default_value {
Expand Down
6 changes: 3 additions & 3 deletions src/flattening/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use sus_proc_macro::{field, kind, kw};


use crate::{
arena_alloc::{FlatAlloc, UUID}, errors::ErrorCollector, file_position::FileText, flattening::Module, instantiation::InstantiationList, linker::{checkpoint::CheckPoint, FileBuilder, LinkInfo, ResolvedGlobals}, parser::Cursor, template::{TemplateInput, TemplateInputs}
arena_alloc::{FlatAlloc, UUID}, errors::ErrorCollector, file_position::FileText, flattening::Module, instantiation::InstantiationList, linker::{checkpoint::CheckPoint, FileBuilder, LinkInfo, ResolvedGlobals}, parser::Cursor, template::{GenerativeTemplateInputKind, TemplateInput, TemplateInputs, TypeTemplateInputKind}
};

use super::*;
Expand All @@ -27,7 +27,7 @@ impl<'linker> ModuleInitializationContext<'linker> {
self.template_inputs.alloc(TemplateInput{
name,
name_span,
kind: TemplateInputKind::Type{default_value : None} // UNSET, gets overwritten in Flattening
kind: TemplateInputKind::Type(TypeTemplateInputKind{default_value : None}) // UNSET, gets overwritten in Flattening
});
});
});
Expand Down Expand Up @@ -175,7 +175,7 @@ impl<'linker> ModuleInitializationContext<'linker> {
self.template_inputs.alloc(TemplateInput {
name,
name_span,
kind: TemplateInputKind::Generative{decl_span, declaration_instruction : UUID::PLACEHOLDER}
kind: TemplateInputKind::Generative(GenerativeTemplateInputKind{decl_span, declaration_instruction : UUID::PLACEHOLDER})
});
} else {
self.ports.alloc(Port{
Expand Down
119 changes: 80 additions & 39 deletions src/flattening/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use std::{ops::{Deref, DerefMut}, str::FromStr};

use num::BigInt;
use sus_proc_macro::{field, kind, kw};

use crate::{
arena_alloc::{UUIDRange, UUIDRangeIter, UUID}, debug::SpanDebugger, errors::ErrorCollector, file_position::{BracketSpan, Span}, linker::{with_module_editing_context, ConstantUUIDMarker, Linker, ModuleUUID, ModuleUUIDMarker, NameElem, NameResolver, NamedConstant, NamedType, Resolver, TypeUUIDMarker, WorkingOnResolver}, parser::Cursor, template::{TemplateArg, TemplateArgKind, TemplateArgs, TemplateIDMarker, TemplateInputs}, value::Value
arena_alloc::{UUIDRange, UUIDRangeIter, UUID}, debug::SpanDebugger, errors::ErrorCollector, file_position::{BracketSpan, Span}, linker::{with_module_editing_context, ConstantUUIDMarker, Linker, ModuleUUID, ModuleUUIDMarker, NameElem, NameResolver, NamedConstant, NamedType, Resolver, TypeUUIDMarker, WorkingOnResolver}, parser::Cursor, template::{GenerativeTemplateInputKind, TemplateArg, TemplateArgKind, TemplateArgs, TemplateIDMarker, TypeTemplateInputKind}, value::Value
};

use super::name_context::LocalVariableContext;
Expand Down Expand Up @@ -194,6 +195,31 @@ impl<'l, 'errs> DerefMut for FlatteningContext<'l, 'errs> {
}

impl<'l, 'errs> FlatteningContext<'l, 'errs> {
fn flatten_template_inputs(&mut self, cursor: &mut Cursor) {
if cursor.optional_field(field!("template_declaration_arguments")) {
cursor.list(kind!("template_declaration_arguments"), |cursor| {
cursor.go_down(kind!("template_declaration_type"), |cursor| {
// Already covered in initialization
cursor.field(field!("name"));
let default_type = cursor.optional_field(field!("default_value")).then(|| {
self.flatten_type(cursor)
});

let claimed_type_id = self.template_inputs_to_visit.next().unwrap();

let selected_arg = &mut self.working_on.link_info.template_arguments[claimed_type_id];
let TemplateInputKind::Type(TypeTemplateInputKind{default_value}) = &mut selected_arg.kind else {unreachable!()};

*default_value = default_type;

let name_span = selected_arg.name_span;

self.alloc_local_name(name_span, NamedLocal::TemplateType(claimed_type_id));
});
})
}
}

fn flatten_template_args(&mut self, cursor : &mut Cursor) -> Vec<TemplateArg> {
cursor.collect_list(kind!("template_params"), |cursor| {
let (outer_kind, whole_span) = cursor.kind_span();
Expand All @@ -219,39 +245,75 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> {
})
}

fn collect_template_args(&self, name_elem : NameElem, template_argument_list : Vec<TemplateArg>) -> TemplateArgs {
let empty_template = TemplateInputs::new();

let template_info = match name_elem {
fn collect_template_args(&self, name_elem : NameElem, whole_span : Span, template_argument_list : Vec<TemplateArg>) -> TemplateArgs {
let target_link_info = match name_elem {
NameElem::Module(md_id) => {
&self.modules[md_id].link_info.template_arguments
&self.modules[md_id].link_info
},
NameElem::Constant(_cst) => &empty_template, //TODO
NameElem::Type(_ty) => &empty_template, //TODO
NameElem::Constant(_) | NameElem::Type(_) => {
if !template_argument_list.is_empty() {
self.errors.todo(whole_span, "Types and Constants should get LinkInfo");
};
return FlatAlloc::new()
}
};

let mut resulting_template_arguments : TemplateArgs = FlatAlloc::new_nones(template_info.len());
let mut resulting_template_arguments : TemplateArgs = FlatAlloc::new_nones(target_link_info.template_arguments.len());

let mut index_iter = template_info.id_range().iter();
let mut value_index_iter = target_link_info.template_arguments.iter();
let mut type_index_iter = target_link_info.template_arguments.iter();

let mut get_next_type_idx = || -> Option<TemplateID> {
while let Some((idx, arg)) = type_index_iter.next() {
if let TemplateInputKind::Type(_) = &arg.kind {
return Some(idx)
}
}
None
};
let mut get_next_value_idx = || -> Option<TemplateID> {
while let Some((idx, arg)) = value_index_iter.next() {
if let TemplateInputKind::Generative(_) = &arg.kind {
return Some(idx)
}
}
None
};

// Now that we have all arguments, we construct the map of TemplateID to TemplateArg
for given_arg in template_argument_list {
let template_idx = if let Some(name_span) = given_arg.name_specification {
let target_name = &self.name_resolver.file_text[name_span];

let Some(named_index) = template_info.find(|_, template_input| template_input.name == target_name) else {
let Some((named_index, input_on_obj)) = target_link_info.template_arguments.iter().find(|(_, template_input)| template_input.name == target_name) else {
let info = self.name_resolver.get_linking_error_location(name_elem);
let err_ref = self.errors.error(name_span, format!("No template argument of name '{target_name}' on '{}'", info.full_name));
if let Some(pos) = info.location {
err_ref.info(pos, format!("'{}' declared here", info.full_name));
}
continue;
};
named_index
match (&input_on_obj.kind, &given_arg.kind) {
(TemplateInputKind::Type(_), TemplateArgKind::Type(_)) | (TemplateInputKind::Generative(_), TemplateArgKind::Value(_)) => named_index, // OK
(TemplateInputKind::Type(_), TemplateArgKind::Value(_)) => {
self.errors.error(name_span, format!("'{target_name}' is not a value. Place it behind the template ';'"))
.info((input_on_obj.name_span, target_link_info.file), "Declared here");
continue;
}
(TemplateInputKind::Generative(_), TemplateArgKind::Type(_)) => {
self.errors.error(name_span, format!("'{target_name}' is not a type. Place it before the template ';'"))
.info((input_on_obj.name_span, target_link_info.file), "Declared here");
continue;
}
}
} else {
let Some(index) = index_iter.next() else {
let (index, kind) = match &given_arg.kind {
TemplateArgKind::Type(_) => (get_next_type_idx(), "type"),
TemplateArgKind::Value(_) => (get_next_value_idx(), "generative")
};
let Some(index) = index else {
let info = self.name_resolver.get_linking_error_location(name_elem);
let err_ref = self.errors.error(given_arg.whole_span, format!("Too many template arguments! '{}' only requires {} template arguments", info.full_name, template_info.len()));
let err_ref = self.errors.error(given_arg.whole_span, format!("Too many template arguments! '{}' only requires {} {kind} template arguments", info.full_name, target_link_info.template_arguments.len()));
if let Some(pos) = info.location {
err_ref.info(pos, format!("'{}' declared here", info.full_name));
}
Expand All @@ -264,7 +326,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> {

if let Some(existing_arg) = arg {
self.errors.error(given_arg.name_specification.unwrap_or(given_arg.whole_span), "This template variable has already been set")
.info_same_file(existing_arg.whole_span, format!("'{} has already been defined here'", template_info[template_idx].name));
.info_same_file(existing_arg.whole_span, format!("'{} has already been defined here'", target_link_info.template_arguments[template_idx].name));
} else {
*arg = Some(given_arg);
}
Expand Down Expand Up @@ -316,7 +378,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> {
// Global identifier
let [name_span] = name_path.as_slice() else {todo!("Namespaces")};
if let Some((found_global, found_global_span)) = self.name_resolver.resolve_global(*name_span) {
let template_arg_map = self.collect_template_args(found_global, template_args);
let template_arg_map = self.collect_template_args(found_global, found_global_span, template_args);

LocalOrGlobal::Global(found_global, found_global_span, template_arg_map, template_args_whole_span)
} else {
Expand Down Expand Up @@ -534,7 +596,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> {
port.declaration_instruction = decl_id;
}
DeclarationPortInfo::GenerativeInput(this_template_id) => {
let TemplateInputKind::Generative { decl_span:_, declaration_instruction } = &mut self.working_on.link_info.template_arguments[this_template_id].kind else {unreachable!()};
let TemplateInputKind::Generative(GenerativeTemplateInputKind { decl_span:_, declaration_instruction }) = &mut self.working_on.link_info.template_arguments[this_template_id].kind else {unreachable!()};

*declaration_instruction = decl_id;
}
Expand Down Expand Up @@ -1123,28 +1185,7 @@ impl<'l, 'errs> FlatteningContext<'l, 'errs> {
fn flatten_module(&mut self, cursor : &mut Cursor) {
cursor.go_down(kind!("module"), |cursor| {
let name_span = cursor.field_span(field!("name"), kind!("identifier"));
if cursor.optional_field(field!("template_declaration_arguments")) {
cursor.list(kind!("template_declaration_arguments"), |cursor| {
cursor.go_down(kind!("template_declaration_type"), |cursor| {
// Already covered in initialization
cursor.field(field!("name"));
let default_type = cursor.optional_field(field!("default_value")).then(|| {
self.flatten_type(cursor)
});

let claimed_type_id = self.template_inputs_to_visit.next().unwrap();

let selected_arg = &mut self.working_on.link_info.template_arguments[claimed_type_id];
let TemplateInputKind::Type{default_value} = &mut selected_arg.kind else {unreachable!()};

*default_value = default_type;

let name_span = selected_arg.name_span;

self.alloc_local_name(name_span, NamedLocal::TemplateType(claimed_type_id));
});
})
}
self.flatten_template_inputs(cursor);
let module_name = &self.name_resolver.file_text[name_span];
println!("TREE SITTER module! {module_name}");
// Interface is allocated in self
Expand Down
Loading

0 comments on commit c28f087

Please sign in to comment.