diff --git a/src/resolve/expr/basic_binary_operation.rs b/src/resolve/expr/basic_binary_operation.rs index 8eab22e..d0175bc 100644 --- a/src/resolve/expr/basic_binary_operation.rs +++ b/src/resolve/expr/basic_binary_operation.rs @@ -95,7 +95,7 @@ pub fn resolve_basic_binary_operator( ast::BasicBinaryOperator::Add => NumericMode::try_new(resolved_type) .map(resolved::BasicBinaryOperator::Add) .or_else(|| { - ctx.constraints + ctx.current_constraints .satisfies(resolved_type, &Constraint::PrimitiveAdd) .then(|| resolved::BasicBinaryOperator::PrimitiveAdd(resolved_type.clone())) }), diff --git a/src/resolve/expr/mod.rs b/src/resolve/expr/mod.rs index f278d93..66f1e3b 100644 --- a/src/resolve/expr/mod.rs +++ b/src/resolve/expr/mod.rs @@ -59,7 +59,7 @@ pub struct ResolveExprCtx<'a, 'b> { pub helper_exprs_in_modules: &'b HashMap>, pub module_fs_node_id: FsNodeId, pub physical_fs_node_id: FsNodeId, - pub constraints: CurrentConstraints, + pub current_constraints: CurrentConstraints, } impl<'a, 'b> ResolveExprCtx<'a, 'b> { diff --git a/src/resolve/function_body.rs b/src/resolve/function_body.rs index 1f4357e..17afebc 100644 --- a/src/resolve/function_body.rs +++ b/src/resolve/function_body.rs @@ -70,7 +70,7 @@ pub fn resolve_function_bodies( helper_exprs_in_modules: &mut ctx.helper_exprs_in_modules, module_fs_node_id: module_file_id, physical_fs_node_id: physical_file_id, - constraints, + current_constraints: constraints, }, &ast_function.stmts, )?; @@ -98,11 +98,14 @@ fn resolve_parameter_variables( let mut variable_haystack = VariableHaystack::new(); for parameter in ast_function.parameters.required.iter() { + let function = resolved_ast.functions.get(resolved_function_ref).unwrap(); + let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, physical_file_id, &ctx.types_in_modules, + &function.constraints, ); let mut resolved_type = type_ctx.resolve(¶meter.ast_type)?; diff --git a/src/resolve/function_head.rs b/src/resolve/function_head.rs index 5ed59ee..2a5a5f8 100644 --- a/src/resolve/function_head.rs +++ b/src/resolve/function_head.rs @@ -25,11 +25,17 @@ pub fn create_function_heads( for (function_i, function) in file.functions.iter().enumerate() { let name = ResolvedName::new(module_file_id, &function.name); + + let fake_constraints = CurrentConstraints { + constraints: Default::default(), + }; + let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, *physical_file_id, &ctx.types_in_modules, + &fake_constraints, ); let is_generic = function.return_type.contains_polymorph().is_some() @@ -125,7 +131,7 @@ pub fn create_function_heads( Ok(()) } -fn collect_constraints(map: &mut HashMap>, ty: &resolved::Type) { +pub fn collect_constraints(map: &mut HashMap>, ty: &resolved::Type) { match &ty.kind { resolved::TypeKind::Unresolved => panic!(), resolved::TypeKind::Boolean diff --git a/src/resolve/global_variable.rs b/src/resolve/global_variable.rs index d2bb9cb..2a459f7 100644 --- a/src/resolve/global_variable.rs +++ b/src/resolve/global_variable.rs @@ -2,7 +2,7 @@ use super::{ctx::ResolveCtx, error::ResolveError, type_ctx::ResolveTypeCtx}; use crate::{ ast::AstWorkspace, name::{Name, ResolvedName}, - resolved::{self, GlobalVarDecl}, + resolved::{self, CurrentConstraints, GlobalVarDecl}, }; pub fn resolve_global_variables( @@ -10,6 +10,8 @@ pub fn resolve_global_variables( resolved_ast: &mut resolved::Ast, ast_workspace: &AstWorkspace, ) -> Result<(), ResolveError> { + let constraints = CurrentConstraints::default(); + for (physical_file_id, file) in ast_workspace.files.iter() { let module_file_id = ast_workspace .get_owning_module(*physical_file_id) @@ -21,6 +23,7 @@ pub fn resolve_global_variables( module_file_id, *physical_file_id, &ctx.types_in_modules, + &constraints, ); let resolved_type = type_ctx.resolve(&global.ast_type)?; diff --git a/src/resolve/helper_expr.rs b/src/resolve/helper_expr.rs index 44b57fb..c83ffb0 100644 --- a/src/resolve/helper_expr.rs +++ b/src/resolve/helper_expr.rs @@ -43,7 +43,7 @@ pub fn resolve_helper_expressions( helper_exprs_in_modules: &ctx.helper_exprs_in_modules, module_fs_node_id: module_file_id, physical_fs_node_id: *physical_file_id, - constraints: CurrentConstraints { + current_constraints: CurrentConstraints { constraints: Default::default(), }, }; diff --git a/src/resolve/polymorph.rs b/src/resolve/polymorph.rs index e807717..b6cff6c 100644 --- a/src/resolve/polymorph.rs +++ b/src/resolve/polymorph.rs @@ -240,7 +240,7 @@ impl PolyCatalog { self.put_type(name, concrete_type).map_err(Some)?; for constraint in constraints { - if !ctx.constraints.satisfies(concrete_type, constraint) { + if !ctx.current_constraints.satisfies(concrete_type, constraint) { return Err(None); } } diff --git a/src/resolve/type_ctx/find.rs b/src/resolve/type_ctx/find.rs index 8941cc2..c97b511 100644 --- a/src/resolve/type_ctx/find.rs +++ b/src/resolve/type_ctx/find.rs @@ -24,12 +24,6 @@ impl<'a> ResolveTypeCtx<'a> { .expect("valid settings id") .0]; - if !arguments.is_empty() { - eprintln!( - "warning: ResolveTypeCtx does not properly handle constraints for compile time arguments yet" - ); - } - if let Some(decl) = name .as_plain_str() .and_then(|name| { diff --git a/src/resolve/type_ctx/mod.rs b/src/resolve/type_ctx/mod.rs index 5717a62..fc0dcfa 100644 --- a/src/resolve/type_ctx/mod.rs +++ b/src/resolve/type_ctx/mod.rs @@ -9,7 +9,7 @@ use super::{ use crate::{ ast, name::ResolvedName, - resolved::{self, Constraint}, + resolved::{self, Constraint, CurrentConstraints}, workspace::fs::FsNodeId, }; use std::collections::{HashMap, HashSet}; @@ -21,6 +21,7 @@ pub struct ResolveTypeCtx<'a> { file_fs_node_id: FsNodeId, types_in_modules: &'a HashMap>, used_aliases_stack: HashSet, + current_constraints: &'a CurrentConstraints, } impl<'a> ResolveTypeCtx<'a> { @@ -29,6 +30,7 @@ impl<'a> ResolveTypeCtx<'a> { module_fs_node_id: FsNodeId, file_fs_node_id: FsNodeId, types_in_modules: &'a HashMap>, + current_constraints: &'a CurrentConstraints, ) -> Self { Self { resolved_ast, @@ -36,6 +38,7 @@ impl<'a> ResolveTypeCtx<'a> { file_fs_node_id, types_in_modules, used_aliases_stack: Default::default(), + current_constraints, } } } @@ -47,6 +50,7 @@ impl<'a, 'b, 'c> From<&'c ResolveExprCtx<'a, 'b>> for ResolveTypeCtx<'c> { ctx.module_fs_node_id, ctx.physical_fs_node_id, ctx.types_in_modules, + &ctx.current_constraints, ) } } diff --git a/src/resolve/type_ctx/resolve_type.rs b/src/resolve/type_ctx/resolve_type.rs index 3a29123..634fa5f 100644 --- a/src/resolve/type_ctx/resolve_type.rs +++ b/src/resolve/type_ctx/resolve_type.rs @@ -3,7 +3,7 @@ use crate::{ ast::{self, IntegerBits}, ir::IntegerSign, resolve::error::{ResolveError, ResolveErrorKind}, - resolved::{self, CurrentConstraints}, + resolved::{self}, source_files::Source, }; use std::borrow::Borrow; @@ -45,9 +45,18 @@ impl<'a> ResolveTypeCtx<'a> { .get(*structure_ref) .expect("referenced struct to exist"); - for (name, parameter) in structure.parameters.parameters.iter() { + assert!(arguments.len() == structure.parameters.len()); + + for (parameter, argument) in + structure.parameters.parameters.values().zip(arguments) + { for constraint in ¶meter.constraints { - todo!("enforce type constraints for structure type usage") + if !self.current_constraints.satisfies(argument, constraint) { + return Err(ResolveErrorKind::ConstraintsNotSatisfiedForType { + name: name.to_string(), + } + .at(ast_type.source)); + } } } } diff --git a/src/resolve/type_definition/resolve.rs b/src/resolve/type_definition/resolve.rs index 0f1f2b4..1f49825 100644 --- a/src/resolve/type_definition/resolve.rs +++ b/src/resolve/type_definition/resolve.rs @@ -1,10 +1,18 @@ use crate::{ ast::{self, AstWorkspace}, - resolve::{ctx::ResolveCtx, error::ResolveError, job::TypeJob, type_ctx::ResolveTypeCtx}, - resolved::{self, EnumRef, StructureRef, TypeAliasRef}, + resolve::{ + ctx::ResolveCtx, + error::ResolveError, + job::TypeJob, + type_ctx::{resolve_constraints, ResolveTypeCtx}, + }, + resolved::{self, CurrentConstraints, EnumRef, StructureRef, TypeAliasRef}, workspace::fs::FsNodeId, }; -use std::borrow::Cow; +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, +}; pub fn resolve_type_jobs( ctx: &mut ResolveCtx, @@ -68,11 +76,23 @@ fn resolve_structure( structure_ref: StructureRef, ) -> Result<(), ResolveError> { for (field_name, field) in structure.fields.iter() { + let mut constraints = HashMap::new(); + + for (name, parameter) in structure.parameters.iter() { + constraints.insert( + name.into(), + HashSet::from_iter(resolve_constraints(¶meter.constraints)?.drain(..)), + ); + } + + let constraints = CurrentConstraints { constraints }; + let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, physical_file_id, &ctx.types_in_modules, + &constraints, ); let resolved_type = type_ctx.resolve_or_undeclared(&field.ast_type)?; @@ -103,11 +123,13 @@ fn resolve_enum( definition: &ast::Enum, enum_ref: EnumRef, ) -> Result<(), ResolveError> { + let constraints = CurrentConstraints::default(); let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, physical_file_id, &ctx.types_in_modules, + &constraints, ); let ast_type = definition @@ -129,11 +151,14 @@ fn resolve_type_alias( definition: &ast::TypeAlias, type_alias_ref: TypeAliasRef, ) -> Result<(), ResolveError> { + let constraints = CurrentConstraints::default(); + let type_ctx = ResolveTypeCtx::new( &resolved_ast, module_file_id, physical_file_id, &ctx.types_in_modules, + &constraints, ); let resolved_type = type_ctx.resolve_or_undeclared(&definition.value)?; diff --git a/src/resolved/function.rs b/src/resolved/function.rs index 2e431bd..6f75b03 100644 --- a/src/resolved/function.rs +++ b/src/resolved/function.rs @@ -1,7 +1,7 @@ use crate::{name::ResolvedName, resolved::*, source_files::Source, tag::Tag}; use std::{collections::HashSet, fmt::Display}; -#[derive(Debug, Clone)] +#[derive(Clone, Debug, Default)] pub struct CurrentConstraints { pub constraints: HashMap>, } @@ -11,10 +11,13 @@ impl CurrentConstraints { match constraint { Constraint::PrimitiveAdd => match &ty.kind { TypeKind::Integer(..) | TypeKind::CInteger(..) | TypeKind::Floating(..) => true, - TypeKind::Polymorph(name, _) => self - .constraints - .get(name) - .map_or(false, |set| set.contains(constraint)), + TypeKind::Polymorph(name, constraints) => { + constraints.contains(constraint) + || self + .constraints + .get(name) + .map_or(false, |in_scope| in_scope.contains(constraint)) + } _ => false, }, }