From 3752b41d21f50b4641ca1edace9ffd9b7ccb3b53 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Tue, 8 Oct 2024 22:00:59 -0500 Subject: [PATCH 01/14] Started sketching out new type resolution process that will work with module system --- src/resolve/expr/struct_literal.rs | 4 +- src/resolve/mod.rs | 73 ++++++++++++++++++++++++++++- src/resolved/mod.rs | 9 +++- src/resolved/new_type_resolution.rs | 50 ++++++++++++++++++++ 4 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 src/resolved/new_type_resolution.rs diff --git a/src/resolve/expr/struct_literal.rs b/src/resolve/expr/struct_literal.rs index 1b444a9..dd31555 100644 --- a/src/resolve/expr/struct_literal.rs +++ b/src/resolve/expr/struct_literal.rs @@ -14,7 +14,7 @@ use indexmap::IndexMap; use itertools::Itertools; fn get_field_info<'a>( - ctx: &'a ResolveExprCtx<'_, '_>, + ctx: &'a ResolveExprCtx, structure_ref: StructureRef, field_name: &str, ) -> (usize, &'a resolved::Field) { @@ -30,7 +30,7 @@ fn get_field_info<'a>( } pub fn resolve_struct_literal_expr( - ctx: &mut ResolveExprCtx<'_, '_>, + ctx: &mut ResolveExprCtx, ast_type: &ast::Type, fields: &[FieldInitializer], fill_behavior: FillBehavior, diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 035fe3f..8092f87 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -23,7 +23,7 @@ use crate::{ cli::BuildOptions, index_map_ext::IndexMapExt, name::ResolvedName, - resolved::{self, Enum, TypedExpr, VariableStorage}, + resolved::{self, new_type_resolution, Enum, TypedExpr, VariableStorage}, source_files::Source, tag::Tag, workspace::fs::FsNodeId, @@ -103,6 +103,77 @@ pub fn resolve<'a>( let source_files = ast_workspace.source_files; let mut resolved_ast = resolved::Ast::new(source_files, &ast_workspace.fs); + // Pre-resolve types for new type resolution system + #[allow(unreachable_code, unused_variables)] + for (physical_file_id, file) in ast_workspace.files.iter() { + let file_id = ast_workspace + .get_owning_module(*physical_file_id) + .unwrap_or(*physical_file_id); + + let decls = resolved_ast.types_per_module.entry(file_id).or_default(); + + for structure in file.structures.iter() { + let privacy = structure.privacy; + let source = structure.source; + let resolved_name = ResolvedName::new(file_id, &structure.name); + + let structure_ref = resolved_ast.structures.insert(resolved::Structure { + name: resolved_name.clone(), + fields: IndexMap::new(), + is_packed: structure.is_packed, + source: structure.source, + }); + + let struct_type_kind = new_type_resolution::TypeKind::Structure( + new_type_resolution::HumanName(structure.name.to_string()), + structure_ref, + ); + + let Some(name) = structure.name.as_plain_str() else { + eprintln!( + "warning: internal namespaced structures ignored by new type resolution system" + ); + continue; + }; + + decls.insert( + name.to_string(), + new_type_resolution::TypeDecl { + kind: struct_type_kind.clone(), + source, + privacy, + }, + ); + } + + for (name, definition) in file.enums.iter() { + eprintln!("warning: enums not implemented for new type resolution system yet"); + continue; + + let representation_type_ref = todo!(); + + let kind = new_type_resolution::TypeKind::Enum( + new_type_resolution::HumanName(name.to_string()), + representation_type_ref, + ); + let source = definition.source; + let privacy = todo!("can't use enums with new type resolution system yet, since enums don't have privacy yet"); // definition.privacy; + + decls.insert( + name.to_string(), + new_type_resolution::TypeDecl { + kind, + source, + privacy, + }, + ); + } + + for (name, definition) in file.type_aliases.iter() { + eprintln!("warning: type aliases not implemented for new type resolution system yet"); + } + } + // Unify type aliases into single map for (real_file_id, file) in ast_workspace.files.iter() { let file_id = ast_workspace diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index d67aff3..75d1c25 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -1,5 +1,6 @@ mod variable_storage; +pub mod new_type_resolution; pub use self::variable_storage::VariableStorageKey; pub use crate::ast::{ CInteger, EnumMember, FloatSize, IntegerBits, IntegerKnown, IntegerSign, @@ -12,7 +13,7 @@ use crate::{ source_files::{Source, SourceFiles}, tag::Tag, target::Target, - workspace::fs::Fs, + workspace::fs::{Fs, FsNodeId}, }; use derive_more::{IsVariant, Unwrap}; use indexmap::IndexMap; @@ -20,6 +21,7 @@ use num_bigint::BigInt; use num_traits::Zero; use slotmap::{new_key_type, SlotMap}; use std::{ + collections::HashMap, ffi::CString, fmt::{Debug, Display}, }; @@ -40,6 +42,9 @@ pub struct Ast<'a> { pub globals: SlotMap, pub enums: IndexMap, pub fs: &'a Fs, + // New Experimental Type Resolution System + pub all_types: SlotMap, + pub types_per_module: HashMap>, } impl<'a> Ast<'a> { @@ -52,6 +57,8 @@ impl<'a> Ast<'a> { globals: SlotMap::with_key(), enums: IndexMap::new(), fs, + all_types: SlotMap::with_key(), + types_per_module: HashMap::new(), } } } diff --git a/src/resolved/new_type_resolution.rs b/src/resolved/new_type_resolution.rs new file mode 100644 index 0000000..3df8be7 --- /dev/null +++ b/src/resolved/new_type_resolution.rs @@ -0,0 +1,50 @@ +use super::{ + AnonymousEnum, CInteger, FixedArray, FloatSize, FunctionPointer, IntegerBits, IntegerSign, + Privacy, StructureRef, +}; +use crate::source_files::Source; +use derive_more::{IsVariant, Unwrap}; +use num::BigInt; +use slotmap::new_key_type; + +new_key_type! { + pub struct TypeRef; + pub struct EnumRef; +} + +#[derive(Clone, Debug)] +pub struct Type { + pub value: TypeRef, + pub source: Source, +} + +#[derive(Clone, Debug)] +pub struct TypeDecl { + pub kind: TypeKind, + pub source: Source, + pub privacy: Privacy, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct HumanName(pub String); + +#[derive(Clone, Debug, PartialEq, IsVariant, Unwrap)] +pub enum TypeKind { + Unresolved, + Boolean, + Integer(IntegerBits, IntegerSign), + CInteger(CInteger, Option), + IntegerLiteral(BigInt), + FloatLiteral(f64), + Floating(FloatSize), + Pointer(Box), + Void, + AnonymousStruct(), + AnonymousUnion(), + AnonymousEnum(AnonymousEnum), + FixedArray(Box), + FunctionPointer(FunctionPointer), + Enum(HumanName, TypeRef), + Structure(HumanName, StructureRef), + TypeAlias(HumanName, TypeRef), +} From a6a909eea2527fc80cb3859c012c38160240c572 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Tue, 8 Oct 2024 22:39:53 -0500 Subject: [PATCH 02/14] Added ability to declare enums as public --- src/ast/enumeration.rs | 3 ++- src/interpreter_env/mod.rs | 1 + src/parser/parse_enum.rs | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ast/enumeration.rs b/src/ast/enumeration.rs index 5f81c48..f384b0e 100644 --- a/src/ast/enumeration.rs +++ b/src/ast/enumeration.rs @@ -1,4 +1,4 @@ -use super::Type; +use super::{Privacy, Type}; use crate::source_files::Source; use indexmap::IndexMap; use num::BigInt; @@ -8,6 +8,7 @@ pub struct Enum { pub backing_type: Option, pub source: Source, pub members: IndexMap, + pub privacy: Privacy, } #[derive(Clone, Debug, PartialEq)] diff --git a/src/interpreter_env/mod.rs b/src/interpreter_env/mod.rs index 56eec2e..dfc25c1 100644 --- a/src/interpreter_env/mod.rs +++ b/src/interpreter_env/mod.rs @@ -127,6 +127,7 @@ pub fn setup_build_system_interpreter_symbols(file: &mut AstFile) { }, ), ]), + privacy: Privacy::Private, }, ); diff --git a/src/parser/parse_enum.rs b/src/parser/parse_enum.rs index 48bb07b..a558e45 100644 --- a/src/parser/parse_enum.rs +++ b/src/parser/parse_enum.rs @@ -1,6 +1,6 @@ use super::{annotation::Annotation, error::ParseError, Parser}; use crate::{ - ast::{Enum, EnumMember, Named}, + ast::{Enum, EnumMember, Named, Privacy}, inflow::Inflow, name::Name, parser::annotation::AnnotationKind, @@ -14,14 +14,15 @@ impl<'a, I: Inflow> Parser<'a, I> { let source = self.source_here(); assert!(self.input.advance().is_enum_keyword()); + let mut privacy = Privacy::Private; let mut namespace = None; let name = self.parse_identifier(Some("for enum name after 'enum' keyword"))?; self.ignore_newlines(); - #[allow(clippy::never_loop, clippy::match_single_binding)] for annotation in annotations { match annotation.kind { AnnotationKind::Namespace(new_namespace) => namespace = Some(new_namespace), + AnnotationKind::Public => privacy = Privacy::Public, _ => return Err(self.unexpected_annotation(&annotation, Some("for enum"))), } } @@ -63,6 +64,7 @@ impl<'a, I: Inflow> Parser<'a, I> { backing_type: None, members, source, + privacy, }, }) } From 4d63ca6a462556d5d36e3aee3dde687cdb76e374 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Wed, 9 Oct 2024 20:37:03 -0500 Subject: [PATCH 03/14] Added ability to make type aliases and expression definitions public --- src/ast/helper_expr.rs | 3 ++- src/ast/type_alias.rs | 3 ++- src/c/translation/mod.rs | 3 ++- src/c/translation/types/enumeration.rs | 3 ++- src/parser/parse_helper_expr.rs | 5 ++++- src/parser/parse_type_alias.rs | 5 ++++- src/workspace/mod.rs | 3 ++- 7 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/ast/helper_expr.rs b/src/ast/helper_expr.rs index ccf74c2..c988ca7 100644 --- a/src/ast/helper_expr.rs +++ b/src/ast/helper_expr.rs @@ -1,4 +1,4 @@ -use super::Expr; +use super::{Expr, Privacy}; use crate::source_files::Source; #[derive(Debug, Clone)] @@ -6,4 +6,5 @@ pub struct HelperExpr { pub value: Expr, pub source: Source, pub is_file_local_only: bool, + pub privacy: Privacy, } diff --git a/src/ast/type_alias.rs b/src/ast/type_alias.rs index bd9eede..4f28e74 100644 --- a/src/ast/type_alias.rs +++ b/src/ast/type_alias.rs @@ -1,8 +1,9 @@ -use super::Type; +use super::{Privacy, Type}; use crate::source_files::Source; #[derive(Clone, Debug)] pub struct TypeAlias { pub value: Type, pub source: Source, + pub privacy: Privacy, } diff --git a/src/c/translation/mod.rs b/src/c/translation/mod.rs index 9fd7eae..4b3a7b7 100644 --- a/src/c/translation/mod.rs +++ b/src/c/translation/mod.rs @@ -7,7 +7,7 @@ mod types; use self::types::get_name_and_type; pub use self::{expr::translate_expr, function::declare_function}; use crate::{ - ast::{self, AstFile}, + ast::{self, AstFile, Privacy}, c::parser::{CTypedef, DeclarationSpecifiers, Declarator, ParseError}, diagnostics::Diagnostics, name::Name, @@ -37,6 +37,7 @@ pub fn declare_named_declaration( ast::TypeAlias { value: ast_type.clone(), source: declarator.source, + privacy: Privacy::Public, }, ); diff --git a/src/c/translation/types/enumeration.rs b/src/c/translation/types/enumeration.rs index b472b26..05f3de7 100644 --- a/src/c/translation/types/enumeration.rs +++ b/src/c/translation/types/enumeration.rs @@ -1,5 +1,5 @@ use crate::{ - ast::{self, AnonymousEnum, AstFile, EnumMember, TypeKind}, + ast::{self, AnonymousEnum, AstFile, EnumMember, Privacy, TypeKind}, c::{ parser::{error::ParseErrorKind, Enumeration, ParseError}, translation::eval::evaluate_to_const_integer, @@ -67,6 +67,7 @@ pub fn make_anonymous_enum( value: aka_value, source: enumerator.source, is_file_local_only: false, + privacy: Privacy::Public, }, |name| { ParseErrorKind::EnumMemberNameConflictsWithExistingSymbol { diff --git a/src/parser/parse_helper_expr.rs b/src/parser/parse_helper_expr.rs index e8bdbae..c2b6da1 100644 --- a/src/parser/parse_helper_expr.rs +++ b/src/parser/parse_helper_expr.rs @@ -4,7 +4,7 @@ use super::{ Parser, }; use crate::{ - ast::{HelperExpr, Named}, + ast::{HelperExpr, Named, Privacy}, inflow::Inflow, name::Name, token::{Token, TokenKind}, @@ -19,6 +19,7 @@ impl<'a, I: Inflow> Parser<'a, I> { self.input.advance(); let mut namespace = None; + let mut privacy = Privacy::Private; let name = self.parse_identifier(Some("for define name after 'define' keyword"))?; self.ignore_newlines(); @@ -28,6 +29,7 @@ impl<'a, I: Inflow> Parser<'a, I> { for annotation in annotations { match annotation.kind { AnnotationKind::Namespace(new_namespace) => namespace = Some(new_namespace), + AnnotationKind::Public => privacy = Privacy::Public, _ => return Err(self.unexpected_annotation(&annotation, Some("for define"))), } } @@ -40,6 +42,7 @@ impl<'a, I: Inflow> Parser<'a, I> { value, source, is_file_local_only: false, + privacy, }, }) } diff --git a/src/parser/parse_type_alias.rs b/src/parser/parse_type_alias.rs index 05b411d..2acc779 100644 --- a/src/parser/parse_type_alias.rs +++ b/src/parser/parse_type_alias.rs @@ -1,6 +1,6 @@ use super::{annotation::Annotation, error::ParseError, Parser}; use crate::{ - ast::{Named, TypeAlias}, + ast::{Named, Privacy, TypeAlias}, inflow::Inflow, name::Name, parser::annotation::AnnotationKind, @@ -16,6 +16,7 @@ impl<'a, I: Inflow> Parser<'a, I> { assert!(self.input.advance().is_type_alias_keyword()); let mut namespace = None; + let mut privacy = Privacy::Private; let name = self.parse_identifier(Some("for alias name after 'typealias' keyword"))?; self.ignore_newlines(); @@ -23,6 +24,7 @@ impl<'a, I: Inflow> Parser<'a, I> { for annotation in annotations { match annotation.kind { AnnotationKind::Namespace(new_namespace) => namespace = Some(new_namespace), + AnnotationKind::Public => privacy = Privacy::Public, _ => return Err(self.unexpected_annotation(&annotation, Some("for type alias"))), } } @@ -36,6 +38,7 @@ impl<'a, I: Inflow> Parser<'a, I> { value: TypeAlias { value: becomes_type, source, + privacy, }, }) } diff --git a/src/workspace/mod.rs b/src/workspace/mod.rs index ec777de..cc23a62 100644 --- a/src/workspace/mod.rs +++ b/src/workspace/mod.rs @@ -11,7 +11,7 @@ mod module_file; mod normal_file; use crate::{ - ast::{self, AstFile, AstWorkspace, Settings}, + ast::{self, AstFile, AstWorkspace, Privacy, Settings}, c::{ self, lexer::lex_c_code, @@ -451,6 +451,7 @@ fn header( value, source: define.source, is_file_local_only: define.is_file_local_only, + privacy: Privacy::Public, }, ); } From 90a75da97162ac9690581dc73625422a4ee107fb Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Thu, 10 Oct 2024 22:15:51 -0500 Subject: [PATCH 04/14] Continued working on new type resolution system --- src/resolve/conform/mod.rs | 6 +- src/resolve/mod.rs | 100 +++++++++++++++++++++++++--- src/resolved/new_type_resolution.rs | 3 +- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/src/resolve/conform/mod.rs b/src/resolve/conform/mod.rs index c6c230b..0540503 100644 --- a/src/resolve/conform/mod.rs +++ b/src/resolve/conform/mod.rs @@ -62,7 +62,11 @@ pub fn conform_expr( conform_source: Source, ) -> ObjectiveResult { if expr.resolved_type == *to_type { - return O::success(|| expr.clone()); + return O::success(|| TypedExpr { + resolved_type: to_type.clone(), + expr: expr.expr.clone(), + is_initialized: expr.is_initialized, + }); } match &expr.resolved_type.kind { diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 8092f87..0723396 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -22,8 +22,12 @@ use crate::{ ast::{self, AstWorkspace, Type}, cli::BuildOptions, index_map_ext::IndexMapExt, - name::ResolvedName, - resolved::{self, new_type_resolution, Enum, TypedExpr, VariableStorage}, + name::{Name, ResolvedName}, + resolved::{ + self, + new_type_resolution::{self, TypeRef}, + Enum, StructureRef, TypedExpr, VariableStorage, + }, source_files::Source, tag::Tag, workspace::fs::FsNodeId, @@ -103,13 +107,29 @@ pub fn resolve<'a>( let source_files = ast_workspace.source_files; let mut resolved_ast = resolved::Ast::new(source_files, &ast_workspace.fs); + #[derive(Clone, Debug)] + struct TypeJob<'a> { + physical_file_id: FsNodeId, + type_aliases: HashMap<&'a Name, TypeRef>, + structures: Vec, + enums: HashMap<&'a Name, TypeRef>, + } + + let mut type_jobs = Vec::with_capacity(ast_workspace.files.len()); + // Pre-resolve types for new type resolution system - #[allow(unreachable_code, unused_variables)] for (physical_file_id, file) in ast_workspace.files.iter() { let file_id = ast_workspace .get_owning_module(*physical_file_id) .unwrap_or(*physical_file_id); + let mut job = TypeJob { + physical_file_id: *physical_file_id, + type_aliases: HashMap::with_capacity(file.type_aliases.len()), + structures: Vec::with_capacity(file.structures.len()), + enums: HashMap::with_capacity(file.enums.len()), + }; + let decls = resolved_ast.types_per_module.entry(file_id).or_default(); for structure in file.structures.iter() { @@ -144,20 +164,23 @@ pub fn resolve<'a>( privacy, }, ); + + job.structures.push(structure_ref); } for (name, definition) in file.enums.iter() { - eprintln!("warning: enums not implemented for new type resolution system yet"); - continue; - - let representation_type_ref = todo!(); + let backing_type = definition.backing_type.is_some().then(|| { + resolved_ast + .all_types + .insert(new_type_resolution::TypeKind::Unresolved) + }); let kind = new_type_resolution::TypeKind::Enum( new_type_resolution::HumanName(name.to_string()), - representation_type_ref, + backing_type, ); let source = definition.source; - let privacy = todo!("can't use enums with new type resolution system yet, since enums don't have privacy yet"); // definition.privacy; + let privacy = definition.privacy; decls.insert( name.to_string(), @@ -167,10 +190,67 @@ pub fn resolve<'a>( privacy, }, ); + + if let Some(backing_type) = backing_type { + job.enums.insert(name, backing_type); + } } for (name, definition) in file.type_aliases.iter() { - eprintln!("warning: type aliases not implemented for new type resolution system yet"); + let source = definition.source; + let privacy = definition.privacy; + + let becomes_type = resolved_ast + .all_types + .insert(new_type_resolution::TypeKind::Unresolved); + + let kind = new_type_resolution::TypeKind::TypeAlias( + new_type_resolution::HumanName(name.to_string()), + becomes_type, + ); + + job.type_aliases.insert(name, becomes_type); + + decls.insert( + name.to_string(), + new_type_resolution::TypeDecl { + kind, + source, + privacy, + }, + ); + } + + type_jobs.push(job); + } + + // Create edges between types + #[allow(dead_code, unused_variables)] + for job in type_jobs.iter() { + let file = ast_workspace + .files + .get(&job.physical_file_id) + .expect("valid ast file"); + + let module_file_id = ast_workspace + .get_owning_module(job.physical_file_id) + .unwrap_or(job.physical_file_id); + + let types = resolved_ast + .types_per_module + .get(&module_file_id) + .expect("valid module"); + + for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) { + eprintln!("warning - new type resolution does not handle struct fields yet"); + } + + for (name, type_ref) in job.enums.iter() { + eprintln!("warning - new type resolution does not handle enum backing types yet"); + } + + for (name, type_ref) in job.type_aliases.iter() { + eprintln!("warning - new type resolution does not handle enum type aliases yet"); } } diff --git a/src/resolved/new_type_resolution.rs b/src/resolved/new_type_resolution.rs index 3df8be7..a1ae935 100644 --- a/src/resolved/new_type_resolution.rs +++ b/src/resolved/new_type_resolution.rs @@ -9,7 +9,6 @@ use slotmap::new_key_type; new_key_type! { pub struct TypeRef; - pub struct EnumRef; } #[derive(Clone, Debug)] @@ -44,7 +43,7 @@ pub enum TypeKind { AnonymousEnum(AnonymousEnum), FixedArray(Box), FunctionPointer(FunctionPointer), - Enum(HumanName, TypeRef), + Enum(HumanName, Option), Structure(HumanName, StructureRef), TypeAlias(HumanName, TypeRef), } From 998d9d583b18885e3463fe243f3df2e62736045d Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Thu, 10 Oct 2024 21:04:58 -0500 Subject: [PATCH 05/14] Updated automated builds to use pinned LLVM 18 for macOS --- .github/workflows/remoteBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/remoteBuild.yml b/.github/workflows/remoteBuild.yml index fd9eb75..8c2ec69 100644 --- a/.github/workflows/remoteBuild.yml +++ b/.github/workflows/remoteBuild.yml @@ -96,7 +96,7 @@ jobs: cargo build --release env: CC: /opt/homebrew/opt/llvm/bin/clang - LLVM_SYS_181_PREFIX: /opt/homebrew/opt/llvm + LLVM_SYS_181_PREFIX: /opt/homebrew/opt/llvm@18 zstd_DIR: /usr/local/opt/zstd CFLAGS: -static-libstdc++ CXXFLAGS: -static-libstdc++ From 17209d4035601b5494b0094a627d4a13077fc3b2 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Thu, 10 Oct 2024 22:21:41 -0500 Subject: [PATCH 06/14] Added clang to path during automated macOS builds --- .github/workflows/remoteBuild.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/remoteBuild.yml b/.github/workflows/remoteBuild.yml index 8c2ec69..6c62e10 100644 --- a/.github/workflows/remoteBuild.yml +++ b/.github/workflows/remoteBuild.yml @@ -68,6 +68,7 @@ jobs: - name: Install LLVM and dependencies (macOS) if: ${{ matrix.os == 'macos-latest' }} run: | + export PATH=/opt/homebrew/opt/llvm@18/bin:$PATH brew install llvm@18 brew install zstd - name: Install LLVM and dependencies (Ubuntu) From 26c6ba5d80b3dd609ec3d6e339ebc429093013fa Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Thu, 10 Oct 2024 22:34:04 -0500 Subject: [PATCH 07/14] Fixed automated macOS builds to work with updated GitHub actions runners --- .github/workflows/remoteBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/remoteBuild.yml b/.github/workflows/remoteBuild.yml index 6c62e10..0c1c7e0 100644 --- a/.github/workflows/remoteBuild.yml +++ b/.github/workflows/remoteBuild.yml @@ -68,7 +68,7 @@ jobs: - name: Install LLVM and dependencies (macOS) if: ${{ matrix.os == 'macos-latest' }} run: | - export PATH=/opt/homebrew/opt/llvm@18/bin:$PATH + brew install llvm # For clang brew install llvm@18 brew install zstd - name: Install LLVM and dependencies (Ubuntu) From 4ec6cc7be3b1c0b90cf3c2b954d99641cc7daeff Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Fri, 11 Oct 2024 22:36:17 -0500 Subject: [PATCH 08/14] Gutted out the old type resolution system, and started pluging in the new one --- src/ast/workspace/mod.rs | 41 +++-- src/lower/mod.rs | 25 ++- src/resolve/core_structure_info.rs | 10 +- src/resolve/expr/call.rs | 18 +- src/resolve/expr/mod.rs | 23 ++- src/resolve/expr/struct_literal.rs | 29 ++- src/resolve/mod.rs | 273 ++++++++++------------------ src/resolve/stmt.rs | 3 +- src/resolve/type_search_ctx.rs | 186 +++++-------------- src/resolved/mod.rs | 63 +++++-- src/resolved/new_type_resolution.rs | 49 ----- 11 files changed, 280 insertions(+), 440 deletions(-) delete mode 100644 src/resolved/new_type_resolution.rs diff --git a/src/ast/workspace/mod.rs b/src/ast/workspace/mod.rs index fd5224b..db8ed6d 100644 --- a/src/ast/workspace/mod.rs +++ b/src/ast/workspace/mod.rs @@ -21,24 +21,6 @@ pub struct AstWorkspace<'a> { impl<'a> AstWorkspace<'a> { pub const DEFAULT_SETTINGS_ID: SettingsId = SettingsId(0); - pub fn get_owning_module(&self, fs_node_id: FsNodeId) -> Option { - let mut fs_node_id = fs_node_id; - - loop { - if self.module_folders.contains_key(&fs_node_id) { - return Some(fs_node_id); - } - - if let Some(parent) = self.fs.get(fs_node_id).parent { - fs_node_id = parent; - } else { - break; - } - } - - None - } - pub fn new( fs: Fs, files: IndexMap, @@ -70,6 +52,29 @@ impl<'a> AstWorkspace<'a> { workspace } + pub fn get_owning_module(&self, fs_node_id: FsNodeId) -> Option { + let mut fs_node_id = fs_node_id; + + loop { + if self.module_folders.contains_key(&fs_node_id) { + return Some(fs_node_id); + } + + if let Some(parent) = self.fs.get(fs_node_id).parent { + fs_node_id = parent; + } else { + break; + } + } + + None + } + + pub fn get_settings_for_module(&self, module_node_id: FsNodeId) -> &Settings { + let file = self.files.get(&module_node_id).expect("valid module id"); + &self.settings[file.settings.unwrap_or_default().0] + } + pub fn get_mut(&mut self, id: FsNodeId) -> Option<&mut AstFile> { self.files.get_mut(&id) } diff --git a/src/lower/mod.rs b/src/lower/mod.rs index 752089e..39f89ff 100644 --- a/src/lower/mod.rs +++ b/src/lower/mod.rs @@ -84,7 +84,7 @@ fn lower_global( let mangled_name = if global.is_foreign { global.name.plain().to_string() } else { - global.name.display(resolved_ast.fs).to_string() + global.name.display(&resolved_ast.workspace.fs).to_string() }; ir_module.globals.insert( @@ -167,7 +167,10 @@ fn lower_function( } else { return Err(LowerErrorKind::MustReturnValueOfTypeBeforeExitingFunction { return_type: function.return_type.to_string(), - function: function.name.display(resolved_ast.fs).to_string(), + function: function + .name + .display(&resolved_ast.workspace.fs) + .to_string(), } .at(function.source)); } @@ -200,7 +203,10 @@ fn lower_function( } else if function.is_foreign { function.name.plain().to_string() } else { - function.name.display(resolved_ast.fs).to_string() + function + .name + .display(&resolved_ast.workspace.fs) + .to_string() }; let is_main = mangled_name == "main"; @@ -341,6 +347,8 @@ fn lower_type( use resolved::{IntegerBits as Bits, IntegerSign as Sign}; match &resolved_type.kind { + resolved::TypeKind::Unresolved => panic!(), + resolved::TypeKind::TypeAlias(_, _) => todo!("lower type ref"), resolved::TypeKind::Boolean => Ok(ir::Type::Boolean), resolved::TypeKind::Integer(bits, sign) => Ok(match (bits, sign) { (Bits::Bits8, Sign::Signed) => ir::Type::S8, @@ -395,13 +403,16 @@ fn lower_type( }))) } resolved::TypeKind::FunctionPointer(_function_pointer) => Ok(ir::Type::FunctionPointer), - resolved::TypeKind::Enum(enum_name) => { + resolved::TypeKind::Enum(_, _enum_name) => { + todo!("lower enum type"); + /* let enum_definition = resolved_ast .enums .get(enum_name) .expect("referenced enum to exist"); lower_type(target, &enum_definition.resolved_type, resolved_ast) + */ } } } @@ -898,7 +909,7 @@ fn lower_expr( LowerErrorKind::NoSuchEnumMember { enum_name: enum_member_literal .enum_name - .display(resolved_ast.fs) + .display(&resolved_ast.workspace.fs) .to_string(), variant_name: enum_member_literal.variant_name.clone(), } @@ -918,7 +929,7 @@ fn lower_expr( value: value.to_string(), expected_type: enum_member_literal .enum_name - .display(resolved_ast.fs) + .display(&resolved_ast.workspace.fs) .to_string(), } .at(enum_definition.source) @@ -953,7 +964,7 @@ fn lower_expr( return Err(LowerErrorKind::EnumBackingTypeMustBeInteger { enum_name: enum_member_literal .enum_name - .display(resolved_ast.fs) + .display(&resolved_ast.workspace.fs) .to_string(), } .at(enum_definition.source)) diff --git a/src/resolve/core_structure_info.rs b/src/resolve/core_structure_info.rs index c486d7a..843a22f 100644 --- a/src/resolve/core_structure_info.rs +++ b/src/resolve/core_structure_info.rs @@ -1,4 +1,4 @@ -use super::error::{ResolveError, ResolveErrorKind}; +use super::error::ResolveError; use crate::{ name::ResolvedName, resolved::{self, StructureRef}, @@ -6,9 +6,12 @@ use crate::{ }; pub fn get_core_structure_info( - resolved_type: &resolved::Type, - source: Source, + _resolved_type: &resolved::Type, + _source: Source, ) -> Result<(&ResolvedName, StructureRef), ResolveError> { + todo!("get_core_structure_info"); + + /* match &resolved_type.kind { resolved::TypeKind::Structure(name, structure_ref) => Ok((name, *structure_ref)), _ => Err(ResolveErrorKind::CannotCreateStructLiteralForNonStructure { @@ -16,4 +19,5 @@ pub fn get_core_structure_info( } .at(source)), } + */ } diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index 71c2503..eb2fbd5 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -69,7 +69,10 @@ pub fn resolve_call_expr( return Err(ResolveErrorKind::BadTypeForArgumentToFunction { expected: preferred_type.to_string(), got: argument.resolved_type.to_string(), - name: function.name.display(ctx.resolved_ast.fs).to_string(), + name: function + .name + .display(&ctx.resolved_ast.workspace.fs) + .to_string(), i, } .at(source)); @@ -88,13 +91,20 @@ pub fn resolve_call_expr( } if let Some(required_ty) = &call.expected_to_return { - let resolved_required_ty = - resolve_type(ctx.type_search_ctx, required_ty, &mut Default::default())?; + let resolved_required_ty = resolve_type( + ctx.resolved_ast, + ctx.module_fs_node_id, + required_ty, + &mut Default::default(), + )?; if resolved_required_ty != return_type { return Err(ResolveErrorKind::FunctionMustReturnType { of: required_ty.to_string(), - function_name: function.name.display(ctx.resolved_ast.fs).to_string(), + function_name: function + .name + .display(&ctx.resolved_ast.workspace.fs) + .to_string(), } .at(function.return_type.source)); } diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index 1deff11..e55568c 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -20,7 +20,6 @@ use super::{ error::ResolveError, function_search_ctx::FunctionSearchCtx, global_search_ctx::GlobalSearchCtx, - type_search_ctx::TypeSearchCtx, variable_search_ctx::VariableSearchCtx, Initialized, }; @@ -52,7 +51,6 @@ use std::collections::HashMap; pub struct ResolveExprCtx<'a, 'b> { pub resolved_ast: &'b mut resolved::Ast<'a>, pub function_search_ctx: &'b FunctionSearchCtx, - pub type_search_ctx: &'b TypeSearchCtx<'a>, pub global_search_ctx: &'b GlobalSearchCtx, pub variable_search_ctx: VariableSearchCtx, pub resolved_function_ref: resolved::FunctionRef, @@ -351,7 +349,10 @@ pub fn resolve_expr( resolved::TypeKind::Boolean.at(source), resolved::Expr::new(resolved::ExprKind::BooleanLiteral(*value), source), )), - ast::ExprKind::EnumMemberLiteral(enum_member_literal) => { + ast::ExprKind::EnumMemberLiteral(_enum_member_literal) => { + todo!("resolve enum member literal"); + + /* let resolved_type = resolve_type( ctx.type_search_ctx, &ast::TypeKind::Named(enum_member_literal.enum_name.clone()) @@ -359,7 +360,7 @@ pub fn resolve_expr( &mut Default::default(), )?; - let TypeKind::Enum(resolved_name) = &resolved_type.kind else { + let TypeKind::Enum(_, _) = &resolved_type.kind else { return Err(ResolveErrorKind::StaticMemberOfTypeDoesNotExist { ty: enum_member_literal.enum_name.to_string(), member: enum_member_literal.variant_name.clone(), @@ -379,7 +380,8 @@ pub fn resolve_expr( })), source, ), - )) + )) + */ } ast::ExprKind::InterpreterSyscall(info) => { let ast::InterpreterSyscall { @@ -388,14 +390,19 @@ pub fn resolve_expr( result_type, } = &**info; - let resolved_type = - resolve_type(ctx.type_search_ctx, result_type, &mut Default::default())?; + let resolved_type = resolve_type( + ctx.resolved_ast, + ctx.module_fs_node_id, + result_type, + &mut Default::default(), + )?; let mut resolved_args = Vec::with_capacity(args.len()); for (expected_arg_type, arg) in args { let preferred_type = resolve_type( - ctx.type_search_ctx, + ctx.resolved_ast, + ctx.module_fs_node_id, expected_arg_type, &mut Default::default(), )?; diff --git a/src/resolve/expr/struct_literal.rs b/src/resolve/expr/struct_literal.rs index dd31555..5501df6 100644 --- a/src/resolve/expr/struct_literal.rs +++ b/src/resolve/expr/struct_literal.rs @@ -1,17 +1,10 @@ -use super::{resolve_expr, PreferredType, ResolveExprCtx}; +use super::ResolveExprCtx; use crate::{ ast::{self, ConformBehavior, FieldInitializer, FillBehavior}, - resolve::{ - conform::{conform_expr, ConformMode, Perform}, - core_structure_info::get_core_structure_info, - error::{ResolveError, ResolveErrorKind}, - resolve_type, Initialized, - }, - resolved::{self, StructLiteral, StructureRef, TypedExpr}, + resolve::error::ResolveError, + resolved::{self, StructureRef, TypedExpr}, source_files::Source, }; -use indexmap::IndexMap; -use itertools::Itertools; fn get_field_info<'a>( ctx: &'a ResolveExprCtx, @@ -30,13 +23,16 @@ fn get_field_info<'a>( } pub fn resolve_struct_literal_expr( - ctx: &mut ResolveExprCtx, - ast_type: &ast::Type, - fields: &[FieldInitializer], - fill_behavior: FillBehavior, - conform_behavior: ConformBehavior, - source: Source, + _ctx: &mut ResolveExprCtx, + _ast_type: &ast::Type, + _fields: &[FieldInitializer], + _fill_behavior: FillBehavior, + _conform_behavior: ConformBehavior, + _source: Source, ) -> Result { + todo!("resolve_struct_literal_expr"); + + /* let resolved_type = resolve_type(ctx.type_search_ctx, ast_type, &mut Default::default())?; let (struct_name, structure_ref) = get_core_structure_info(&resolved_type, source)?; @@ -170,4 +166,5 @@ pub fn resolve_struct_literal_expr( ast_type.source, ), )) + */ } diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 0723396..d4541c1 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -15,7 +15,6 @@ use self::{ expr::ResolveExprCtx, global_search_ctx::GlobalSearchCtx, stmt::resolve_stmts, - type_search_ctx::TypeSearchCtx, variable_search_ctx::VariableSearchCtx, }; use crate::{ @@ -24,9 +23,7 @@ use crate::{ index_map_ext::IndexMapExt, name::{Name, ResolvedName}, resolved::{ - self, - new_type_resolution::{self, TypeRef}, - Enum, StructureRef, TypedExpr, VariableStorage, + self, HumanName, StructureRef, TypeDecl, TypeKind, TypeRef, TypedExpr, VariableStorage, }, source_files::Source, tag::Tag, @@ -39,7 +36,7 @@ use std::{ borrow::Borrow, collections::{HashMap, HashSet, VecDeque}, }; -use type_search_ctx::TypeMapping; +use type_search_ctx::find_type; enum Job { Regular(FsNodeId, usize, resolved::FunctionRef), @@ -47,24 +44,20 @@ enum Job { struct ResolveCtx<'a> { pub jobs: VecDeque, - pub type_search_ctxs: IndexMap>, pub function_search_ctxs: IndexMap, pub global_search_ctxs: IndexMap, pub helper_exprs: IndexMap, pub public_functions: HashMap>>, - pub public_types: HashMap>>>, } impl<'a> ResolveCtx<'a> { fn new(helper_exprs: IndexMap) -> Self { Self { jobs: Default::default(), - type_search_ctxs: Default::default(), function_search_ctxs: Default::default(), global_search_ctxs: Default::default(), helper_exprs, public_functions: HashMap::new(), - public_types: HashMap::new(), } } } @@ -105,7 +98,7 @@ pub fn resolve<'a>( let mut ctx = ResolveCtx::new(helper_exprs); let source_files = ast_workspace.source_files; - let mut resolved_ast = resolved::Ast::new(source_files, &ast_workspace.fs); + let mut resolved_ast = resolved::Ast::new(source_files, &ast_workspace); #[derive(Clone, Debug)] struct TypeJob<'a> { @@ -144,10 +137,8 @@ pub fn resolve<'a>( source: structure.source, }); - let struct_type_kind = new_type_resolution::TypeKind::Structure( - new_type_resolution::HumanName(structure.name.to_string()), - structure_ref, - ); + let struct_type_kind = + TypeKind::Structure(HumanName(structure.name.to_string()), structure_ref); let Some(name) = structure.name.as_plain_str() else { eprintln!( @@ -158,7 +149,7 @@ pub fn resolve<'a>( decls.insert( name.to_string(), - new_type_resolution::TypeDecl { + TypeDecl { kind: struct_type_kind.clone(), source, privacy, @@ -169,22 +160,18 @@ pub fn resolve<'a>( } for (name, definition) in file.enums.iter() { - let backing_type = definition.backing_type.is_some().then(|| { - resolved_ast - .all_types - .insert(new_type_resolution::TypeKind::Unresolved) - }); + let backing_type = definition + .backing_type + .is_some() + .then(|| resolved_ast.all_types.insert(TypeKind::Unresolved)); - let kind = new_type_resolution::TypeKind::Enum( - new_type_resolution::HumanName(name.to_string()), - backing_type, - ); + let kind = TypeKind::Enum(HumanName(name.to_string()), backing_type); let source = definition.source; let privacy = definition.privacy; decls.insert( name.to_string(), - new_type_resolution::TypeDecl { + TypeDecl { kind, source, privacy, @@ -199,21 +186,14 @@ pub fn resolve<'a>( for (name, definition) in file.type_aliases.iter() { let source = definition.source; let privacy = definition.privacy; - - let becomes_type = resolved_ast - .all_types - .insert(new_type_resolution::TypeKind::Unresolved); - - let kind = new_type_resolution::TypeKind::TypeAlias( - new_type_resolution::HumanName(name.to_string()), - becomes_type, - ); + let becomes_type = resolved_ast.all_types.insert(TypeKind::Unresolved); + let kind = TypeKind::TypeAlias(HumanName(name.to_string()), becomes_type); job.type_aliases.insert(name, becomes_type); decls.insert( name.to_string(), - new_type_resolution::TypeDecl { + TypeDecl { kind, source, privacy, @@ -242,130 +222,38 @@ pub fn resolve<'a>( .expect("valid module"); for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) { - eprintln!("warning - new type resolution does not handle struct fields yet"); - } - - for (name, type_ref) in job.enums.iter() { - eprintln!("warning - new type resolution does not handle enum backing types yet"); - } - - for (name, type_ref) in job.type_aliases.iter() { - eprintln!("warning - new type resolution does not handle enum type aliases yet"); - } - } - - // Unify type aliases into single map - for (real_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace - .get_owning_module(*real_file_id) - .unwrap_or(*real_file_id); - - let imported_namespaces = - &ast_workspace.settings[file.settings.unwrap_or_default().0].imported_namespaces; - - let type_search_ctx = ctx.type_search_ctxs.get_or_insert_with(file_id, || { - TypeSearchCtx::new(imported_namespaces.clone(), source_files, file_id) - }); - - for (alias_name, alias) in file.type_aliases.iter() { - type_search_ctx.put_type_alias(&alias_name, alias, alias.source)?; - } - } - - // Temporarily used stack to keep track of used type aliases - let mut used_aliases = HashSet::::new(); - - // Pre-compute resolved enum types - for (physical_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace - .get_owning_module(*physical_file_id) - .unwrap_or(*physical_file_id); - - let type_search_ctx = ctx.type_search_ctxs.get_mut(&file_id).unwrap(); - - for (enum_name, enum_definition) in file.enums.iter() { - let resolved_type = resolve_enum_backing_type( - type_search_ctx, - enum_definition.backing_type.as_ref(), - &mut used_aliases, - enum_definition.source, - )?; - - let members = enum_definition.members.clone(); - - resolved_ast.enums.insert( - ResolvedName::new(file_id, enum_name), - Enum { - resolved_type, - source: enum_definition.source, - members, - }, - ); - - type_search_ctx.put_type( - enum_name, - resolved::TypeKind::Enum(ResolvedName::new(file_id, enum_name)), - enum_definition.source, - )?; - } - } - - // Precompute resolved struct types - for (physical_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace - .get_owning_module(*physical_file_id) - .unwrap_or(*physical_file_id); - - let type_search_ctx = ctx.type_search_ctxs.get_mut(&file_id).unwrap(); + for (field_name, field) in structure.fields.iter() { + let resolved_type = resolve_type_or_undeclared( + &resolved_ast, + module_file_id, + &field.ast_type, + &mut Default::default(), + )?; - for structure in file.structures.iter() { - let mut fields = IndexMap::new(); + let resolved_struct = resolved_ast + .structures + .get_mut(*structure_ref) + .expect("valid struct"); - for (field_name, field) in structure.fields.iter() { - fields.insert( - field_name.into(), + resolved_struct.fields.insert( + field_name.clone(), resolved::Field { - resolved_type: resolve_type( - type_search_ctx, - &field.ast_type, - &mut used_aliases, - )?, + resolved_type, privacy: field.privacy, source: field.source, }, ); } - let resolved_name = ResolvedName::new(file_id, &structure.name); - - let structure_key = resolved_ast.structures.insert(resolved::Structure { - name: resolved_name.clone(), - fields, - is_packed: structure.is_packed, - source: structure.source, - }); - - type_search_ctx.put_type( - &structure.name, - resolved::TypeKind::Structure(resolved_name, structure_key), - structure.source, - )?; + eprintln!("warning - new type resolution does not handle struct fields yet"); } - } - - // Resolve type aliases - for (real_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace - .get_owning_module(*real_file_id) - .unwrap_or(*real_file_id); - let type_search_ctx = ctx.type_search_ctxs.get_mut(&file_id).unwrap(); - - for (alias_name, alias) in file.type_aliases.iter() { - let resolved_type = - resolve_type_or_undeclared(type_search_ctx, &alias.value, &mut used_aliases)?; + for (name, type_ref) in job.enums.iter() { + eprintln!("warning - new type resolution does not handle enum backing types yet"); + } - type_search_ctx.override_type(&alias_name, resolved_type.kind); + for (name, type_ref) in job.type_aliases.iter() { + eprintln!("warning - new type resolution does not handle enum type aliases yet"); } } @@ -375,15 +263,17 @@ pub fn resolve<'a>( .get_owning_module(*physical_file_id) .unwrap_or(*physical_file_id); - let type_search_ctx = ctx.type_search_ctxs.get_mut(&file_id).unwrap(); - let global_search_context = ctx .global_search_ctxs .get_or_insert_with(file_id, || GlobalSearchCtx::new()); for global in file.global_variables.iter() { - let resolved_type = - resolve_type(type_search_ctx, &global.ast_type, &mut Default::default())?; + let resolved_type = resolve_type( + &resolved_ast, + file_id, + &global.ast_type, + &mut Default::default(), + )?; let resolved_name = ResolvedName::new(file_id, &global.name); @@ -405,16 +295,15 @@ pub fn resolve<'a>( .get_owning_module(*physical_file_id) .unwrap_or(*physical_file_id); - let type_search_ctx = ctx.type_search_ctxs.get_mut(&file_id).unwrap(); - for (function_i, function) in file.functions.iter().enumerate() { let name = ResolvedName::new(file_id, &function.name); let function_ref = resolved_ast.functions.insert(resolved::Function { name: name.clone(), - parameters: resolve_parameters(type_search_ctx, &function.parameters)?, + parameters: resolve_parameters(&resolved_ast, file_id, &function.parameters)?, return_type: resolve_type( - type_search_ctx, + &resolved_ast, + file_id, &function.return_type, &mut Default::default(), )?, @@ -491,11 +380,6 @@ pub fn resolve<'a>( .get(&file_id) .expect("function search context to exist for file"); - let type_search_ctx = ctx - .type_search_ctxs - .get(&file_id) - .expect("type search context to exist for file"); - let global_search_ctx = ctx .global_search_ctxs .get(&file_id) @@ -514,18 +398,19 @@ pub fn resolve<'a>( let mut variable_search_ctx = VariableSearchCtx::new(); { - let function = resolved_ast - .functions - .get_mut(resolved_function_ref) - .unwrap(); - for parameter in ast_function.parameters.required.iter() { let resolved_type = resolve_type( - type_search_ctx, + &resolved_ast, + file_id, ¶meter.ast_type, &mut Default::default(), )?; + let function = resolved_ast + .functions + .get_mut(resolved_function_ref) + .unwrap(); + let variable_key = function.variables.add_parameter(resolved_type.clone()); variable_search_ctx.put( @@ -547,7 +432,6 @@ pub fn resolve<'a>( let mut ctx = ResolveExprCtx { resolved_ast: &mut resolved_ast, function_search_ctx, - type_search_ctx, global_search_ctx, variable_search_ctx, resolved_function_ref, @@ -580,11 +464,17 @@ enum Initialized { } fn resolve_type_or_undeclared<'a>( - type_search_ctx: &'a TypeSearchCtx<'_>, + resolved_ast: &resolved::Ast, + module_fs_node_id: FsNodeId, ast_type: &'a ast::Type, used_aliases_stack: &mut HashSet, ) -> Result { - match resolve_type(type_search_ctx, ast_type, used_aliases_stack) { + match resolve_type( + resolved_ast, + module_fs_node_id, + ast_type, + used_aliases_stack, + ) { Ok(inner) => Ok(inner), Err(_) if ast_type.kind.allow_indirect_undefined() => { Ok(resolved::TypeKind::Void.at(ast_type.source)) @@ -594,7 +484,8 @@ fn resolve_type_or_undeclared<'a>( } fn resolve_type<'a>( - type_search_ctx: &'a TypeSearchCtx<'_>, + resolved_ast: &resolved::Ast, + module_fs_node_id: FsNodeId, ast_type: &'a ast::Type, used_aliases_stack: &mut HashSet, ) -> Result { @@ -603,12 +494,17 @@ fn resolve_type<'a>( ast::TypeKind::Integer(bits, sign) => Ok(resolved::TypeKind::Integer(*bits, *sign)), ast::TypeKind::CInteger(integer, sign) => Ok(resolved::TypeKind::CInteger(*integer, *sign)), ast::TypeKind::Pointer(inner) => { - let inner = resolve_type_or_undeclared(type_search_ctx, inner, used_aliases_stack)?; + let inner = resolve_type_or_undeclared( + resolved_ast, + module_fs_node_id, + inner, + used_aliases_stack, + )?; Ok(resolved::TypeKind::Pointer(Box::new(inner))) } ast::TypeKind::Void => Ok(resolved::TypeKind::Void), - ast::TypeKind::Named(name) => match type_search_ctx.find_type(name, used_aliases_stack) { + ast::TypeKind::Named(name) => match find_type(resolved_ast, module_fs_node_id, name) { Ok(found) => Ok(found.into_owned()), Err(err) => Err(err.into_resolve_error(name, ast_type.source)), }, @@ -617,7 +513,8 @@ fn resolve_type<'a>( ast::TypeKind::AnonymousUnion(..) => todo!("resolve anonymous union type"), ast::TypeKind::AnonymousEnum(anonymous_enum) => { let resolved_type = Box::new(resolve_enum_backing_type( - type_search_ctx, + resolved_ast, + module_fs_node_id, anonymous_enum.backing_type.as_deref(), &mut Default::default(), ast_type.source, @@ -634,8 +531,12 @@ fn resolve_type<'a>( ast::TypeKind::FixedArray(fixed_array) => { if let ast::ExprKind::Integer(integer) = &fixed_array.count.kind { if let Ok(size) = integer.value().try_into() { - let inner = - resolve_type(type_search_ctx, &fixed_array.ast_type, used_aliases_stack)?; + let inner = resolve_type( + resolved_ast, + module_fs_node_id, + &fixed_array.ast_type, + used_aliases_stack, + )?; Ok(resolved::TypeKind::FixedArray(Box::new( resolved::FixedArray { size, inner }, @@ -651,8 +552,12 @@ fn resolve_type<'a>( let mut parameters = Vec::with_capacity(function_pointer.parameters.len()); for parameter in function_pointer.parameters.iter() { - let resolved_type = - resolve_type(type_search_ctx, ¶meter.ast_type, used_aliases_stack)?; + let resolved_type = resolve_type( + resolved_ast, + module_fs_node_id, + ¶meter.ast_type, + used_aliases_stack, + )?; parameters.push(resolved::Parameter { name: parameter.name.clone(), @@ -661,7 +566,8 @@ fn resolve_type<'a>( } let return_type = Box::new(resolve_type( - type_search_ctx, + resolved_ast, + module_fs_node_id, &function_pointer.return_type, used_aliases_stack, )?); @@ -679,7 +585,8 @@ fn resolve_type<'a>( } fn resolve_parameters( - type_search_ctx: &TypeSearchCtx<'_>, + resolved_ast: &resolved::Ast, + module_fs_node_id: FsNodeId, parameters: &ast::Parameters, ) -> Result { let mut required = Vec::with_capacity(parameters.required.len()); @@ -688,7 +595,8 @@ fn resolve_parameters( required.push(resolved::Parameter { name: parameter.name.clone(), resolved_type: resolve_type( - type_search_ctx, + resolved_ast, + module_fs_node_id, ¶meter.ast_type, &mut Default::default(), )?, @@ -721,13 +629,14 @@ fn ensure_initialized( } fn resolve_enum_backing_type( - type_search_ctx: &TypeSearchCtx, + resolved_ast: &resolved::Ast, + module_fs_node_id: FsNodeId, backing_type: Option>, used_aliases: &mut HashSet, source: Source, ) -> Result { if let Some(backing_type) = backing_type.as_ref().map(Borrow::borrow) { - resolve_type(type_search_ctx, backing_type, used_aliases) + resolve_type(resolved_ast, module_fs_node_id, backing_type, used_aliases) } else { Ok(resolved::TypeKind::Integer(IntegerBits::Bits64, IntegerSign::Unsigned).at(source)) } diff --git a/src/resolve/stmt.rs b/src/resolve/stmt.rs index b0f186d..679535b 100644 --- a/src/resolve/stmt.rs +++ b/src/resolve/stmt.rs @@ -86,7 +86,8 @@ pub fn resolve_stmt( )), ast::StmtKind::Declaration(declaration) => { let resolved_type = resolve_type( - ctx.type_search_ctx, + ctx.resolved_ast, + ctx.module_fs_node_id, &declaration.ast_type, &mut Default::default(), )?; diff --git a/src/resolve/type_search_ctx.rs b/src/resolve/type_search_ctx.rs index b7323c7..600ab72 100644 --- a/src/resolve/type_search_ctx.rs +++ b/src/resolve/type_search_ctx.rs @@ -1,29 +1,60 @@ -use super::{ - error::{ResolveError, ResolveErrorKind}, - resolve_type, -}; +use super::error::{ResolveError, ResolveErrorKind}; use crate::{ - ast, name::{Name, ResolvedName}, resolved, - source_files::{Source, SourceFiles}, + source_files::Source, workspace::fs::FsNodeId, }; -use indexmap::IndexMap; -use std::{borrow::Cow, collections::HashSet}; +use std::borrow::Cow; + +pub fn find_type<'a>( + resolved_ast: &'a resolved::Ast, + module_node_id: FsNodeId, + name: &Name, +) -> Result, FindTypeError> { + let _source_files = resolved_ast.source_files; + let _settings = resolved_ast + .workspace + .get_settings_for_module(module_node_id); + let _all_types = &resolved_ast.all_types; + + if let Some(_name) = name.as_plain_str() { + todo!("TypeSearchCtx find_type for local type"); + } -#[derive(Clone, Debug)] -pub struct TypeSearchCtx<'a> { - types: IndexMap>, - imported_namespaces: Vec>, - source_files: &'a SourceFiles, - fs_node_id: FsNodeId, -} + todo!("TypeSearchCtx find_type"); -#[derive(Clone, Debug)] -pub enum TypeMapping<'a> { - Normal(resolved::TypeKind), - Alias(&'a ast::TypeAlias), + /* + let resolved_name = ResolvedName::new(self.fs_node_id, name); + + if let Some(mapping) = self.types.get(&resolved_name) { + return self.resolve_mapping(&resolved_name, mapping, used_aliases_stack); + } + + if name.namespace.is_empty() { + let mut matches = self + .settings + .imported_namespaces + .iter() + .filter_map(|namespace| { + let resolved_name = ResolvedName::new( + self.fs_node_id, + &Name::new(Some(namespace.clone()), name.basename.clone()), + ); + self.types.get(&resolved_name) + }); + + if let Some(found) = matches.next() { + if matches.next().is_some() { + return Err(FindTypeError::Ambiguous); + } else { + return self.resolve_mapping(&resolved_name, found, used_aliases_stack); + } + } + } + */ + + Err(FindTypeError::NotDefined) } #[derive(Clone, Debug)] @@ -55,120 +86,3 @@ impl FindTypeError { } } } - -impl<'a> TypeSearchCtx<'a> { - pub fn new( - imported_namespaces: Vec>, - source_files: &'a SourceFiles, - fs_node_id: FsNodeId, - ) -> Self { - Self { - types: Default::default(), - imported_namespaces, - source_files, - fs_node_id, - } - } - - pub fn find_type( - &'a self, - name: &Name, - used_aliases_stack: &mut HashSet, - ) -> Result, FindTypeError> { - let resolved_name = ResolvedName::new(self.fs_node_id, name); - - if let Some(mapping) = self.types.get(&resolved_name) { - return self.resolve_mapping(&resolved_name, mapping, used_aliases_stack); - } - - if name.namespace.is_empty() { - let mut matches = self.imported_namespaces.iter().filter_map(|namespace| { - let resolved_name = ResolvedName::new( - self.fs_node_id, - &Name::new(Some(namespace.clone()), name.basename.clone()), - ); - self.types.get(&resolved_name) - }); - - if let Some(found) = matches.next() { - if matches.next().is_some() { - return Err(FindTypeError::Ambiguous); - } else { - return self.resolve_mapping(&resolved_name, found, used_aliases_stack); - } - } - } - - Err(FindTypeError::NotDefined) - } - - pub fn resolve_mapping( - &self, - resolved_name: &ResolvedName, - mapping: &'a TypeMapping, - used_aliases_stack: &mut HashSet, - ) -> Result, FindTypeError> { - match mapping { - TypeMapping::Normal(kind) => Ok(Cow::Borrowed(kind)), - TypeMapping::Alias(alias) => { - if used_aliases_stack.insert(resolved_name.clone()) { - let inner = resolve_type(self, &alias.value, used_aliases_stack) - .map_err(FindTypeError::ResolveError)?; - used_aliases_stack.remove(&resolved_name); - Ok(Cow::Owned(inner.kind.clone())) - } else { - Err(FindTypeError::RecursiveAlias(resolved_name.clone())) - } - } - } - } - - pub fn put_type( - &mut self, - name: &Name, - value: resolved::TypeKind, - source: Source, - ) -> Result<(), ResolveError> { - let resolved_name = ResolvedName::new(self.fs_node_id, name); - - if self - .types - .insert(resolved_name, TypeMapping::Normal(value)) - .is_some() - { - return Err(ResolveErrorKind::MultipleDefinitionsOfTypeNamed { - name: name.to_string(), - } - .at(source)); - } - - Ok(()) - } - - pub fn override_type(&mut self, name: &Name, value: resolved::TypeKind) { - let resolved_name = ResolvedName::new(self.fs_node_id, name); - self.types.insert(resolved_name, TypeMapping::Normal(value)); - } - - pub fn put_type_alias( - &mut self, - name: &Name, - value: &'a ast::TypeAlias, - source: Source, - ) -> Result<(), ResolveError> { - let resolved_name = ResolvedName::new(self.fs_node_id, &name); - - if self - .types - .insert(resolved_name, TypeMapping::Alias(value)) - .is_some() - { - return Err(ResolveErrorKind::MultipleDefinitionsOfTypeNamed { - name: name.to_string(), - } - .at(source)); - } - - Ok(()) - } -} diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index 75d1c25..6cc09bc 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -1,19 +1,18 @@ mod variable_storage; -pub mod new_type_resolution; pub use self::variable_storage::VariableStorageKey; pub use crate::ast::{ CInteger, EnumMember, FloatSize, IntegerBits, IntegerKnown, IntegerSign, ShortCircuitingBinaryOperator, UnaryMathOperator, }; use crate::{ - ast::fmt_c_integer, + ast::{fmt_c_integer, AstWorkspace}, ir::InterpreterSyscallKind, name::ResolvedName, source_files::{Source, SourceFiles}, tag::Tag, target::Target, - workspace::fs::{Fs, FsNodeId}, + workspace::fs::FsNodeId, }; use derive_more::{IsVariant, Unwrap}; use indexmap::IndexMap; @@ -31,6 +30,7 @@ new_key_type! { pub struct FunctionRef; pub struct GlobalVarRef; pub struct StructureRef; + pub struct TypeRef; } #[derive(Clone, Debug)] @@ -41,14 +41,14 @@ pub struct Ast<'a> { pub structures: SlotMap, pub globals: SlotMap, pub enums: IndexMap, - pub fs: &'a Fs, + pub workspace: &'a AstWorkspace<'a>, // New Experimental Type Resolution System - pub all_types: SlotMap, - pub types_per_module: HashMap>, + pub all_types: SlotMap, + pub types_per_module: HashMap>, } impl<'a> Ast<'a> { - pub fn new(source_files: &'a SourceFiles, fs: &'a Fs) -> Self { + pub fn new(source_files: &'a SourceFiles, workspace: &'a AstWorkspace) -> Self { Self { source_files, entry_point: None, @@ -56,7 +56,7 @@ impl<'a> Ast<'a> { structures: SlotMap::with_key(), globals: SlotMap::with_key(), enums: IndexMap::new(), - fs, + workspace, all_types: SlotMap::with_key(), types_per_module: HashMap::new(), } @@ -127,6 +127,12 @@ pub struct Field { pub source: Source, } +impl Display for TypeRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TypeRef(???)") + } +} + #[derive(Clone, Debug)] pub struct Type { pub kind: TypeKind, @@ -135,7 +141,10 @@ pub struct Type { impl Type { pub fn pointer(self, source: Source) -> Self { - TypeKind::Pointer(Box::new(self)).at(source) + Self { + kind: TypeKind::Pointer(Box::new(self)), + source, + } } pub fn is_ambiguous(&self) -> bool { @@ -155,8 +164,25 @@ impl PartialEq for Type { } } +#[derive(Clone, Debug)] +pub struct TypeDecl { + pub kind: TypeKind, + pub source: Source, + pub privacy: Privacy, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct HumanName(pub String); + +impl Display for HumanName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + #[derive(Clone, Debug, PartialEq, IsVariant, Unwrap)] pub enum TypeKind { + Unresolved, Boolean, Integer(IntegerBits, IntegerSign), CInteger(CInteger, Option), @@ -164,14 +190,15 @@ pub enum TypeKind { FloatLiteral(f64), Floating(FloatSize), Pointer(Box), - Structure(ResolvedName, StructureRef), Void, AnonymousStruct(), AnonymousUnion(), AnonymousEnum(AnonymousEnum), FixedArray(Box), FunctionPointer(FunctionPointer), - Enum(ResolvedName), + Enum(HumanName, Option), + Structure(HumanName, StructureRef), + TypeAlias(HumanName, TypeRef), } impl TypeKind { @@ -243,7 +270,7 @@ pub struct AnonymousEnum { impl PartialEq for AnonymousEnum { fn eq(&self, other: &Self) -> bool { - self.resolved_type.kind.eq(&other.resolved_type.kind) && self.members.eq(&other.members) + self.resolved_type.eq(&other.resolved_type) && self.members.eq(&other.members) } } @@ -281,6 +308,8 @@ impl TypeKind { target.map(|target| target.default_c_integer_sign(*integer)) } } + TypeKind::TypeAlias(_, _type_ref) => todo!(), + TypeKind::Unresolved => panic!(), TypeKind::Floating(_) | TypeKind::FloatLiteral(_) | TypeKind::Pointer(_) @@ -290,7 +319,7 @@ impl TypeKind { | TypeKind::AnonymousUnion(..) | TypeKind::FixedArray(..) | TypeKind::FunctionPointer(..) - | TypeKind::Enum(_) + | TypeKind::Enum(_, _) | TypeKind::AnonymousEnum(_) => None, } } @@ -303,6 +332,8 @@ impl TypeKind { impl Display for TypeKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + TypeKind::Unresolved => panic!(), + TypeKind::TypeAlias(_, _type_ref) => todo!(), TypeKind::Boolean => { write!(f, "bool")?; } @@ -330,10 +361,10 @@ impl Display for TypeKind { }, TypeKind::FloatLiteral(value) => write!(f, "float {}", value)?, TypeKind::Pointer(inner) => { - write!(f, "ptr<{}>", inner.kind)?; + write!(f, "ptr<{}>", **inner)?; } TypeKind::Void => f.write_str("void")?, - TypeKind::Structure(name, _) => write!(f, "{}", name.plain())?, + TypeKind::Structure(name, _) => write!(f, "{}", name)?, TypeKind::AnonymousStruct() => f.write_str("(anonymous struct)")?, TypeKind::AnonymousUnion() => f.write_str("(anonymous union)")?, TypeKind::AnonymousEnum(..) => f.write_str("(anonymous enum)")?, @@ -341,7 +372,7 @@ impl Display for TypeKind { write!(f, "array<{}, {}>", fixed_array.size, fixed_array.inner.kind)?; } TypeKind::FunctionPointer(..) => f.write_str("(function pointer type)")?, - TypeKind::Enum(enum_name) => write!(f, "(enum) {}", enum_name.plain())?, + TypeKind::Enum(_, type_ref) => write!(f, "(enum) {:?}", type_ref)?, } Ok(()) diff --git a/src/resolved/new_type_resolution.rs b/src/resolved/new_type_resolution.rs deleted file mode 100644 index a1ae935..0000000 --- a/src/resolved/new_type_resolution.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::{ - AnonymousEnum, CInteger, FixedArray, FloatSize, FunctionPointer, IntegerBits, IntegerSign, - Privacy, StructureRef, -}; -use crate::source_files::Source; -use derive_more::{IsVariant, Unwrap}; -use num::BigInt; -use slotmap::new_key_type; - -new_key_type! { - pub struct TypeRef; -} - -#[derive(Clone, Debug)] -pub struct Type { - pub value: TypeRef, - pub source: Source, -} - -#[derive(Clone, Debug)] -pub struct TypeDecl { - pub kind: TypeKind, - pub source: Source, - pub privacy: Privacy, -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct HumanName(pub String); - -#[derive(Clone, Debug, PartialEq, IsVariant, Unwrap)] -pub enum TypeKind { - Unresolved, - Boolean, - Integer(IntegerBits, IntegerSign), - CInteger(CInteger, Option), - IntegerLiteral(BigInt), - FloatLiteral(f64), - Floating(FloatSize), - Pointer(Box), - Void, - AnonymousStruct(), - AnonymousUnion(), - AnonymousEnum(AnonymousEnum), - FixedArray(Box), - FunctionPointer(FunctionPointer), - Enum(HumanName, Option), - Structure(HumanName, StructureRef), - TypeAlias(HumanName, TypeRef), -} From 2b0d268a1250c71fa06559ed7631261c2062b455 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Fri, 11 Oct 2024 23:20:15 -0500 Subject: [PATCH 09/14] Continued working on new type resolution system and got simple local types resolving --- src/resolve/expr/call.rs | 13 +- src/resolve/expr/mod.rs | 25 +- src/resolve/global_search_ctx.rs | 2 +- src/resolve/mod.rs | 423 ++++++++++++++++++------------- src/resolve/stmt.rs | 13 +- src/resolve/type_search_ctx.rs | 88 ------- 6 files changed, 275 insertions(+), 289 deletions(-) delete mode 100644 src/resolve/type_search_ctx.rs diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index eb2fbd5..cfc7df6 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -4,7 +4,7 @@ use crate::{ resolve::{ conform::{conform_expr, to_default::conform_expr_to_default, ConformMode, Perform}, error::{ResolveError, ResolveErrorKind}, - resolve_type, Initialized, + Initialized, ResolveTypeCtx, }, resolved::{self, TypedExpr}, source_files::Source, @@ -91,12 +91,13 @@ pub fn resolve_call_expr( } if let Some(required_ty) = &call.expected_to_return { - let resolved_required_ty = resolve_type( - ctx.resolved_ast, + let type_ctx = ResolveTypeCtx::new( + &ctx.resolved_ast, ctx.module_fs_node_id, - required_ty, - &mut Default::default(), - )?; + ctx.types_in_modules, + ); + + let resolved_required_ty = type_ctx.resolve(required_ty)?; if resolved_required_ty != return_type { return Err(ResolveErrorKind::FunctionMustReturnType { diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index e55568c..7e82106 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -21,7 +21,7 @@ use super::{ function_search_ctx::FunctionSearchCtx, global_search_ctx::GlobalSearchCtx, variable_search_ctx::VariableSearchCtx, - Initialized, + Initialized, ResolveTypeCtx, }; use crate::{ ast::{ @@ -37,7 +37,7 @@ use crate::{ struct_literal::resolve_struct_literal_expr, unary_operation::resolve_unary_math_operation_expr, variable::resolve_variable_expr, }, - resolve_stmts, resolve_type, + resolve_stmts, }, resolved::{self, Expr, ExprKind, FunctionRef, StructureRef, TypeKind, TypedExpr}, workspace::fs::FsNodeId, @@ -57,6 +57,7 @@ pub struct ResolveExprCtx<'a, 'b> { pub helper_exprs: &'b IndexMap, pub settings: &'b Settings, pub public_functions: &'b HashMap>>, + pub types_in_modules: &'b HashMap>, pub module_fs_node_id: FsNodeId, } @@ -390,22 +391,22 @@ pub fn resolve_expr( result_type, } = &**info; - let resolved_type = resolve_type( - ctx.resolved_ast, + let resolved_type = ResolveTypeCtx::new( + &ctx.resolved_ast, ctx.module_fs_node_id, - result_type, - &mut Default::default(), - )?; + ctx.types_in_modules, + ) + .resolve(result_type)?; let mut resolved_args = Vec::with_capacity(args.len()); for (expected_arg_type, arg) in args { - let preferred_type = resolve_type( - ctx.resolved_ast, + let type_ctx = ResolveTypeCtx::new( + &ctx.resolved_ast, ctx.module_fs_node_id, - expected_arg_type, - &mut Default::default(), - )?; + ctx.types_in_modules, + ); + let preferred_type = type_ctx.resolve(expected_arg_type)?; resolved_args.push( resolve_expr( diff --git a/src/resolve/global_search_ctx.rs b/src/resolve/global_search_ctx.rs index 02918ac..0a5f5d8 100644 --- a/src/resolve/global_search_ctx.rs +++ b/src/resolve/global_search_ctx.rs @@ -7,7 +7,7 @@ use crate::{ }; use std::collections::HashMap; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct GlobalSearchCtx { globals: HashMap, } diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index d4541c1..e7efcee 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -6,7 +6,6 @@ mod expr; mod function_search_ctx; mod global_search_ctx; mod stmt; -mod type_search_ctx; mod unify_types; mod variable_search_ctx; @@ -33,10 +32,9 @@ use ast::{IntegerBits, IntegerSign}; use function_search_ctx::FunctionSearchCtx; use indexmap::IndexMap; use std::{ - borrow::Borrow, + borrow::{Borrow, Cow}, collections::{HashMap, HashSet, VecDeque}, }; -use type_search_ctx::find_type; enum Job { Regular(FsNodeId, usize, resolved::FunctionRef), @@ -48,6 +46,7 @@ struct ResolveCtx<'a> { pub global_search_ctxs: IndexMap, pub helper_exprs: IndexMap, pub public_functions: HashMap>>, + pub types_in_modules: HashMap>, } impl<'a> ResolveCtx<'a> { @@ -58,6 +57,7 @@ impl<'a> ResolveCtx<'a> { global_search_ctxs: Default::default(), helper_exprs, public_functions: HashMap::new(), + types_in_modules: HashMap::new(), } } } @@ -123,8 +123,6 @@ pub fn resolve<'a>( enums: HashMap::with_capacity(file.enums.len()), }; - let decls = resolved_ast.types_per_module.entry(file_id).or_default(); - for structure in file.structures.iter() { let privacy = structure.privacy; let source = structure.source; @@ -147,10 +145,15 @@ pub fn resolve<'a>( continue; }; - decls.insert( + let types_in_module = ctx + .types_in_modules + .entry(file_id) + .or_insert_with(HashMap::new); + + types_in_module.insert( name.to_string(), TypeDecl { - kind: struct_type_kind.clone(), + kind: struct_type_kind, source, privacy, }, @@ -169,7 +172,12 @@ pub fn resolve<'a>( let source = definition.source; let privacy = definition.privacy; - decls.insert( + let types_in_module = ctx + .types_in_modules + .entry(file_id) + .or_insert_with(HashMap::new); + + types_in_module.insert( name.to_string(), TypeDecl { kind, @@ -189,9 +197,12 @@ pub fn resolve<'a>( let becomes_type = resolved_ast.all_types.insert(TypeKind::Unresolved); let kind = TypeKind::TypeAlias(HumanName(name.to_string()), becomes_type); - job.type_aliases.insert(name, becomes_type); + let types_in_module = ctx + .types_in_modules + .entry(file_id) + .or_insert_with(HashMap::new); - decls.insert( + types_in_module.insert( name.to_string(), TypeDecl { kind, @@ -199,6 +210,8 @@ pub fn resolve<'a>( privacy, }, ); + + job.type_aliases.insert(name, becomes_type); } type_jobs.push(job); @@ -218,17 +231,15 @@ pub fn resolve<'a>( let types = resolved_ast .types_per_module - .get(&module_file_id) - .expect("valid module"); + .entry(module_file_id) + .or_default(); for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) { for (field_name, field) in structure.fields.iter() { - let resolved_type = resolve_type_or_undeclared( - &resolved_ast, - module_file_id, - &field.ast_type, - &mut Default::default(), - )?; + let type_ctx = + ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + + let resolved_type = type_ctx.resolve_or_undeclared(&field.ast_type)?; let resolved_struct = resolved_ast .structures @@ -259,23 +270,20 @@ pub fn resolve<'a>( // Resolve global variables for (physical_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace + let module_file_id = ast_workspace .get_owning_module(*physical_file_id) .unwrap_or(*physical_file_id); - let global_search_context = ctx - .global_search_ctxs - .get_or_insert_with(file_id, || GlobalSearchCtx::new()); - for global in file.global_variables.iter() { - let resolved_type = resolve_type( - &resolved_ast, - file_id, - &global.ast_type, - &mut Default::default(), - )?; + let type_ctx = + ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + let resolved_type = type_ctx.resolve(&global.ast_type)?; + + let global_search_context = ctx + .global_search_ctxs + .get_or_insert_with(module_file_id, || GlobalSearchCtx::new()); - let resolved_name = ResolvedName::new(file_id, &global.name); + let resolved_name = ResolvedName::new(module_file_id, &global.name); let global_ref = resolved_ast.globals.insert(resolved::GlobalVar { name: resolved_name.clone(), @@ -291,22 +299,21 @@ pub fn resolve<'a>( // Create initial function jobs for (physical_file_id, file) in ast_workspace.files.iter() { - let file_id = ast_workspace + let module_file_id = ast_workspace .get_owning_module(*physical_file_id) .unwrap_or(*physical_file_id); for (function_i, function) in file.functions.iter().enumerate() { - let name = ResolvedName::new(file_id, &function.name); + let name = ResolvedName::new(module_file_id, &function.name); + let type_ctx = + ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + let parameters = resolve_parameters(&type_ctx, &function.parameters)?; + let return_type = type_ctx.resolve(&function.return_type)?; let function_ref = resolved_ast.functions.insert(resolved::Function { name: name.clone(), - parameters: resolve_parameters(&resolved_ast, file_id, &function.parameters)?, - return_type: resolve_type( - &resolved_ast, - file_id, - &function.return_type, - &mut Default::default(), - )?, + parameters, + return_type, stmts: vec![], is_foreign: function.is_foreign, variables: VariableStorage::new(), @@ -327,7 +334,7 @@ pub fn resolve<'a>( if function.privacy.is_public() { let public_of_module = ctx .public_functions - .entry(file_id) + .entry(module_file_id) .or_insert_with(HashMap::new); // TODO: Add proper error message @@ -350,14 +357,15 @@ pub fn resolve<'a>( let imported_namespaces = settings.map(|settings| &settings.imported_namespaces); let function_search_context = - ctx.function_search_ctxs.get_or_insert_with(file_id, || { - FunctionSearchCtx::new( - imported_namespaces - .map(|namespaces| namespaces.clone()) - .unwrap_or_else(|| vec![]), - file_id, - ) - }); + ctx.function_search_ctxs + .get_or_insert_with(module_file_id, || { + FunctionSearchCtx::new( + imported_namespaces + .map(|namespaces| namespaces.clone()) + .unwrap_or_else(|| vec![]), + module_file_id, + ) + }); function_search_context .available @@ -371,19 +379,17 @@ pub fn resolve<'a>( while let Some(job) = ctx.jobs.pop_front() { match job { Job::Regular(real_file_id, function_index, resolved_function_ref) => { - let file_id = ast_workspace + let module_file_id = ast_workspace .get_owning_module(real_file_id) .unwrap_or(real_file_id); + // NOTE: This module should already have a function search context let function_search_ctx = ctx .function_search_ctxs - .get(&file_id) + .get(&module_file_id) .expect("function search context to exist for file"); - let global_search_ctx = ctx - .global_search_ctxs - .get(&file_id) - .expect("global search context to exist for file"); + let global_search_ctx = &*ctx.global_search_ctxs.entry(module_file_id).or_default(); let ast_file = ast_workspace .files @@ -399,12 +405,13 @@ pub fn resolve<'a>( { for parameter in ast_function.parameters.required.iter() { - let resolved_type = resolve_type( + let type_ctx = ResolveTypeCtx::new( &resolved_ast, - file_id, - ¶meter.ast_type, - &mut Default::default(), - )?; + module_file_id, + &ctx.types_in_modules, + ); + + let resolved_type = type_ctx.resolve(¶meter.ast_type)?; let function = resolved_ast .functions @@ -438,7 +445,8 @@ pub fn resolve<'a>( helper_exprs: &ctx.helper_exprs, settings, public_functions: &ctx.public_functions, - module_fs_node_id: file_id, + types_in_modules: &ctx.types_in_modules, + module_fs_node_id: module_file_id, }; resolve_stmts(&mut ctx, &ast_function.stmts)? @@ -463,130 +471,200 @@ enum Initialized { AllowUninitialized, } -fn resolve_type_or_undeclared<'a>( - resolved_ast: &resolved::Ast, +#[derive(Debug)] +pub struct ResolveTypeCtx<'a> { + resolved_ast: &'a resolved::Ast<'a>, module_fs_node_id: FsNodeId, - ast_type: &'a ast::Type, - used_aliases_stack: &mut HashSet, -) -> Result { - match resolve_type( - resolved_ast, - module_fs_node_id, - ast_type, - used_aliases_stack, - ) { - Ok(inner) => Ok(inner), - Err(_) if ast_type.kind.allow_indirect_undefined() => { - Ok(resolved::TypeKind::Void.at(ast_type.source)) - } - Err(err) => Err(err), - } + types_in_modules: &'a HashMap>, + used_aliases_stack: HashSet, } -fn resolve_type<'a>( - resolved_ast: &resolved::Ast, - module_fs_node_id: FsNodeId, - ast_type: &'a ast::Type, - used_aliases_stack: &mut HashSet, -) -> Result { - match &ast_type.kind { - ast::TypeKind::Boolean => Ok(resolved::TypeKind::Boolean), - ast::TypeKind::Integer(bits, sign) => Ok(resolved::TypeKind::Integer(*bits, *sign)), - ast::TypeKind::CInteger(integer, sign) => Ok(resolved::TypeKind::CInteger(*integer, *sign)), - ast::TypeKind::Pointer(inner) => { - let inner = resolve_type_or_undeclared( - resolved_ast, - module_fs_node_id, - inner, - used_aliases_stack, - )?; - - Ok(resolved::TypeKind::Pointer(Box::new(inner))) +impl<'a> ResolveTypeCtx<'a> { + pub fn new( + resolved_ast: &'a resolved::Ast, + module_fs_node_id: FsNodeId, + public_types: &'a HashMap>, + ) -> Self { + Self { + resolved_ast, + module_fs_node_id, + types_in_modules: public_types, + used_aliases_stack: Default::default(), } - ast::TypeKind::Void => Ok(resolved::TypeKind::Void), - ast::TypeKind::Named(name) => match find_type(resolved_ast, module_fs_node_id, name) { - Ok(found) => Ok(found.into_owned()), - Err(err) => Err(err.into_resolve_error(name, ast_type.source)), - }, - ast::TypeKind::Floating(size) => Ok(resolved::TypeKind::Floating(*size)), - ast::TypeKind::AnonymousStruct(..) => todo!("resolve anonymous struct type"), - ast::TypeKind::AnonymousUnion(..) => todo!("resolve anonymous union type"), - ast::TypeKind::AnonymousEnum(anonymous_enum) => { - let resolved_type = Box::new(resolve_enum_backing_type( - resolved_ast, - module_fs_node_id, - anonymous_enum.backing_type.as_deref(), - &mut Default::default(), - ast_type.source, - )?); - - let members = anonymous_enum.members.clone(); - - Ok(resolved::TypeKind::AnonymousEnum(resolved::AnonymousEnum { - resolved_type, - source: ast_type.source, - members, - })) + } + + pub fn resolve_or_undeclared( + &self, + ast_type: &'a ast::Type, + ) -> Result { + match self.resolve(ast_type) { + Ok(inner) => Ok(inner), + Err(_) if ast_type.kind.allow_indirect_undefined() => { + Ok(resolved::TypeKind::Void.at(ast_type.source)) + } + Err(err) => Err(err), } - ast::TypeKind::FixedArray(fixed_array) => { - if let ast::ExprKind::Integer(integer) = &fixed_array.count.kind { - if let Ok(size) = integer.value().try_into() { - let inner = resolve_type( - resolved_ast, - module_fs_node_id, - &fixed_array.ast_type, - used_aliases_stack, - )?; - - Ok(resolved::TypeKind::FixedArray(Box::new( - resolved::FixedArray { size, inner }, - ))) + } + + pub fn resolve(&self, ast_type: &'a ast::Type) -> Result { + match &ast_type.kind { + ast::TypeKind::Boolean => Ok(resolved::TypeKind::Boolean), + ast::TypeKind::Integer(bits, sign) => Ok(resolved::TypeKind::Integer(*bits, *sign)), + ast::TypeKind::CInteger(integer, sign) => { + Ok(resolved::TypeKind::CInteger(*integer, *sign)) + } + ast::TypeKind::Pointer(inner) => { + let inner = self.resolve_or_undeclared(inner)?; + Ok(resolved::TypeKind::Pointer(Box::new(inner))) + } + ast::TypeKind::Void => Ok(resolved::TypeKind::Void), + ast::TypeKind::Named(name) => match self.find_type(name) { + Ok(found) => Ok(found.into_owned()), + Err(err) => Err(err.into_resolve_error(name, ast_type.source)), + }, + ast::TypeKind::Floating(size) => Ok(resolved::TypeKind::Floating(*size)), + ast::TypeKind::AnonymousStruct(..) => todo!("resolve anonymous struct type"), + ast::TypeKind::AnonymousUnion(..) => todo!("resolve anonymous union type"), + ast::TypeKind::AnonymousEnum(anonymous_enum) => { + let resolved_type = Box::new(resolve_enum_backing_type( + self, + anonymous_enum.backing_type.as_deref(), + ast_type.source, + )?); + + let members = anonymous_enum.members.clone(); + + Ok(resolved::TypeKind::AnonymousEnum(resolved::AnonymousEnum { + resolved_type, + source: ast_type.source, + members, + })) + } + ast::TypeKind::FixedArray(fixed_array) => { + if let ast::ExprKind::Integer(integer) = &fixed_array.count.kind { + if let Ok(size) = integer.value().try_into() { + let inner = self.resolve(&fixed_array.ast_type)?; + + Ok(resolved::TypeKind::FixedArray(Box::new( + resolved::FixedArray { size, inner }, + ))) + } else { + Err(ResolveErrorKind::ArraySizeTooLarge.at(fixed_array.count.source)) + } } else { - Err(ResolveErrorKind::ArraySizeTooLarge.at(fixed_array.count.source)) + todo!("resolve fixed array type with variable size") } - } else { - todo!("resolve fixed array type with variable size") + } + ast::TypeKind::FunctionPointer(function_pointer) => { + let mut parameters = Vec::with_capacity(function_pointer.parameters.len()); + + for parameter in function_pointer.parameters.iter() { + let resolved_type = self.resolve(¶meter.ast_type)?; + + parameters.push(resolved::Parameter { + name: parameter.name.clone(), + resolved_type, + }); + } + + let return_type = Box::new(self.resolve(&function_pointer.return_type)?); + + Ok(resolved::TypeKind::FunctionPointer( + resolved::FunctionPointer { + parameters, + return_type, + is_cstyle_variadic: function_pointer.is_cstyle_variadic, + }, + )) } } - ast::TypeKind::FunctionPointer(function_pointer) => { - let mut parameters = Vec::with_capacity(function_pointer.parameters.len()); - - for parameter in function_pointer.parameters.iter() { - let resolved_type = resolve_type( - resolved_ast, - module_fs_node_id, - ¶meter.ast_type, - used_aliases_stack, - )?; + .map(|kind| kind.at(ast_type.source)) + } - parameters.push(resolved::Parameter { - name: parameter.name.clone(), - resolved_type, + pub fn find_type(&self, name: &Name) -> Result, FindTypeError> { + let _source_files = self.resolved_ast.source_files; + let _settings = self + .resolved_ast + .workspace + .get_settings_for_module(self.module_fs_node_id); + let _all_types = &self.resolved_ast.all_types; + + if let Some(name) = name.as_plain_str() { + if let Some(types_in_modules) = self.types_in_modules.get(&self.module_fs_node_id) { + if let Some(decl) = types_in_modules.get(name) { + return Ok(Cow::Borrowed(&decl.kind)); + } + } + } + + todo!("TypeSearchCtx find_type - {:?}", name); + + /* + let resolved_name = ResolvedName::new(self.fs_node_id, name); + + if let Some(mapping) = self.types.get(&resolved_name) { + return self.resolve_mapping(&resolved_name, mapping, used_aliases_stack); + } + + if name.namespace.is_empty() { + let mut matches = self + .settings + .imported_namespaces + .iter() + .filter_map(|namespace| { + let resolved_name = ResolvedName::new( + self.fs_node_id, + &Name::new(Some(namespace.clone()), name.basename.clone()), + ); + self.types.get(&resolved_name) }); + + if let Some(found) = matches.next() { + if matches.next().is_some() { + return Err(FindTypeError::Ambiguous); + } else { + return self.resolve_mapping(&resolved_name, found, used_aliases_stack); + } } + } + */ - let return_type = Box::new(resolve_type( - resolved_ast, - module_fs_node_id, - &function_pointer.return_type, - used_aliases_stack, - )?); - - Ok(resolved::TypeKind::FunctionPointer( - resolved::FunctionPointer { - parameters, - return_type, - is_cstyle_variadic: function_pointer.is_cstyle_variadic, - }, - )) + Err(FindTypeError::NotDefined) + } +} + +#[derive(Clone, Debug)] +pub enum FindTypeError { + NotDefined, + Ambiguous, + RecursiveAlias(ResolvedName), + ResolveError(ResolveError), +} + +impl FindTypeError { + pub fn into_resolve_error(self: FindTypeError, name: &Name, source: Source) -> ResolveError { + let name = name.to_string(); + + match self { + FindTypeError::NotDefined => ResolveErrorKind::UndeclaredType { + name: name.to_string(), + } + .at(source), + FindTypeError::Ambiguous => ResolveErrorKind::AmbiguousType { + name: name.to_string(), + } + .at(source), + FindTypeError::RecursiveAlias(_) => ResolveErrorKind::RecursiveTypeAlias { + name: name.to_string(), + } + .at(source), + FindTypeError::ResolveError(err) => err, } } - .map(|kind| kind.at(ast_type.source)) } fn resolve_parameters( - resolved_ast: &resolved::Ast, - module_fs_node_id: FsNodeId, + type_ctx: &ResolveTypeCtx, parameters: &ast::Parameters, ) -> Result { let mut required = Vec::with_capacity(parameters.required.len()); @@ -594,12 +672,7 @@ fn resolve_parameters( for parameter in parameters.required.iter() { required.push(resolved::Parameter { name: parameter.name.clone(), - resolved_type: resolve_type( - resolved_ast, - module_fs_node_id, - ¶meter.ast_type, - &mut Default::default(), - )?, + resolved_type: type_ctx.resolve(¶meter.ast_type)?, }); } @@ -629,14 +702,12 @@ fn ensure_initialized( } fn resolve_enum_backing_type( - resolved_ast: &resolved::Ast, - module_fs_node_id: FsNodeId, + ctx: &ResolveTypeCtx, backing_type: Option>, - used_aliases: &mut HashSet, source: Source, ) -> Result { if let Some(backing_type) = backing_type.as_ref().map(Borrow::borrow) { - resolve_type(resolved_ast, module_fs_node_id, backing_type, used_aliases) + ctx.resolve(backing_type) } else { Ok(resolved::TypeKind::Integer(IntegerBits::Bits64, IntegerSign::Unsigned).at(source)) } diff --git a/src/resolve/stmt.rs b/src/resolve/stmt.rs index 679535b..d7104fa 100644 --- a/src/resolve/stmt.rs +++ b/src/resolve/stmt.rs @@ -3,7 +3,7 @@ use super::{ destination::resolve_expr_to_destination, error::{ResolveError, ResolveErrorKind}, expr::{resolve_basic_binary_operator, resolve_expr, PreferredType, ResolveExprCtx}, - resolve_type, Initialized, + Initialized, ResolveTypeCtx, }; use crate::{ast, resolved}; @@ -85,12 +85,13 @@ pub fn resolve_stmt( source, )), ast::StmtKind::Declaration(declaration) => { - let resolved_type = resolve_type( - ctx.resolved_ast, + let type_ctx = ResolveTypeCtx::new( + &ctx.resolved_ast, ctx.module_fs_node_id, - &declaration.ast_type, - &mut Default::default(), - )?; + ctx.types_in_modules, + ); + + let resolved_type = type_ctx.resolve(&declaration.ast_type)?; let value = declaration .initial_value diff --git a/src/resolve/type_search_ctx.rs b/src/resolve/type_search_ctx.rs deleted file mode 100644 index 600ab72..0000000 --- a/src/resolve/type_search_ctx.rs +++ /dev/null @@ -1,88 +0,0 @@ -use super::error::{ResolveError, ResolveErrorKind}; -use crate::{ - name::{Name, ResolvedName}, - resolved, - source_files::Source, - workspace::fs::FsNodeId, -}; -use std::borrow::Cow; - -pub fn find_type<'a>( - resolved_ast: &'a resolved::Ast, - module_node_id: FsNodeId, - name: &Name, -) -> Result, FindTypeError> { - let _source_files = resolved_ast.source_files; - let _settings = resolved_ast - .workspace - .get_settings_for_module(module_node_id); - let _all_types = &resolved_ast.all_types; - - if let Some(_name) = name.as_plain_str() { - todo!("TypeSearchCtx find_type for local type"); - } - - todo!("TypeSearchCtx find_type"); - - /* - let resolved_name = ResolvedName::new(self.fs_node_id, name); - - if let Some(mapping) = self.types.get(&resolved_name) { - return self.resolve_mapping(&resolved_name, mapping, used_aliases_stack); - } - - if name.namespace.is_empty() { - let mut matches = self - .settings - .imported_namespaces - .iter() - .filter_map(|namespace| { - let resolved_name = ResolvedName::new( - self.fs_node_id, - &Name::new(Some(namespace.clone()), name.basename.clone()), - ); - self.types.get(&resolved_name) - }); - - if let Some(found) = matches.next() { - if matches.next().is_some() { - return Err(FindTypeError::Ambiguous); - } else { - return self.resolve_mapping(&resolved_name, found, used_aliases_stack); - } - } - } - */ - - Err(FindTypeError::NotDefined) -} - -#[derive(Clone, Debug)] -pub enum FindTypeError { - NotDefined, - Ambiguous, - RecursiveAlias(ResolvedName), - ResolveError(ResolveError), -} - -impl FindTypeError { - pub fn into_resolve_error(self: FindTypeError, name: &Name, source: Source) -> ResolveError { - let name = name.to_string(); - - match self { - FindTypeError::NotDefined => ResolveErrorKind::UndeclaredType { - name: name.to_string(), - } - .at(source), - FindTypeError::Ambiguous => ResolveErrorKind::AmbiguousType { - name: name.to_string(), - } - .at(source), - FindTypeError::RecursiveAlias(_) => ResolveErrorKind::RecursiveTypeAlias { - name: name.to_string(), - } - .at(source), - FindTypeError::ResolveError(err) => err, - } - } -} From 6dad6c4778d3f9bbda7acd882f8295ffdb6f4af6 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Sat, 12 Oct 2024 23:09:56 -0500 Subject: [PATCH 10/14] Got basic type resolution across imported modules working --- src/ast/enumeration.rs | 1 + src/ast/file.rs | 4 +- src/ast/workspace/mod.rs | 5 - src/interpreter_env/mod.rs | 46 +++++---- src/lower/mod.rs | 30 ++---- src/parser/parse_enum.rs | 21 ++--- src/parser/parse_top_level.rs | 16 +--- src/resolve/core_structure_info.rs | 15 +-- src/resolve/expr/call.rs | 10 +- src/resolve/expr/mod.rs | 20 ++-- src/resolve/expr/struct_literal.rs | 33 ++++--- src/resolve/mod.rs | 147 ++++++++++++++++++----------- src/resolve/stmt.rs | 10 +- src/resolved/mod.rs | 12 ++- 14 files changed, 180 insertions(+), 190 deletions(-) diff --git a/src/ast/enumeration.rs b/src/ast/enumeration.rs index f384b0e..36221f4 100644 --- a/src/ast/enumeration.rs +++ b/src/ast/enumeration.rs @@ -5,6 +5,7 @@ use num::BigInt; #[derive(Clone, Debug)] pub struct Enum { + pub name: String, pub backing_type: Option, pub source: Source, pub members: IndexMap, diff --git a/src/ast/file.rs b/src/ast/file.rs index dafd8e5..dd506bd 100644 --- a/src/ast/file.rs +++ b/src/ast/file.rs @@ -11,7 +11,7 @@ pub struct AstFile { pub structures: Vec, pub type_aliases: IndexMap, pub global_variables: Vec, - pub enums: IndexMap, + pub enums: Vec, pub helper_exprs: IndexMap, pub settings: Option, } @@ -23,7 +23,7 @@ impl AstFile { structures: vec![], type_aliases: IndexMap::default(), global_variables: vec![], - enums: IndexMap::default(), + enums: vec![], helper_exprs: IndexMap::default(), settings: None, } diff --git a/src/ast/workspace/mod.rs b/src/ast/workspace/mod.rs index db8ed6d..23d62a6 100644 --- a/src/ast/workspace/mod.rs +++ b/src/ast/workspace/mod.rs @@ -70,11 +70,6 @@ impl<'a> AstWorkspace<'a> { None } - pub fn get_settings_for_module(&self, module_node_id: FsNodeId) -> &Settings { - let file = self.files.get(&module_node_id).expect("valid module id"); - &self.settings[file.settings.unwrap_or_default().0] - } - pub fn get_mut(&mut self, id: FsNodeId) -> Option<&mut AstFile> { self.files.get_mut(&id) } diff --git a/src/interpreter_env/mod.rs b/src/interpreter_env/mod.rs index dfc25c1..4f5843d 100644 --- a/src/interpreter_env/mod.rs +++ b/src/interpreter_env/mod.rs @@ -106,30 +106,28 @@ pub fn setup_build_system_interpreter_symbols(file: &mut AstFile) { privacy: Privacy::Public, }); - file.enums.insert( - Name::plain("ProjectKind"), - Enum { - backing_type: Some(TypeKind::u64().at(source)), - source, - members: IndexMap::from_iter([ - ( - "ConsoleApp".into(), - EnumMember { - value: (ProjectKind::ConsoleApp as u64).into(), - explicit_value: true, - }, - ), - ( - "WindowedApp".into(), - EnumMember { - value: (ProjectKind::WindowedApp as u64).into(), - explicit_value: true, - }, - ), - ]), - privacy: Privacy::Private, - }, - ); + file.enums.push(Enum { + name: "ProjectKind".into(), + backing_type: Some(TypeKind::u64().at(source)), + source, + members: IndexMap::from_iter([ + ( + "ConsoleApp".into(), + EnumMember { + value: (ProjectKind::ConsoleApp as u64).into(), + explicit_value: true, + }, + ), + ( + "WindowedApp".into(), + EnumMember { + value: (ProjectKind::WindowedApp as u64).into(), + explicit_value: true, + }, + ), + ]), + privacy: Privacy::Private, + }); file.structures.push(Structure { name: Name::plain("Project"), diff --git a/src/lower/mod.rs b/src/lower/mod.rs index 39f89ff..d1be87c 100644 --- a/src/lower/mod.rs +++ b/src/lower/mod.rs @@ -347,8 +347,10 @@ fn lower_type( use resolved::{IntegerBits as Bits, IntegerSign as Sign}; match &resolved_type.kind { - resolved::TypeKind::Unresolved => panic!(), - resolved::TypeKind::TypeAlias(_, _) => todo!("lower type ref"), + resolved::TypeKind::Unresolved => panic!("got unresolved type during lower_type!"), + resolved::TypeKind::TypeAlias(_, _) => { + todo!("lower type ref for aliases not supported yet") + } resolved::TypeKind::Boolean => Ok(ir::Type::Boolean), resolved::TypeKind::Integer(bits, sign) => Ok(match (bits, sign) { (Bits::Bits8, Sign::Signed) => ir::Type::S8, @@ -403,16 +405,13 @@ fn lower_type( }))) } resolved::TypeKind::FunctionPointer(_function_pointer) => Ok(ir::Type::FunctionPointer), - resolved::TypeKind::Enum(_, _enum_name) => { - todo!("lower enum type"); - /* + resolved::TypeKind::Enum(_human_name, enum_ref) => { let enum_definition = resolved_ast .enums - .get(enum_name) + .get(*enum_ref) .expect("referenced enum to exist"); lower_type(target, &enum_definition.resolved_type, resolved_ast) - */ } } } @@ -899,7 +898,7 @@ fn lower_expr( ExprKind::EnumMemberLiteral(enum_member_literal) => { let enum_definition = resolved_ast .enums - .get(&enum_member_literal.enum_name) + .get(enum_member_literal.enum_ref) .expect("referenced enum to exist for enum member literal"); let member = enum_definition @@ -907,10 +906,7 @@ fn lower_expr( .get(&enum_member_literal.variant_name) .ok_or_else(|| { LowerErrorKind::NoSuchEnumMember { - enum_name: enum_member_literal - .enum_name - .display(&resolved_ast.workspace.fs) - .to_string(), + enum_name: enum_member_literal.human_name.to_string(), variant_name: enum_member_literal.variant_name.clone(), } .at(enum_member_literal.source) @@ -927,10 +923,7 @@ fn lower_expr( let make_error = |_| { LowerErrorKind::CannotFit { value: value.to_string(), - expected_type: enum_member_literal - .enum_name - .display(&resolved_ast.workspace.fs) - .to_string(), + expected_type: enum_member_literal.human_name.to_string(), } .at(enum_definition.source) }; @@ -962,10 +955,7 @@ fn lower_expr( } _ => { return Err(LowerErrorKind::EnumBackingTypeMustBeInteger { - enum_name: enum_member_literal - .enum_name - .display(&resolved_ast.workspace.fs) - .to_string(), + enum_name: enum_member_literal.human_name.to_string(), } .at(enum_definition.source)) } diff --git a/src/parser/parse_enum.rs b/src/parser/parse_enum.rs index a558e45..8bb2a45 100644 --- a/src/parser/parse_enum.rs +++ b/src/parser/parse_enum.rs @@ -1,8 +1,7 @@ use super::{annotation::Annotation, error::ParseError, Parser}; use crate::{ - ast::{Enum, EnumMember, Named, Privacy}, + ast::{Enum, EnumMember, Privacy}, inflow::Inflow, - name::Name, parser::annotation::AnnotationKind, token::{Token, TokenKind}, }; @@ -10,18 +9,16 @@ use indexmap::IndexMap; use num::{BigInt, Zero}; impl<'a, I: Inflow> Parser<'a, I> { - pub fn parse_enum(&mut self, annotations: Vec) -> Result, ParseError> { + pub fn parse_enum(&mut self, annotations: Vec) -> Result { let source = self.source_here(); assert!(self.input.advance().is_enum_keyword()); let mut privacy = Privacy::Private; - let mut namespace = None; let name = self.parse_identifier(Some("for enum name after 'enum' keyword"))?; self.ignore_newlines(); for annotation in annotations { match annotation.kind { - AnnotationKind::Namespace(new_namespace) => namespace = Some(new_namespace), AnnotationKind::Public => privacy = Privacy::Public, _ => return Err(self.unexpected_annotation(&annotation, Some("for enum"))), } @@ -58,14 +55,12 @@ impl<'a, I: Inflow> Parser<'a, I> { self.parse_token(TokenKind::CloseParen, Some("to close enum body"))?; - Ok(Named:: { - name: Name::new(namespace, name), - value: Enum { - backing_type: None, - members, - source, - privacy, - }, + Ok(Enum { + name, + backing_type: None, + members, + source, + privacy, }) } } diff --git a/src/parser/parse_top_level.rs b/src/parser/parse_top_level.rs index 327bbe8..027c42b 100644 --- a/src/parser/parse_top_level.rs +++ b/src/parser/parse_top_level.rs @@ -4,7 +4,7 @@ use super::{ Parser, }; use crate::{ - ast::{AstFile, Enum, HelperExpr, Named, TypeAlias}, + ast::{AstFile, HelperExpr, Named, TypeAlias}, index_map_ext::IndexMapExt, inflow::Inflow, token::{Token, TokenKind}, @@ -72,19 +72,9 @@ impl<'a, I: Inflow> Parser<'a, I> { })?; } TokenKind::EnumKeyword => { - let Named:: { - name, - value: enum_definition, - } = self.parse_enum(annotations)?; - - let source = enum_definition.source; + let enum_definition = self.parse_enum(annotations)?; - ast_file.enums.try_insert(name, enum_definition, |name| { - ParseErrorKind::EnumHasMultipleDefinitions { - name: name.to_string(), - } - .at(source) - })?; + ast_file.enums.push(enum_definition); } TokenKind::DefineKeyword => { let Named:: { diff --git a/src/resolve/core_structure_info.rs b/src/resolve/core_structure_info.rs index 843a22f..20fce81 100644 --- a/src/resolve/core_structure_info.rs +++ b/src/resolve/core_structure_info.rs @@ -1,17 +1,13 @@ -use super::error::ResolveError; +use super::error::{ResolveError, ResolveErrorKind}; use crate::{ - name::ResolvedName, - resolved::{self, StructureRef}, + resolved::{self, HumanName, StructureRef}, source_files::Source, }; pub fn get_core_structure_info( - _resolved_type: &resolved::Type, - _source: Source, -) -> Result<(&ResolvedName, StructureRef), ResolveError> { - todo!("get_core_structure_info"); - - /* + resolved_type: &resolved::Type, + source: Source, +) -> Result<(&HumanName, StructureRef), ResolveError> { match &resolved_type.kind { resolved::TypeKind::Structure(name, structure_ref) => Ok((name, *structure_ref)), _ => Err(ResolveErrorKind::CannotCreateStructLiteralForNonStructure { @@ -19,5 +15,4 @@ pub fn get_core_structure_info( } .at(source)), } - */ } diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index cfc7df6..e7667b5 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -4,7 +4,7 @@ use crate::{ resolve::{ conform::{conform_expr, to_default::conform_expr_to_default, ConformMode, Perform}, error::{ResolveError, ResolveErrorKind}, - Initialized, ResolveTypeCtx, + Initialized, }, resolved::{self, TypedExpr}, source_files::Source, @@ -91,13 +91,7 @@ pub fn resolve_call_expr( } if let Some(required_ty) = &call.expected_to_return { - let type_ctx = ResolveTypeCtx::new( - &ctx.resolved_ast, - ctx.module_fs_node_id, - ctx.types_in_modules, - ); - - let resolved_required_ty = type_ctx.resolve(required_ty)?; + let resolved_required_ty = ctx.type_ctx().resolve(required_ty)?; if resolved_required_ty != return_type { return Err(ResolveErrorKind::FunctionMustReturnType { diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index 7e82106..5e98510 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -59,9 +59,14 @@ pub struct ResolveExprCtx<'a, 'b> { pub public_functions: &'b HashMap>>, pub types_in_modules: &'b HashMap>, pub module_fs_node_id: FsNodeId, + pub physical_fs_node_id: FsNodeId, } impl<'a, 'b> ResolveExprCtx<'a, 'b> { + pub fn type_ctx<'c>(&'c self) -> ResolveTypeCtx<'c> { + ResolveTypeCtx::from(self) + } + pub fn adept_conform_behavior(&self) -> ConformBehavior { ConformBehavior::Adept(self.c_integer_assumptions()) } @@ -391,22 +396,11 @@ pub fn resolve_expr( result_type, } = &**info; - let resolved_type = ResolveTypeCtx::new( - &ctx.resolved_ast, - ctx.module_fs_node_id, - ctx.types_in_modules, - ) - .resolve(result_type)?; - + let resolved_type = ctx.type_ctx().resolve(result_type)?; let mut resolved_args = Vec::with_capacity(args.len()); for (expected_arg_type, arg) in args { - let type_ctx = ResolveTypeCtx::new( - &ctx.resolved_ast, - ctx.module_fs_node_id, - ctx.types_in_modules, - ); - let preferred_type = type_ctx.resolve(expected_arg_type)?; + let preferred_type = ctx.type_ctx().resolve(expected_arg_type)?; resolved_args.push( resolve_expr( diff --git a/src/resolve/expr/struct_literal.rs b/src/resolve/expr/struct_literal.rs index 5501df6..3492fd2 100644 --- a/src/resolve/expr/struct_literal.rs +++ b/src/resolve/expr/struct_literal.rs @@ -1,10 +1,17 @@ -use super::ResolveExprCtx; +use super::{resolve_expr, PreferredType, ResolveExprCtx}; use crate::{ ast::{self, ConformBehavior, FieldInitializer, FillBehavior}, - resolve::error::ResolveError, - resolved::{self, StructureRef, TypedExpr}, + resolve::{ + conform::{conform_expr, ConformMode, Perform}, + core_structure_info::get_core_structure_info, + error::{ResolveError, ResolveErrorKind}, + Initialized, + }, + resolved::{self, StructLiteral, StructureRef, TypedExpr}, source_files::Source, }; +use indexmap::IndexMap; +use itertools::Itertools; fn get_field_info<'a>( ctx: &'a ResolveExprCtx, @@ -23,17 +30,14 @@ fn get_field_info<'a>( } pub fn resolve_struct_literal_expr( - _ctx: &mut ResolveExprCtx, - _ast_type: &ast::Type, - _fields: &[FieldInitializer], - _fill_behavior: FillBehavior, - _conform_behavior: ConformBehavior, - _source: Source, + ctx: &mut ResolveExprCtx, + ast_type: &ast::Type, + fields: &[FieldInitializer], + fill_behavior: FillBehavior, + conform_behavior: ConformBehavior, + source: Source, ) -> Result { - todo!("resolve_struct_literal_expr"); - - /* - let resolved_type = resolve_type(ctx.type_search_ctx, ast_type, &mut Default::default())?; + let resolved_type = ctx.type_ctx().resolve(ast_type)?; let (struct_name, structure_ref) = get_core_structure_info(&resolved_type, source)?; let structure_type = @@ -113,7 +117,7 @@ pub fn resolve_struct_literal_expr( .is_some() { return Err(ResolveErrorKind::FieldSpecifiedMoreThanOnce { - struct_name: struct_name.display(ctx.resolved_ast.fs).to_string(), + struct_name: struct_name.to_string(), field_name: field_name.to_string(), } .at(ast_type.source)); @@ -166,5 +170,4 @@ pub fn resolve_struct_literal_expr( ast_type.source, ), )) - */ } diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index e7efcee..7f550db 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -22,7 +22,8 @@ use crate::{ index_map_ext::IndexMapExt, name::{Name, ResolvedName}, resolved::{ - self, HumanName, StructureRef, TypeDecl, TypeKind, TypeRef, TypedExpr, VariableStorage, + self, EnumRef, HumanName, StructureRef, TypeDecl, TypeKind, TypeRef, TypedExpr, + VariableStorage, }, source_files::Source, tag::Tag, @@ -105,7 +106,7 @@ pub fn resolve<'a>( physical_file_id: FsNodeId, type_aliases: HashMap<&'a Name, TypeRef>, structures: Vec, - enums: HashMap<&'a Name, TypeRef>, + enums: Vec, } let mut type_jobs = Vec::with_capacity(ast_workspace.files.len()); @@ -120,7 +121,7 @@ pub fn resolve<'a>( physical_file_id: *physical_file_id, type_aliases: HashMap::with_capacity(file.type_aliases.len()), structures: Vec::with_capacity(file.structures.len()), - enums: HashMap::with_capacity(file.enums.len()), + enums: Vec::with_capacity(file.enums.len()), }; for structure in file.structures.iter() { @@ -162,13 +163,14 @@ pub fn resolve<'a>( job.structures.push(structure_ref); } - for (name, definition) in file.enums.iter() { - let backing_type = definition - .backing_type - .is_some() - .then(|| resolved_ast.all_types.insert(TypeKind::Unresolved)); + for definition in file.enums.iter() { + let enum_ref = resolved_ast.enums.insert(resolved::Enum { + resolved_type: TypeKind::Unresolved.at(definition.source), + source: definition.source, + members: definition.members.clone(), + }); - let kind = TypeKind::Enum(HumanName(name.to_string()), backing_type); + let kind = TypeKind::Enum(HumanName(definition.name.to_string()), enum_ref); let source = definition.source; let privacy = definition.privacy; @@ -178,7 +180,7 @@ pub fn resolve<'a>( .or_insert_with(HashMap::new); types_in_module.insert( - name.to_string(), + definition.name.to_string(), TypeDecl { kind, source, @@ -186,9 +188,7 @@ pub fn resolve<'a>( }, ); - if let Some(backing_type) = backing_type { - job.enums.insert(name, backing_type); - } + job.enums.push(enum_ref); } for (name, definition) in file.type_aliases.iter() { @@ -236,8 +236,12 @@ pub fn resolve<'a>( for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) { for (field_name, field) in structure.fields.iter() { - let type_ctx = - ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + let type_ctx = ResolveTypeCtx::new( + &resolved_ast, + module_file_id, + job.physical_file_id, + &ctx.types_in_modules, + ); let resolved_type = type_ctx.resolve_or_undeclared(&field.ast_type)?; @@ -255,12 +259,26 @@ pub fn resolve<'a>( }, ); } - - eprintln!("warning - new type resolution does not handle struct fields yet"); } - for (name, type_ref) in job.enums.iter() { - eprintln!("warning - new type resolution does not handle enum backing types yet"); + for (enum_ref, definition) in job.enums.iter().zip(file.enums.iter()) { + let type_ctx = ResolveTypeCtx::new( + &resolved_ast, + module_file_id, + job.physical_file_id, + &ctx.types_in_modules, + ); + + let ast_type = definition + .backing_type + .as_ref() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(ast::TypeKind::u32().at(definition.source))); + + let resolved_type = type_ctx.resolve_or_undeclared(&ast_type)?; + + let definition = resolved_ast.enums.get_mut(*enum_ref).unwrap(); + definition.resolved_type = resolved_type; } for (name, type_ref) in job.type_aliases.iter() { @@ -275,8 +293,12 @@ pub fn resolve<'a>( .unwrap_or(*physical_file_id); for global in file.global_variables.iter() { - let type_ctx = - ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + let type_ctx = ResolveTypeCtx::new( + &resolved_ast, + module_file_id, + *physical_file_id, + &ctx.types_in_modules, + ); let resolved_type = type_ctx.resolve(&global.ast_type)?; let global_search_context = ctx @@ -305,8 +327,12 @@ pub fn resolve<'a>( for (function_i, function) in file.functions.iter().enumerate() { let name = ResolvedName::new(module_file_id, &function.name); - let type_ctx = - ResolveTypeCtx::new(&resolved_ast, module_file_id, &ctx.types_in_modules); + let type_ctx = ResolveTypeCtx::new( + &resolved_ast, + module_file_id, + *physical_file_id, + &ctx.types_in_modules, + ); let parameters = resolve_parameters(&type_ctx, &function.parameters)?; let return_type = type_ctx.resolve(&function.return_type)?; @@ -408,6 +434,7 @@ pub fn resolve<'a>( let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, + real_file_id, &ctx.types_in_modules, ); @@ -447,6 +474,7 @@ pub fn resolve<'a>( public_functions: &ctx.public_functions, types_in_modules: &ctx.types_in_modules, module_fs_node_id: module_file_id, + physical_fs_node_id: real_file_id, }; resolve_stmts(&mut ctx, &ast_function.stmts)? @@ -475,20 +503,34 @@ enum Initialized { pub struct ResolveTypeCtx<'a> { resolved_ast: &'a resolved::Ast<'a>, module_fs_node_id: FsNodeId, + file_fs_node_id: FsNodeId, types_in_modules: &'a HashMap>, used_aliases_stack: HashSet, } +impl<'a, 'b, 'c> From<&'c ResolveExprCtx<'a, 'b>> for ResolveTypeCtx<'c> { + fn from(ctx: &'c ResolveExprCtx<'a, 'b>) -> Self { + Self::new( + ctx.resolved_ast, + ctx.module_fs_node_id, + ctx.physical_fs_node_id, + ctx.types_in_modules, + ) + } +} + impl<'a> ResolveTypeCtx<'a> { pub fn new( resolved_ast: &'a resolved::Ast, module_fs_node_id: FsNodeId, - public_types: &'a HashMap>, + file_fs_node_id: FsNodeId, + types_in_modules: &'a HashMap>, ) -> Self { Self { resolved_ast, module_fs_node_id, - types_in_modules: public_types, + file_fs_node_id, + types_in_modules, used_aliases_stack: Default::default(), } } @@ -582,52 +624,49 @@ impl<'a> ResolveTypeCtx<'a> { } pub fn find_type(&self, name: &Name) -> Result, FindTypeError> { - let _source_files = self.resolved_ast.source_files; - let _settings = self + let settings = &self.resolved_ast.workspace.settings[self .resolved_ast .workspace - .get_settings_for_module(self.module_fs_node_id); - let _all_types = &self.resolved_ast.all_types; + .files + .get(&self.file_fs_node_id) + .unwrap() + .settings + .expect("valid settings id") + .0]; if let Some(name) = name.as_plain_str() { - if let Some(types_in_modules) = self.types_in_modules.get(&self.module_fs_node_id) { - if let Some(decl) = types_in_modules.get(name) { + if let Some(types_in_module) = self.types_in_modules.get(&self.module_fs_node_id) { + if let Some(decl) = types_in_module.get(name) { return Ok(Cow::Borrowed(&decl.kind)); } } } - todo!("TypeSearchCtx find_type - {:?}", name); - - /* - let resolved_name = ResolvedName::new(self.fs_node_id, name); - - if let Some(mapping) = self.types.get(&resolved_name) { - return self.resolve_mapping(&resolved_name, mapping, used_aliases_stack); - } - - if name.namespace.is_empty() { - let mut matches = self - .settings - .imported_namespaces - .iter() - .filter_map(|namespace| { - let resolved_name = ResolvedName::new( - self.fs_node_id, - &Name::new(Some(namespace.clone()), name.basename.clone()), - ); - self.types.get(&resolved_name) - }); + if !name.namespace.is_empty() { + let Name { + namespace, + basename, + .. + } = name; + + let mut matches = settings + .namespace_to_dependency + .get(namespace.as_ref()) + .into_iter() + .flatten() + .flat_map(|dep| settings.dependency_to_module.get(dep)) + .flat_map(|fs_node_id| self.types_in_modules.get(fs_node_id)) + .flat_map(|decls| decls.get(basename.as_ref())) + .filter(|decl| decl.privacy.is_public()); if let Some(found) = matches.next() { if matches.next().is_some() { return Err(FindTypeError::Ambiguous); } else { - return self.resolve_mapping(&resolved_name, found, used_aliases_stack); + return Ok(Cow::Borrowed(&found.kind)); } } } - */ Err(FindTypeError::NotDefined) } diff --git a/src/resolve/stmt.rs b/src/resolve/stmt.rs index d7104fa..5c0c6d4 100644 --- a/src/resolve/stmt.rs +++ b/src/resolve/stmt.rs @@ -3,7 +3,7 @@ use super::{ destination::resolve_expr_to_destination, error::{ResolveError, ResolveErrorKind}, expr::{resolve_basic_binary_operator, resolve_expr, PreferredType, ResolveExprCtx}, - Initialized, ResolveTypeCtx, + Initialized, }; use crate::{ast, resolved}; @@ -85,13 +85,7 @@ pub fn resolve_stmt( source, )), ast::StmtKind::Declaration(declaration) => { - let type_ctx = ResolveTypeCtx::new( - &ctx.resolved_ast, - ctx.module_fs_node_id, - ctx.types_in_modules, - ); - - let resolved_type = type_ctx.resolve(&declaration.ast_type)?; + let resolved_type = ctx.type_ctx().resolve(&declaration.ast_type)?; let value = declaration .initial_value diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index 6cc09bc..cd41ec3 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -31,6 +31,7 @@ new_key_type! { pub struct GlobalVarRef; pub struct StructureRef; pub struct TypeRef; + pub struct EnumRef; } #[derive(Clone, Debug)] @@ -40,7 +41,7 @@ pub struct Ast<'a> { pub functions: SlotMap, pub structures: SlotMap, pub globals: SlotMap, - pub enums: IndexMap, + pub enums: SlotMap, pub workspace: &'a AstWorkspace<'a>, // New Experimental Type Resolution System pub all_types: SlotMap, @@ -55,7 +56,7 @@ impl<'a> Ast<'a> { functions: SlotMap::with_key(), structures: SlotMap::with_key(), globals: SlotMap::with_key(), - enums: IndexMap::new(), + enums: SlotMap::with_key(), workspace, all_types: SlotMap::with_key(), types_per_module: HashMap::new(), @@ -171,7 +172,7 @@ pub struct TypeDecl { pub privacy: Privacy, } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct HumanName(pub String); impl Display for HumanName { @@ -196,7 +197,7 @@ pub enum TypeKind { AnonymousEnum(AnonymousEnum), FixedArray(Box), FunctionPointer(FunctionPointer), - Enum(HumanName, Option), + Enum(HumanName, EnumRef), Structure(HumanName, StructureRef), TypeAlias(HumanName, TypeRef), } @@ -531,7 +532,8 @@ pub struct ArrayAccess { #[derive(Clone, Debug)] pub struct EnumMemberLiteral { - pub enum_name: ResolvedName, + pub human_name: HumanName, + pub enum_ref: EnumRef, pub variant_name: String, pub source: Source, } From ee79f5d2f0884d778110da7a94722d7817da230a Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Sun, 13 Oct 2024 15:48:31 -0500 Subject: [PATCH 11/14] Improved error messages for missing functions --- src/name.rs | 6 ++--- src/resolve/error.rs | 34 +++++++++++++++++++++----- src/resolve/expr/call.rs | 15 +++++++++++- src/resolve/function_search_ctx.rs | 39 ++++++++++++++++++++++++++++++ src/resolved/mod.rs | 27 +++++++++++++++++++++ 5 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/name.rs b/src/name.rs index 419047e..025e167 100644 --- a/src/name.rs +++ b/src/name.rs @@ -88,14 +88,14 @@ impl Display for DisplayResolvedName<'_> { #[allow(dead_code)] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let filename = &self.fs.get(self.name.fs_node_id).filename; - let prefix = if cfg!(target_os = "windows") { "/" } else { "" }; + let prefix = if cfg!(target_os = "windows") { "" } else { "/" }; write!( f, - "{}{} ::: {}", + "{}{} - {}", prefix, filename.to_string_lossy(), - self.name.plain() + self.name.plain(), )?; Ok(()) diff --git a/src/resolve/error.rs b/src/resolve/error.rs index ef9a659..147c41b 100644 --- a/src/resolve/error.rs +++ b/src/resolve/error.rs @@ -31,8 +31,9 @@ pub enum ResolveErrorKind { value: String, }, FailedToFindFunction { - name: String, + signature: String, reason: FindFunctionError, + almost_matches: Vec, }, UndeclaredVariable { name: String, @@ -211,12 +212,33 @@ impl Display for ResolveErrorKind { value )?; } - ResolveErrorKind::FailedToFindFunction { name, reason } => match reason { - FindFunctionError::NotDefined => write!(f, "Failed to find function '{}'", name)?, - FindFunctionError::Ambiguous => { - write!(f, "Multiple possibilities for function '{}'", name)? + ResolveErrorKind::FailedToFindFunction { + signature, + reason, + almost_matches, + } => { + match reason { + FindFunctionError::NotDefined => { + write!(f, "Failed to find function '{}'", signature)? + } + FindFunctionError::Ambiguous => { + write!(f, "Multiple possibilities for function '{}'", signature)? + } + } + + if !almost_matches.is_empty() { + write!(f, "\n Did you mean?")?; + + for almost_match in almost_matches { + write!(f, "\n {}", almost_match)?; + } + } else { + write!( + f, + "\n No available functions have that name, is it public?" + )?; } - }, + } ResolveErrorKind::UndeclaredVariable { name } => { write!(f, "Undeclared variable '{}'", name)?; } diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index e7667b5..b1625cd 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -9,6 +9,7 @@ use crate::{ resolved::{self, TypedExpr}, source_files::Source, }; +use itertools::Itertools; pub fn resolve_call_expr( ctx: &mut ResolveExprCtx<'_, '_>, @@ -35,9 +36,21 @@ pub fn resolve_call_expr( ) { Ok(function_ref) => function_ref, Err(reason) => { + let args = arguments + .iter() + .map(|arg| arg.resolved_type.to_string()) + .collect_vec(); + + let signature = format!("{}({})", call.function_name, args.join(", ")); + + let almost_matches = ctx + .function_search_ctx + .find_function_almost_matches(ctx, &call.function_name); + return Err(ResolveErrorKind::FailedToFindFunction { - name: call.function_name.to_string(), + signature, reason, + almost_matches, } .at(source)); } diff --git a/src/resolve/function_search_ctx.rs b/src/resolve/function_search_ctx.rs index 987ce28..43c6f3e 100644 --- a/src/resolve/function_search_ctx.rs +++ b/src/resolve/function_search_ctx.rs @@ -9,6 +9,7 @@ use crate::{ source_files::Source, workspace::fs::FsNodeId, }; +use itertools::Itertools; use std::collections::HashMap; #[derive(Clone, Debug)] @@ -151,4 +152,42 @@ impl FunctionSearchCtx { true } + + pub fn find_function_almost_matches(&self, ctx: &ResolveExprCtx, name: &Name) -> Vec { + let resolved_name = ResolvedName::new(self.fs_node_id, name); + + let local_matches = self.available.get(&resolved_name).into_iter().flatten(); + + let remote_matches = (!name.namespace.is_empty()) + .then(|| { + ctx.settings + .namespace_to_dependency + .get(name.namespace.as_ref()) + }) + .flatten() + .into_iter() + .flatten() + .flat_map(|dependency| { + ctx.settings + .dependency_to_module + .get(dependency) + .and_then(|module_fs_node_id| ctx.public_functions.get(module_fs_node_id)) + .and_then(|public| public.get(name.basename.as_ref())) + .into_iter() + }) + .flatten(); + + local_matches + .chain(remote_matches) + .map(|function_ref| { + let function = ctx.resolved_ast.functions.get(*function_ref).unwrap(); + + format!( + "{}({})", + function.name.display(&ctx.resolved_ast.workspace.fs), + function.parameters + ) + }) + .collect_vec() + } } diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index cd41ec3..6d542b1 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -99,12 +99,39 @@ pub struct Parameters { pub is_cstyle_vararg: bool, } +impl Display for Parameters { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, param) in self.required.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", param)?; + } + + if self.is_cstyle_vararg { + if !self.required.is_empty() { + write!(f, ", ")?; + } + + write!(f, "...")?; + } + + Ok(()) + } +} + #[derive(Clone, Debug)] pub struct Parameter { pub name: String, pub resolved_type: Type, } +impl Display for Parameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self.name, self.resolved_type) + } +} + impl PartialEq for Parameter { fn eq(&self, other: &Self) -> bool { self.resolved_type.eq(&other.resolved_type) From 011356f21ff69cb4b3e2217dcfc5377ad3773286 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Sun, 13 Oct 2024 21:37:41 -0500 Subject: [PATCH 12/14] Added support for type aliases in new type resolution system --- src/ast/file.rs | 4 +- src/ast/type_alias.rs | 1 + src/c/translation/mod.rs | 15 ++--- src/lower/mod.rs | 11 +++- src/parser/parse_top_level.rs | 14 +---- src/parser/parse_type_alias.rs | 20 +++--- src/resolve/conform/from_c_integer.rs | 20 +++--- src/resolve/conform/from_float.rs | 4 +- src/resolve/conform/from_integer.rs | 15 +++-- src/resolve/conform/from_pointer.rs | 47 +++++++++----- src/resolve/conform/mod.rs | 55 ++++++++++++---- src/resolve/core_structure_info.rs | 13 ++-- src/resolve/error.rs | 14 +++++ src/resolve/expr/basic_binary_operation.rs | 1 + src/resolve/expr/call.rs | 1 + src/resolve/expr/conditional.rs | 2 + src/resolve/expr/member_expr.rs | 3 +- src/resolve/expr/mod.rs | 15 +++-- .../expr/short_circuiting_binary_operation.rs | 2 + src/resolve/expr/struct_literal.rs | 11 +++- src/resolve/function_search_ctx.rs | 1 + src/resolve/mod.rs | 35 +++++++---- src/resolve/stmt.rs | 3 + src/resolve/unify_types/mod.rs | 7 ++- src/resolved/mod.rs | 63 +++++++++++-------- 25 files changed, 244 insertions(+), 133 deletions(-) diff --git a/src/ast/file.rs b/src/ast/file.rs index dd506bd..71b2fae 100644 --- a/src/ast/file.rs +++ b/src/ast/file.rs @@ -9,7 +9,7 @@ use indexmap::IndexMap; pub struct AstFile { pub functions: Vec, pub structures: Vec, - pub type_aliases: IndexMap, + pub type_aliases: Vec, pub global_variables: Vec, pub enums: Vec, pub helper_exprs: IndexMap, @@ -21,7 +21,7 @@ impl AstFile { AstFile { functions: vec![], structures: vec![], - type_aliases: IndexMap::default(), + type_aliases: vec![], global_variables: vec![], enums: vec![], helper_exprs: IndexMap::default(), diff --git a/src/ast/type_alias.rs b/src/ast/type_alias.rs index 4f28e74..481858b 100644 --- a/src/ast/type_alias.rs +++ b/src/ast/type_alias.rs @@ -3,6 +3,7 @@ use crate::source_files::Source; #[derive(Clone, Debug)] pub struct TypeAlias { + pub name: String, pub value: Type, pub source: Source, pub privacy: Privacy, diff --git a/src/c/translation/mod.rs b/src/c/translation/mod.rs index 4b3a7b7..73d47d8 100644 --- a/src/c/translation/mod.rs +++ b/src/c/translation/mod.rs @@ -10,7 +10,6 @@ use crate::{ ast::{self, AstFile, Privacy}, c::parser::{CTypedef, DeclarationSpecifiers, Declarator, ParseError}, diagnostics::Diagnostics, - name::Name, }; use std::collections::HashMap; @@ -32,14 +31,12 @@ pub fn declare_named_declaration( )?; if is_typedef { - ast_file.type_aliases.insert( - Name::plain(name.clone()), - ast::TypeAlias { - value: ast_type.clone(), - source: declarator.source, - privacy: Privacy::Public, - }, - ); + ast_file.type_aliases.push(ast::TypeAlias { + name: name.clone(), + value: ast_type.clone(), + source: declarator.source, + privacy: Privacy::Public, + }); typedefs.insert(name, CTypedef { ast_type }); return Ok(()); diff --git a/src/lower/mod.rs b/src/lower/mod.rs index d1be87c..b362b14 100644 --- a/src/lower/mod.rs +++ b/src/lower/mod.rs @@ -348,9 +348,6 @@ fn lower_type( match &resolved_type.kind { resolved::TypeKind::Unresolved => panic!("got unresolved type during lower_type!"), - resolved::TypeKind::TypeAlias(_, _) => { - todo!("lower type ref for aliases not supported yet") - } resolved::TypeKind::Boolean => Ok(ir::Type::Boolean), resolved::TypeKind::Integer(bits, sign) => Ok(match (bits, sign) { (Bits::Bits8, Sign::Signed) => ir::Type::S8, @@ -413,6 +410,14 @@ fn lower_type( lower_type(target, &enum_definition.resolved_type, resolved_ast) } + resolved::TypeKind::TypeAlias(_, type_alias_ref) => { + let resolved_type = resolved_ast + .type_aliases + .get(*type_alias_ref) + .expect("referenced type alias to exist"); + + lower_type(target, resolved_type, resolved_ast) + } } } diff --git a/src/parser/parse_top_level.rs b/src/parser/parse_top_level.rs index 027c42b..91a6ad9 100644 --- a/src/parser/parse_top_level.rs +++ b/src/parser/parse_top_level.rs @@ -4,7 +4,7 @@ use super::{ Parser, }; use crate::{ - ast::{AstFile, HelperExpr, Named, TypeAlias}, + ast::{AstFile, HelperExpr, Named}, index_map_ext::IndexMapExt, inflow::Inflow, token::{Token, TokenKind}, @@ -60,16 +60,8 @@ impl<'a, I: Inflow> Parser<'a, I> { ast_file.structures.push(self.parse_structure(annotations)?) } TokenKind::TypeAliasKeyword => { - let Named:: { name, value: alias } = - self.parse_type_alias(annotations)?; - let source = alias.source; - - ast_file.type_aliases.try_insert(name, alias, |name| { - ParseErrorKind::TypeAliasHasMultipleDefinitions { - name: name.to_string(), - } - .at(source) - })?; + let type_alias = self.parse_type_alias(annotations)?; + ast_file.type_aliases.push(type_alias); } TokenKind::EnumKeyword => { let enum_definition = self.parse_enum(annotations)?; diff --git a/src/parser/parse_type_alias.rs b/src/parser/parse_type_alias.rs index 2acc779..a25784f 100644 --- a/src/parser/parse_type_alias.rs +++ b/src/parser/parse_type_alias.rs @@ -1,8 +1,7 @@ use super::{annotation::Annotation, error::ParseError, Parser}; use crate::{ - ast::{Named, Privacy, TypeAlias}, + ast::{Privacy, TypeAlias}, inflow::Inflow, - name::Name, parser::annotation::AnnotationKind, token::{Token, TokenKind}, }; @@ -11,19 +10,16 @@ impl<'a, I: Inflow> Parser<'a, I> { pub fn parse_type_alias( &mut self, annotations: Vec, - ) -> Result, ParseError> { + ) -> Result { let source = self.source_here(); assert!(self.input.advance().is_type_alias_keyword()); - let mut namespace = None; let mut privacy = Privacy::Private; let name = self.parse_identifier(Some("for alias name after 'typealias' keyword"))?; self.ignore_newlines(); - #[allow(clippy::never_loop, clippy::match_single_binding)] for annotation in annotations { match annotation.kind { - AnnotationKind::Namespace(new_namespace) => namespace = Some(new_namespace), AnnotationKind::Public => privacy = Privacy::Public, _ => return Err(self.unexpected_annotation(&annotation, Some("for type alias"))), } @@ -33,13 +29,11 @@ impl<'a, I: Inflow> Parser<'a, I> { let becomes_type = self.parse_type(None::<&str>, Some("for type alias"))?; - Ok(Named:: { - name: Name::new(namespace, name), - value: TypeAlias { - value: becomes_type, - source, - privacy, - }, + Ok(TypeAlias { + name, + value: becomes_type, + source, + privacy, }) } } diff --git a/src/resolve/conform/from_c_integer.rs b/src/resolve/conform/from_c_integer.rs index cdcf9ce..c8adc06 100644 --- a/src/resolve/conform/from_c_integer.rs +++ b/src/resolve/conform/from_c_integer.rs @@ -3,14 +3,15 @@ use crate::{ ast::{CInteger, IntegerBits, OptionIntegerSignExt}, logic::implies, resolved::{ - Cast, CastFrom, ExprKind, IntegerSign, Type, TypeKind, TypedExpr, UnaryMathOperation, + Cast, CastFrom, Expr, ExprKind, IntegerSign, Type, TypeKind, TypedExpr, UnaryMathOperation, UnaryMathOperator, }, source_files::Source, }; pub fn from_c_integer( - expr: &TypedExpr, + expr: &Expr, + from_type: &Type, mode: ConformMode, from_c_integer: CInteger, from_sign: Option, @@ -18,7 +19,7 @@ pub fn from_c_integer( source: Source, ) -> ObjectiveResult { match &to_type.kind { - TypeKind::Boolean => from_c_integer_to_bool::(expr, mode, source), + TypeKind::Boolean => from_c_integer_to_bool::(expr, from_type, mode, source), TypeKind::Integer(to_bits, to_sign) => from_c_integer_to_integer::( expr, mode, @@ -42,7 +43,8 @@ pub fn from_c_integer( } fn from_c_integer_to_bool( - expr: &TypedExpr, + expr: &Expr, + from_type: &Type, mode: ConformMode, source: Source, ) -> ObjectiveResult { @@ -55,7 +57,7 @@ fn from_c_integer_to_bool( TypeKind::Boolean.at(source), ExprKind::UnaryMathOperation(Box::new(UnaryMathOperation { operator: UnaryMathOperator::IsNonZero, - inner: expr.clone(), + inner: TypedExpr::new(from_type.clone(), expr.clone()), })) .at(source), ) @@ -63,7 +65,7 @@ fn from_c_integer_to_bool( } pub fn from_c_integer_to_c_integer( - expr: &TypedExpr, + expr: &Expr, mode: ConformMode, from_c_integer: CInteger, from_sign: Option, @@ -89,7 +91,7 @@ pub fn from_c_integer_to_c_integer( TypedExpr::new( target_type.clone(), ExprKind::IntegerCast(Box::new(CastFrom { - cast: Cast::new(target_type, expr.expr.clone()), + cast: Cast::new(target_type, expr.clone()), from_type: TypeKind::CInteger(from_c_integer, from_sign).at(source), })) .at(source), @@ -101,7 +103,7 @@ pub fn from_c_integer_to_c_integer( } fn from_c_integer_to_integer( - expr: &TypedExpr, + expr: &Expr, mode: ConformMode, from_c_integer: CInteger, from_sign: Option, @@ -119,7 +121,7 @@ fn from_c_integer_to_integer( TypedExpr::new( target_type.clone(), ExprKind::IntegerCast(Box::new(CastFrom { - cast: Cast::new(target_type, expr.expr.clone()), + cast: Cast::new(target_type, expr.clone()), from_type: TypeKind::CInteger(from_c_integer, from_sign).at(source), })) .at(source), diff --git a/src/resolve/conform/from_float.rs b/src/resolve/conform/from_float.rs index d44b4a0..71b9a1e 100644 --- a/src/resolve/conform/from_float.rs +++ b/src/resolve/conform/from_float.rs @@ -6,7 +6,7 @@ use crate::{ }; pub fn from_float( - expr: &TypedExpr, + expr: &Expr, mode: ConformMode, from_size: FloatSize, to_type: &Type, @@ -17,7 +17,7 @@ pub fn from_float( match &to_type.kind { TypeKind::Floating(to_size) => { - from_float_to_float::(&expr.expr, from_size, *to_size, to_type.source) + from_float_to_float::(&expr, from_size, *to_size, to_type.source) } _ => O::fail(), } diff --git a/src/resolve/conform/from_integer.rs b/src/resolve/conform/from_integer.rs index 7a97b33..1e973d0 100644 --- a/src/resolve/conform/from_integer.rs +++ b/src/resolve/conform/from_integer.rs @@ -7,7 +7,8 @@ use crate::{ }; pub fn from_integer( - expr: &TypedExpr, + expr: &Expr, + from_type: &Type, mode: ConformMode, behavior: ConformBehavior, from_bits: IntegerBits, @@ -17,7 +18,7 @@ pub fn from_integer( match &to_type.kind { TypeKind::Integer(to_bits, to_sign) => match behavior { ConformBehavior::Adept(_) => from_integer_adept_mode::( - &expr.expr, + &expr, mode, from_bits, from_sign, @@ -26,7 +27,7 @@ pub fn from_integer( to_type.source, ), ConformBehavior::C => from_integer_c_mode::( - &expr.expr, + &expr, mode, from_bits, from_sign, @@ -37,6 +38,7 @@ pub fn from_integer( }, TypeKind::CInteger(to_c_integer, to_sign) => conform_from_integer_to_c_integer::( expr, + from_type, mode, behavior, from_bits, @@ -92,7 +94,8 @@ fn from_integer_c_mode( } fn conform_from_integer_to_c_integer( - expr: &TypedExpr, + expr: &Expr, + from_type: &Type, mode: ConformMode, behavior: ConformBehavior, from_bits: IntegerBits, @@ -116,8 +119,8 @@ fn conform_from_integer_to_c_integer( if mode.allow_lossy_integer() || is_lossless { let cast_from = CastFrom { - cast: Cast::new(target_type.clone(), expr.expr.clone()), - from_type: expr.resolved_type.clone(), + cast: Cast::new(target_type.clone(), expr.clone()), + from_type: from_type.clone(), }; return O::success(|| { diff --git a/src/resolve/conform/from_pointer.rs b/src/resolve/conform/from_pointer.rs index 0eb4a8a..978bf63 100644 --- a/src/resolve/conform/from_pointer.rs +++ b/src/resolve/conform/from_pointer.rs @@ -1,29 +1,44 @@ -use super::{ConformMode, Objective, ObjectiveResult}; -use crate::resolved::{Type, TypeKind, TypedExpr}; +use super::{warn_type_alias_depth_exceeded, ConformMode, Objective, ObjectiveResult}; +use crate::{ + resolve::expr::ResolveExprCtx, + resolved::{Expr, Type, TypeKind, TypedExpr}, +}; pub fn from_pointer( - expr: &TypedExpr, + ctx: &ResolveExprCtx, + expr: &Expr, mode: ConformMode, - from_inner: &Type, + from_inner_type: &Type, to_type: &Type, ) -> ObjectiveResult { - if from_inner.kind.is_void() { - return match &to_type.kind { - TypeKind::Pointer(to_inner) => O::success(|| { - TypedExpr::new( - TypeKind::Pointer(to_inner.clone()).at(to_type.source), - expr.expr.clone(), - ) - }), - _ => O::fail(), - }; + let Ok(from_inner_type) = ctx.resolved_ast.unalias(from_inner_type) else { + warn_type_alias_depth_exceeded(from_inner_type); + return O::fail(); + }; + + let TypeKind::Pointer(to_inner_type) = &to_type.kind else { + return O::fail(); + }; + + let Ok(to_inner_type) = ctx.resolved_ast.unalias(to_inner_type) else { + warn_type_alias_depth_exceeded(to_inner_type); + return O::fail(); + }; + + if from_inner_type.kind.is_void() { + return O::success(|| { + TypedExpr::new( + TypeKind::Pointer(Box::new(TypeKind::Void.at(to_type.source))).at(to_type.source), + expr.clone(), + ) + }); } - if to_type.kind.is_void_pointer() && mode.allow_pointer_into_void_pointer() { + if to_inner_type.kind.is_void() && mode.allow_pointer_into_void_pointer() { return O::success(|| { TypedExpr::new( TypeKind::Pointer(Box::new(TypeKind::Void.at(to_type.source))).at(to_type.source), - expr.expr.clone(), + expr.clone(), ) }); } diff --git a/src/resolve/conform/mod.rs b/src/resolve/conform/mod.rs index 0540503..947d7bf 100644 --- a/src/resolve/conform/mod.rs +++ b/src/resolve/conform/mod.rs @@ -12,7 +12,10 @@ use self::{ from_integer::from_integer, from_integer_literal::from_integer_literal, from_pointer::from_pointer, }; -use super::error::{ResolveError, ResolveErrorKind}; +use super::{ + error::{ResolveError, ResolveErrorKind}, + expr::ResolveExprCtx, +}; use crate::{ ast::ConformBehavior, resolved::{Type, TypeKind, TypedExpr}, @@ -54,14 +57,35 @@ impl Objective for Validate { } } +pub fn warn_type_alias_depth_exceeded(resolved_type: &Type) { + // TODO: WARNING: When this happens, it might not be obvious why there + // wasn't a match. This should probably cause an error message + // TODO: Make this more transparent by adding a good error message + eprintln!( + "warning: ignoring type '{}' since it exceeds maximum type alias recursion depth", + resolved_type + ); +} + pub fn conform_expr( + ctx: &ResolveExprCtx, expr: &TypedExpr, to_type: &Type, mode: ConformMode, behavior: ConformBehavior, conform_source: Source, ) -> ObjectiveResult { - if expr.resolved_type == *to_type { + let Ok(from_type) = ctx.resolved_ast.unalias(&expr.resolved_type) else { + warn_type_alias_depth_exceeded(&expr.resolved_type); + return O::fail(); + }; + + let Ok(to_type) = ctx.resolved_ast.unalias(to_type) else { + warn_type_alias_depth_exceeded(&expr.resolved_type); + return O::fail(); + }; + + if *from_type == *to_type { return O::success(|| TypedExpr { resolved_type: to_type.clone(), expr: expr.expr.clone(), @@ -69,34 +93,43 @@ pub fn conform_expr( }); } - match &expr.resolved_type.kind { + match &from_type.kind { TypeKind::IntegerLiteral(from) => from_integer_literal::( from, behavior.c_integer_assumptions(), expr.expr.source, to_type, ), - TypeKind::Integer(from_bits, from_sign) => { - from_integer::(expr, mode, behavior, *from_bits, *from_sign, to_type) - } + TypeKind::Integer(from_bits, from_sign) => from_integer::( + &expr.expr, from_type, mode, behavior, *from_bits, *from_sign, to_type, + ), TypeKind::FloatLiteral(from) => from_float_literal::(*from, to_type, conform_source), - TypeKind::Floating(from_size) => from_float::(expr, mode, *from_size, to_type), - TypeKind::Pointer(from_inner) => from_pointer::(expr, mode, from_inner, to_type), - TypeKind::CInteger(from_size, from_sign) => { - from_c_integer::(expr, mode, *from_size, *from_sign, to_type, conform_source) + TypeKind::Floating(from_size) => from_float::(&expr.expr, mode, *from_size, to_type), + TypeKind::Pointer(from_inner) => { + from_pointer::(ctx, &expr.expr, mode, from_inner, to_type) } + TypeKind::CInteger(from_size, from_sign) => from_c_integer::( + &expr.expr, + from_type, + mode, + *from_size, + *from_sign, + to_type, + conform_source, + ), _ => O::fail(), } } pub fn conform_expr_or_error( + ctx: &ResolveExprCtx, expr: &TypedExpr, target_type: &Type, mode: ConformMode, behavior: ConformBehavior, conform_source: Source, ) -> Result { - conform_expr::(expr, target_type, mode, behavior, conform_source).or_else(|_| { + conform_expr::(ctx, expr, target_type, mode, behavior, conform_source).or_else(|_| { Err(ResolveErrorKind::TypeMismatch { left: expr.resolved_type.to_string(), right: target_type.to_string(), diff --git a/src/resolve/core_structure_info.rs b/src/resolve/core_structure_info.rs index 20fce81..1e6a05b 100644 --- a/src/resolve/core_structure_info.rs +++ b/src/resolve/core_structure_info.rs @@ -4,11 +4,16 @@ use crate::{ source_files::Source, }; -pub fn get_core_structure_info( - resolved_type: &resolved::Type, +pub fn get_core_structure_info<'a, 'b>( + resolved_ast: &'b resolved::Ast<'a>, + resolved_type: &'a resolved::Type, source: Source, -) -> Result<(&HumanName, StructureRef), ResolveError> { - match &resolved_type.kind { +) -> Result<(&'b HumanName, StructureRef), ResolveError> { + match &resolved_ast + .unalias(resolved_type) + .map_err(|e| ResolveErrorKind::from(e).at(source))? + .kind + { resolved::TypeKind::Structure(name, structure_ref) => Ok((name, *structure_ref)), _ => Err(ResolveErrorKind::CannotCreateStructLiteralForNonStructure { bad_type: resolved_type.to_string(), diff --git a/src/resolve/error.rs b/src/resolve/error.rs index 147c41b..874ff93 100644 --- a/src/resolve/error.rs +++ b/src/resolve/error.rs @@ -1,5 +1,6 @@ use super::function_search_ctx::FindFunctionError; use crate::{ + resolved::UnaliasError, show::Show, source_files::{Source, SourceFiles}, }; @@ -18,6 +19,12 @@ impl ResolveError { } } +impl From for ResolveErrorKind { + fn from(value: UnaliasError) -> Self { + Self::UnaliasError(value) + } +} + #[derive(Clone, Debug)] pub enum ResolveErrorKind { CannotReturnValueOfType { @@ -165,6 +172,7 @@ pub enum ResolveErrorKind { name: String, }, UndeterminedCharacterLiteral, + UnaliasError(UnaliasError), Other { message: String, }, @@ -447,6 +455,12 @@ impl Display for ResolveErrorKind { "Undetermined character literal, consider using c'A' if you want a 'char'" )?; } + ResolveErrorKind::UnaliasError(details) => match details { + UnaliasError::MaxDepthExceeded => write!( + f, + "Maximum type alias depth exceeded, please ensure your type alias is not recursive" + )?, + }, ResolveErrorKind::Other { message } => { write!(f, "{}", message)?; } diff --git a/src/resolve/expr/basic_binary_operation.rs b/src/resolve/expr/basic_binary_operation.rs index 26b2dbb..d66e26f 100644 --- a/src/resolve/expr/basic_binary_operation.rs +++ b/src/resolve/expr/basic_binary_operation.rs @@ -45,6 +45,7 @@ pub fn resolve_basic_binary_operation_expr( } let unified_type = unify_types( + ctx, preferred_type.map(|preferred_type| preferred_type.view(ctx.resolved_ast)), &mut [&mut left, &mut right], ctx.adept_conform_behavior(), diff --git a/src/resolve/expr/call.rs b/src/resolve/expr/call.rs index b1625cd..a7b313b 100644 --- a/src/resolve/expr/call.rs +++ b/src/resolve/expr/call.rs @@ -71,6 +71,7 @@ pub fn resolve_call_expr( preferred_type.map(|preferred_type| preferred_type.view(ctx.resolved_ast)) { if let Ok(conformed_argument) = conform_expr::( + ctx, &argument, preferred_type, ConformMode::ParameterPassing, diff --git a/src/resolve/expr/conditional.rs b/src/resolve/expr/conditional.rs index 8e8daca..87256cb 100644 --- a/src/resolve/expr/conditional.rs +++ b/src/resolve/expr/conditional.rs @@ -33,6 +33,7 @@ pub fn resolve_conditional_expr( let stmts = resolve_stmts(ctx, &block.stmts)?; let condition = conform_expr_or_error( + ctx, &condition, &resolved::TypeKind::Boolean.at(source), ConformMode::Normal, @@ -103,6 +104,7 @@ pub fn resolve_conditional_expr( .collect_vec(); unify_types( + ctx, preferred_type.map(|preferred_type| preferred_type.view(ctx.resolved_ast)), &mut last_exprs[..], ctx.adept_conform_behavior(), diff --git a/src/resolve/expr/member_expr.rs b/src/resolve/expr/member_expr.rs index 2664fd3..b4b765d 100644 --- a/src/resolve/expr/member_expr.rs +++ b/src/resolve/expr/member_expr.rs @@ -20,7 +20,8 @@ pub fn resolve_member_expr( ) -> Result { let resolved_subject = resolve_expr(ctx, subject, None, Initialized::Require)?; - let (_, structure_ref) = get_core_structure_info(&resolved_subject.resolved_type, source)?; + let (_, structure_ref) = + get_core_structure_info(ctx.resolved_ast, &resolved_subject.resolved_type, source)?; let structure = ctx .resolved_ast diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index 5e98510..07ac76c 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -326,13 +326,16 @@ pub fn resolve_expr( ast::ExprKind::While(while_loop) => { ctx.variable_search_ctx.begin_scope(); + let expr = resolve_expr( + ctx, + &while_loop.condition, + Some(PreferredType::of(&resolved::TypeKind::Boolean.at(source))), + Initialized::Require, + )?; + let condition = conform_expr_or_error( - &resolve_expr( - ctx, - &while_loop.condition, - Some(PreferredType::of(&resolved::TypeKind::Boolean.at(source))), - Initialized::Require, - )?, + ctx, + &expr, &resolved::TypeKind::Boolean.at(source), ConformMode::Normal, ctx.adept_conform_behavior(), diff --git a/src/resolve/expr/short_circuiting_binary_operation.rs b/src/resolve/expr/short_circuiting_binary_operation.rs index 1ebca63..95bfb7c 100644 --- a/src/resolve/expr/short_circuiting_binary_operation.rs +++ b/src/resolve/expr/short_circuiting_binary_operation.rs @@ -26,6 +26,7 @@ pub fn resolve_short_circuiting_binary_operation_expr( )?; let left = conform_expr::( + ctx, &left, &local_bool_type, ConformMode::Normal, @@ -52,6 +53,7 @@ pub fn resolve_short_circuiting_binary_operation_expr( )?; let right = conform_expr::( + ctx, &right, &local_bool_type, ConformMode::Normal, diff --git a/src/resolve/expr/struct_literal.rs b/src/resolve/expr/struct_literal.rs index 3492fd2..430dc15 100644 --- a/src/resolve/expr/struct_literal.rs +++ b/src/resolve/expr/struct_literal.rs @@ -37,8 +37,9 @@ pub fn resolve_struct_literal_expr( conform_behavior: ConformBehavior, source: Source, ) -> Result { - let resolved_type = ctx.type_ctx().resolve(ast_type)?; - let (struct_name, structure_ref) = get_core_structure_info(&resolved_type, source)?; + let resolved_struct_type = ctx.type_ctx().resolve(ast_type)?; + let (struct_name, structure_ref) = + get_core_structure_info(ctx.resolved_ast, &resolved_struct_type, source)?; let structure_type = resolved::TypeKind::Structure(struct_name.clone(), structure_ref).at(source); @@ -97,6 +98,7 @@ pub fn resolve_struct_literal_expr( }; let resolved_expr = conform_expr::( + ctx, &resolved_expr, &field.resolved_type, mode, @@ -116,6 +118,9 @@ pub fn resolve_struct_literal_expr( .insert(field_name.to_string(), (resolved_expr.expr, index)) .is_some() { + let (struct_name, _) = + get_core_structure_info(ctx.resolved_ast, &resolved_struct_type, source)?; + return Err(ResolveErrorKind::FieldSpecifiedMoreThanOnce { struct_name: struct_name.to_string(), field_name: field_name.to_string(), @@ -161,7 +166,7 @@ pub fn resolve_struct_literal_expr( } Ok(TypedExpr::new( - resolved_type.clone(), + resolved_struct_type.clone(), resolved::Expr::new( resolved::ExprKind::StructLiteral(Box::new(StructLiteral { structure_type, diff --git a/src/resolve/function_search_ctx.rs b/src/resolve/function_search_ctx.rs index 43c6f3e..53ba365 100644 --- a/src/resolve/function_search_ctx.rs +++ b/src/resolve/function_search_ctx.rs @@ -135,6 +135,7 @@ impl FunctionSearchCtx { let argument_conform = if let Some(preferred_type) = preferred_type.map(|p| p.view(ctx.resolved_ast)) { conform_expr::( + ctx, argument, preferred_type, ConformMode::ParameterPassing, diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 7f550db..6b051d1 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -22,7 +22,7 @@ use crate::{ index_map_ext::IndexMapExt, name::{Name, ResolvedName}, resolved::{ - self, EnumRef, HumanName, StructureRef, TypeDecl, TypeKind, TypeRef, TypedExpr, + self, EnumRef, HumanName, StructureRef, TypeAliasRef, TypeDecl, TypeKind, TypedExpr, VariableStorage, }, source_files::Source, @@ -102,9 +102,9 @@ pub fn resolve<'a>( let mut resolved_ast = resolved::Ast::new(source_files, &ast_workspace); #[derive(Clone, Debug)] - struct TypeJob<'a> { + struct TypeJob { physical_file_id: FsNodeId, - type_aliases: HashMap<&'a Name, TypeRef>, + type_aliases: Vec, structures: Vec, enums: Vec, } @@ -119,7 +119,7 @@ pub fn resolve<'a>( let mut job = TypeJob { physical_file_id: *physical_file_id, - type_aliases: HashMap::with_capacity(file.type_aliases.len()), + type_aliases: Vec::with_capacity(file.type_aliases.len()), structures: Vec::with_capacity(file.structures.len()), enums: Vec::with_capacity(file.enums.len()), }; @@ -191,11 +191,14 @@ pub fn resolve<'a>( job.enums.push(enum_ref); } - for (name, definition) in file.type_aliases.iter() { + for definition in file.type_aliases.iter() { + let type_alias_ref = resolved_ast + .type_aliases + .insert(resolved::TypeKind::Unresolved.at(definition.value.source)); + let source = definition.source; let privacy = definition.privacy; - let becomes_type = resolved_ast.all_types.insert(TypeKind::Unresolved); - let kind = TypeKind::TypeAlias(HumanName(name.to_string()), becomes_type); + let kind = TypeKind::TypeAlias(HumanName(definition.name.to_string()), type_alias_ref); let types_in_module = ctx .types_in_modules @@ -203,7 +206,7 @@ pub fn resolve<'a>( .or_insert_with(HashMap::new); types_in_module.insert( - name.to_string(), + definition.name.to_string(), TypeDecl { kind, source, @@ -211,7 +214,7 @@ pub fn resolve<'a>( }, ); - job.type_aliases.insert(name, becomes_type); + job.type_aliases.push(type_alias_ref); } type_jobs.push(job); @@ -281,8 +284,18 @@ pub fn resolve<'a>( definition.resolved_type = resolved_type; } - for (name, type_ref) in job.type_aliases.iter() { - eprintln!("warning - new type resolution does not handle enum type aliases yet"); + for (type_alias_ref, definition) in job.type_aliases.iter().zip(file.type_aliases.iter()) { + let type_ctx = ResolveTypeCtx::new( + &resolved_ast, + module_file_id, + job.physical_file_id, + &ctx.types_in_modules, + ); + + let resolved_type = type_ctx.resolve_or_undeclared(&definition.value)?; + + let binding = resolved_ast.type_aliases.get_mut(*type_alias_ref).unwrap(); + *binding = resolved_type; } } diff --git a/src/resolve/stmt.rs b/src/resolve/stmt.rs index 5c0c6d4..4954934 100644 --- a/src/resolve/stmt.rs +++ b/src/resolve/stmt.rs @@ -44,6 +44,7 @@ pub fn resolve_stmt( .return_type; if let Ok(result) = conform_expr::( + ctx, &result, return_type, ConformMode::Normal, @@ -102,6 +103,7 @@ pub fn resolve_stmt( .as_ref() .map(|value| { conform_expr::( + ctx, value, &resolved_type, ConformMode::Normal, @@ -164,6 +166,7 @@ pub fn resolve_stmt( )?; let value = conform_expr::( + ctx, &value, &destination_expr.resolved_type, ConformMode::Normal, diff --git a/src/resolve/unify_types/mod.rs b/src/resolve/unify_types/mod.rs index 101c72e..a7a14b4 100644 --- a/src/resolve/unify_types/mod.rs +++ b/src/resolve/unify_types/mod.rs @@ -1,7 +1,10 @@ mod compute; mod integer_literals; -use super::conform::{conform_expr, ConformMode, Perform}; +use super::{ + conform::{conform_expr, ConformMode, Perform}, + expr::ResolveExprCtx, +}; use crate::{ ast::ConformBehavior, resolved::{self, TypedExpr}, @@ -10,6 +13,7 @@ use crate::{ use compute::compute_unifying_type; pub fn unify_types( + ctx: &ResolveExprCtx, preferred_type: Option<&resolved::Type>, exprs: &mut [&mut TypedExpr], behavior: ConformBehavior, @@ -24,6 +28,7 @@ pub fn unify_types( // Conform the supplied expressions if a unifying type was found for expr in exprs { **expr = match conform_expr::( + ctx, expr, &unified_type, ConformMode::Normal, diff --git a/src/resolved/mod.rs b/src/resolved/mod.rs index 6d542b1..72ab058 100644 --- a/src/resolved/mod.rs +++ b/src/resolved/mod.rs @@ -30,8 +30,8 @@ new_key_type! { pub struct FunctionRef; pub struct GlobalVarRef; pub struct StructureRef; - pub struct TypeRef; pub struct EnumRef; + pub struct TypeAliasRef; } #[derive(Clone, Debug)] @@ -42,13 +42,14 @@ pub struct Ast<'a> { pub structures: SlotMap, pub globals: SlotMap, pub enums: SlotMap, + pub type_aliases: SlotMap, pub workspace: &'a AstWorkspace<'a>, - // New Experimental Type Resolution System - pub all_types: SlotMap, pub types_per_module: HashMap>, } impl<'a> Ast<'a> { + const MAX_UNALIAS_DEPTH: usize = 1024; + pub fn new(source_files: &'a SourceFiles, workspace: &'a AstWorkspace) -> Self { Self { source_files, @@ -57,11 +58,35 @@ impl<'a> Ast<'a> { structures: SlotMap::with_key(), globals: SlotMap::with_key(), enums: SlotMap::with_key(), + type_aliases: SlotMap::with_key(), workspace, - all_types: SlotMap::with_key(), types_per_module: HashMap::new(), } } + + pub fn unalias(&'a self, mut resolved_type: &'a Type) -> Result<&'a Type, UnaliasError> { + let mut depth = 0; + + while let TypeKind::TypeAlias(_, type_alias_ref) = resolved_type.kind { + resolved_type = self + .type_aliases + .get(type_alias_ref) + .expect("valid type alias ref"); + + depth += 1; + + if depth > Self::MAX_UNALIAS_DEPTH { + return Err(UnaliasError::MaxDepthExceeded); + } + } + + Ok(resolved_type) + } +} + +#[derive(Clone, Debug)] +pub enum UnaliasError { + MaxDepthExceeded, } #[derive(Clone, Debug)] @@ -155,12 +180,6 @@ pub struct Field { pub source: Source, } -impl Display for TypeRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "TypeRef(???)") - } -} - #[derive(Clone, Debug)] pub struct Type { pub kind: TypeKind, @@ -226,7 +245,7 @@ pub enum TypeKind { FunctionPointer(FunctionPointer), Enum(HumanName, EnumRef), Structure(HumanName, StructureRef), - TypeAlias(HumanName, TypeRef), + TypeAlias(HumanName, TypeAliasRef), } impl TypeKind { @@ -351,20 +370,14 @@ impl TypeKind { | TypeKind::AnonymousEnum(_) => None, } } - - pub fn is_void_pointer(&self) -> bool { - matches!(self, TypeKind::Pointer(inner) if inner.kind.is_void()) - } } impl Display for TypeKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - TypeKind::Unresolved => panic!(), - TypeKind::TypeAlias(_, _type_ref) => todo!(), - TypeKind::Boolean => { - write!(f, "bool")?; - } + TypeKind::Unresolved => panic!("cannot display unresolved type"), + TypeKind::TypeAlias(name, _) => write!(f, "{}", name)?, + TypeKind::Boolean => write!(f, "bool")?, TypeKind::Integer(bits, sign) => { f.write_str(match (bits, sign) { (IntegerBits::Bits8, IntegerSign::Signed) => "i8", @@ -393,14 +406,14 @@ impl Display for TypeKind { } TypeKind::Void => f.write_str("void")?, TypeKind::Structure(name, _) => write!(f, "{}", name)?, - TypeKind::AnonymousStruct() => f.write_str("(anonymous struct)")?, - TypeKind::AnonymousUnion() => f.write_str("(anonymous union)")?, - TypeKind::AnonymousEnum(..) => f.write_str("(anonymous enum)")?, + TypeKind::AnonymousStruct() => f.write_str("anonymous-struct")?, + TypeKind::AnonymousUnion() => f.write_str("anonymous-union")?, + TypeKind::AnonymousEnum(..) => f.write_str("anonymous-enum")?, TypeKind::FixedArray(fixed_array) => { write!(f, "array<{}, {}>", fixed_array.size, fixed_array.inner.kind)?; } - TypeKind::FunctionPointer(..) => f.write_str("(function pointer type)")?, - TypeKind::Enum(_, type_ref) => write!(f, "(enum) {:?}", type_ref)?, + TypeKind::FunctionPointer(..) => f.write_str("function-pointer-type")?, + TypeKind::Enum(name, _) => write!(f, "{}", name)?, } Ok(()) From 682afcce1755ebfb3900145e8b38efa9efa4fd9e Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Sun, 13 Oct 2024 21:40:45 -0500 Subject: [PATCH 13/14] Improved pointer type conversions to better support type aliased void pointers --- src/resolve/conform/from_pointer.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/resolve/conform/from_pointer.rs b/src/resolve/conform/from_pointer.rs index 978bf63..6c73519 100644 --- a/src/resolve/conform/from_pointer.rs +++ b/src/resolve/conform/from_pointer.rs @@ -26,21 +26,11 @@ pub fn from_pointer( }; if from_inner_type.kind.is_void() { - return O::success(|| { - TypedExpr::new( - TypeKind::Pointer(Box::new(TypeKind::Void.at(to_type.source))).at(to_type.source), - expr.clone(), - ) - }); + return O::success(|| TypedExpr::new(to_type.clone(), expr.clone())); } if to_inner_type.kind.is_void() && mode.allow_pointer_into_void_pointer() { - return O::success(|| { - TypedExpr::new( - TypeKind::Pointer(Box::new(TypeKind::Void.at(to_type.source))).at(to_type.source), - expr.clone(), - ) - }); + return O::success(|| TypedExpr::new(to_type.clone(), expr.clone())); } O::fail() From f98e750f1289311a19e5f4f768ffe7aaa5e217d4 Mon Sep 17 00:00:00 2001 From: IsaacShelton Date: Mon, 14 Oct 2024 19:53:37 -0500 Subject: [PATCH 14/14] Updated enum member literals to work with new type resolution system --- src/resolve/conform/mod.rs | 2 +- src/resolve/expr/mod.rs | 21 +++++++-------------- src/resolve/mod.rs | 7 ------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/resolve/conform/mod.rs b/src/resolve/conform/mod.rs index 947d7bf..7e6f2f2 100644 --- a/src/resolve/conform/mod.rs +++ b/src/resolve/conform/mod.rs @@ -81,7 +81,7 @@ pub fn conform_expr( }; let Ok(to_type) = ctx.resolved_ast.unalias(to_type) else { - warn_type_alias_depth_exceeded(&expr.resolved_type); + warn_type_alias_depth_exceeded(to_type); return O::fail(); }; diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index 07ac76c..8746a69 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -358,18 +358,13 @@ pub fn resolve_expr( resolved::TypeKind::Boolean.at(source), resolved::Expr::new(resolved::ExprKind::BooleanLiteral(*value), source), )), - ast::ExprKind::EnumMemberLiteral(_enum_member_literal) => { - todo!("resolve enum member literal"); - - /* - let resolved_type = resolve_type( - ctx.type_search_ctx, + ast::ExprKind::EnumMemberLiteral(enum_member_literal) => { + let resolved_type = ctx.type_ctx().resolve( &ast::TypeKind::Named(enum_member_literal.enum_name.clone()) .at(enum_member_literal.source), - &mut Default::default(), )?; - let TypeKind::Enum(_, _) = &resolved_type.kind else { + let TypeKind::Enum(human_name, enum_ref) = &resolved_type.kind else { return Err(ResolveErrorKind::StaticMemberOfTypeDoesNotExist { ty: enum_member_literal.enum_name.to_string(), member: enum_member_literal.variant_name.clone(), @@ -377,20 +372,18 @@ pub fn resolve_expr( .at(source)); }; - let resolved_name = resolved_name.clone(); - Ok(TypedExpr::new( - resolved_type, + resolved_type.clone(), resolved::Expr::new( resolved::ExprKind::EnumMemberLiteral(Box::new(resolved::EnumMemberLiteral { - enum_name: resolved_name, + human_name: human_name.clone(), + enum_ref: *enum_ref, variant_name: enum_member_literal.variant_name.clone(), source, })), source, ), - )) - */ + )) } ast::ExprKind::InterpreterSyscall(info) => { let ast::InterpreterSyscall { diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 6b051d1..bc607dc 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -111,7 +111,6 @@ pub fn resolve<'a>( let mut type_jobs = Vec::with_capacity(ast_workspace.files.len()); - // Pre-resolve types for new type resolution system for (physical_file_id, file) in ast_workspace.files.iter() { let file_id = ast_workspace .get_owning_module(*physical_file_id) @@ -221,7 +220,6 @@ pub fn resolve<'a>( } // Create edges between types - #[allow(dead_code, unused_variables)] for job in type_jobs.iter() { let file = ast_workspace .files @@ -232,11 +230,6 @@ pub fn resolve<'a>( .get_owning_module(job.physical_file_id) .unwrap_or(job.physical_file_id); - let types = resolved_ast - .types_per_module - .entry(module_file_id) - .or_default(); - for (structure_ref, structure) in job.structures.iter().zip(file.structures.iter()) { for (field_name, field) in structure.fields.iter() { let type_ctx = ResolveTypeCtx::new(