@@ -22,7 +22,7 @@ use cairo_lang_filesystem::ids::{FileKind, FileLongId, VirtualFile};
22
22
use cairo_lang_proc_macros:: DebugWithDb ;
23
23
use cairo_lang_syntax:: node:: ast:: {
24
24
BinaryOperator , BlockOrIf , ClosureParamWrapper , ExprPtr , OptionReturnTypeClause , PatternListOr ,
25
- PatternStructParam , UnaryOperator ,
25
+ PatternStructParam , TerminalIdentifier , UnaryOperator ,
26
26
} ;
27
27
use cairo_lang_syntax:: node:: db:: SyntaxGroup ;
28
28
use cairo_lang_syntax:: node:: helpers:: { GetIdentifier , PathSegmentEx } ;
@@ -66,7 +66,7 @@ use crate::expr::inference::{ImplVarTraitItemMappings, InferenceId};
66
66
use crate :: items:: constant:: { ConstValue , resolve_const_expr_and_evaluate, validate_const_expr} ;
67
67
use crate :: items:: enm:: SemanticEnumEx ;
68
68
use crate :: items:: feature_kind:: extract_item_feature_config;
69
- use crate :: items:: functions:: function_signature_params;
69
+ use crate :: items:: functions:: { concrete_function_closure_params , function_signature_params} ;
70
70
use crate :: items:: imp:: { ImplLookupContext , filter_candidate_traits, infer_impl_by_self} ;
71
71
use crate :: items:: modifiers:: compute_mutability;
72
72
use crate :: items:: us:: get_use_path_segments;
@@ -424,7 +424,7 @@ pub fn maybe_compute_expr_semantic(
424
424
ast:: Expr :: Indexed ( expr) => compute_expr_indexed_semantic ( ctx, expr) ,
425
425
ast:: Expr :: FixedSizeArray ( expr) => compute_expr_fixed_size_array_semantic ( ctx, expr) ,
426
426
ast:: Expr :: For ( expr) => compute_expr_for_semantic ( ctx, expr) ,
427
- ast:: Expr :: Closure ( expr) => compute_expr_closure_semantic ( ctx, expr) ,
427
+ ast:: Expr :: Closure ( expr) => compute_expr_closure_semantic ( ctx, expr, None ) ,
428
428
}
429
429
}
430
430
@@ -882,7 +882,7 @@ fn compute_expr_function_call_semantic(
882
882
let mut arg_types = vec ! [ ] ;
883
883
for arg_syntax in args_iter {
884
884
let stable_ptr = arg_syntax. stable_ptr ( ) ;
885
- let arg = compute_named_argument_clause ( ctx, arg_syntax) ;
885
+ let arg = compute_named_argument_clause ( ctx, arg_syntax, None ) ;
886
886
if arg. 2 != Mutability :: Immutable {
887
887
return Err ( ctx. diagnostics . report ( stable_ptr, RefClosureArgument ) ) ;
888
888
}
@@ -930,7 +930,7 @@ fn compute_expr_function_call_semantic(
930
930
let named_args: Vec < _ > = args_syntax
931
931
. elements ( syntax_db)
932
932
. into_iter ( )
933
- . map ( |arg_syntax| compute_named_argument_clause ( ctx, arg_syntax) )
933
+ . map ( |arg_syntax| compute_named_argument_clause ( ctx, arg_syntax, None ) )
934
934
. collect ( ) ;
935
935
if named_args. len ( ) != 1 {
936
936
return Err ( ctx. diagnostics . report ( syntax, WrongNumberOfArguments {
@@ -979,16 +979,21 @@ fn compute_expr_function_call_semantic(
979
979
let mut args_iter = args_syntax. elements ( syntax_db) . into_iter ( ) ;
980
980
// Normal parameters
981
981
let mut named_args = vec ! [ ] ;
982
- for _ in function_parameter_types ( ctx, function) ? {
982
+ let closure_params = concrete_function_closure_params ( db, function) ?;
983
+ for ty in function_parameter_types ( ctx, function) ? {
983
984
let Some ( arg_syntax) = args_iter. next ( ) else {
984
985
continue ;
985
986
} ;
986
- named_args. push ( compute_named_argument_clause ( ctx, arg_syntax) ) ;
987
+ named_args. push ( compute_named_argument_clause (
988
+ ctx,
989
+ arg_syntax,
990
+ closure_params. get ( & ty) . cloned ( ) ,
991
+ ) ) ;
987
992
}
988
993
989
994
// Maybe coupon
990
995
if let Some ( arg_syntax) = args_iter. next ( ) {
991
- named_args. push ( compute_named_argument_clause ( ctx, arg_syntax) ) ;
996
+ named_args. push ( compute_named_argument_clause ( ctx, arg_syntax, None ) ) ;
992
997
}
993
998
994
999
expr_function_call ( ctx, function, named_args, syntax, syntax. stable_ptr ( ) . into ( ) )
@@ -1006,6 +1011,7 @@ fn compute_expr_function_call_semantic(
1006
1011
pub fn compute_named_argument_clause (
1007
1012
ctx : & mut ComputationContext < ' _ > ,
1008
1013
arg_syntax : ast:: Arg ,
1014
+ closure_param_types : Option < TypeId > ,
1009
1015
) -> NamedArg {
1010
1016
let syntax_db = ctx. db . upcast ( ) ;
1011
1017
@@ -1017,11 +1023,16 @@ pub fn compute_named_argument_clause(
1017
1023
1018
1024
let arg_clause = arg_syntax. arg_clause ( syntax_db) ;
1019
1025
let ( expr, arg_name_identifier) = match arg_clause {
1020
- ast:: ArgClause :: Unnamed ( arg_unnamed) => {
1021
- ( compute_expr_semantic ( ctx, & arg_unnamed. value ( syntax_db) ) , None )
1022
- }
1023
- ast:: ArgClause :: Named ( arg_named) => (
1024
- compute_expr_semantic ( ctx, & arg_named. value ( syntax_db) ) ,
1026
+ ast:: ArgClause :: Unnamed ( arg_unnamed) => handle_possible_closure_expr (
1027
+ ctx,
1028
+ & arg_unnamed. value ( syntax_db) ,
1029
+ closure_param_types,
1030
+ None ,
1031
+ ) ,
1032
+ ast:: ArgClause :: Named ( arg_named) => handle_possible_closure_expr (
1033
+ ctx,
1034
+ & arg_named. value ( syntax_db) ,
1035
+ closure_param_types,
1025
1036
Some ( arg_named. name ( syntax_db) ) ,
1026
1037
) ,
1027
1038
ast:: ArgClause :: FieldInitShorthand ( arg_field_init_shorthand) => {
@@ -1034,10 +1045,32 @@ pub fn compute_named_argument_clause(
1034
1045
( expr, Some ( arg_name_identifier) )
1035
1046
}
1036
1047
} ;
1037
-
1038
1048
NamedArg ( expr, arg_name_identifier, mutability)
1039
1049
}
1040
1050
1051
+ /// Handles the semantic computation of a closure expression.
1052
+ /// It processes a closure expression, computes its semantic model,
1053
+ /// allocates it in the expression arena, and ensures that the closure's
1054
+ /// parameter types are conformed if provided.
1055
+ fn handle_possible_closure_expr (
1056
+ ctx : & mut ComputationContext < ' _ > ,
1057
+ expr : & ast:: Expr ,
1058
+ closure_param_types : Option < TypeId > ,
1059
+ arg_name : Option < TerminalIdentifier > ,
1060
+ ) -> ( ExprAndId , Option < TerminalIdentifier > ) {
1061
+ if let ast:: Expr :: Closure ( expr_closure) = expr {
1062
+ let expr = compute_expr_closure_semantic ( ctx, expr_closure, closure_param_types) ;
1063
+ let expr = wrap_maybe_with_missing ( ctx, expr, expr_closure. stable_ptr ( ) . into ( ) ) ;
1064
+ let id = ctx. arenas . exprs . alloc ( expr. clone ( ) ) ;
1065
+ ( ExprAndId { expr, id } , arg_name)
1066
+ } else {
1067
+ let expr = compute_expr_semantic ( ctx, expr) ;
1068
+ let expr = wrap_maybe_with_missing ( ctx, Ok ( expr. expr . clone ( ) ) , expr. stable_ptr ( ) ) ;
1069
+ let id = ctx. arenas . exprs . alloc ( expr. clone ( ) ) ;
1070
+ ( ExprAndId { expr, id } , arg_name)
1071
+ }
1072
+ }
1073
+
1041
1074
pub fn compute_root_expr (
1042
1075
ctx : & mut ComputationContext < ' _ > ,
1043
1076
syntax : & ast:: ExprBlock ,
@@ -1645,6 +1678,7 @@ fn compute_loop_body_semantic(
1645
1678
fn compute_expr_closure_semantic (
1646
1679
ctx : & mut ComputationContext < ' _ > ,
1647
1680
syntax : & ast:: ExprClosure ,
1681
+ param_types : Option < TypeId > ,
1648
1682
) -> Maybe < Expr > {
1649
1683
ctx. are_closures_in_context = true ;
1650
1684
let syntax_db = ctx. db . upcast ( ) ;
@@ -1663,6 +1697,14 @@ fn compute_expr_closure_semantic(
1663
1697
} else {
1664
1698
vec ! [ ]
1665
1699
} ;
1700
+ let closure_type =
1701
+ TypeLongId :: Tuple ( params. iter ( ) . map ( |param| param. ty ) . collect ( ) ) . intern ( new_ctx. db ) ;
1702
+ if let Some ( param_types) = param_types {
1703
+ if let Err ( err_set) = new_ctx. resolver . inference ( ) . conform_ty ( closure_type, param_types)
1704
+ {
1705
+ new_ctx. resolver . inference ( ) . consume_error_without_reporting ( err_set) ;
1706
+ }
1707
+ }
1666
1708
1667
1709
params. iter ( ) . filter ( |param| param. mutability == Mutability :: Reference ) . for_each ( |param| {
1668
1710
new_ctx. diagnostics . report ( param. stable_ptr ( ctx. db . upcast ( ) ) , RefClosureParam ) ;
@@ -2834,16 +2876,22 @@ fn method_call_expr(
2834
2876
// Self argument.
2835
2877
let mut named_args = vec ! [ NamedArg ( fixed_lexpr, None , mutability) ] ;
2836
2878
// Other arguments.
2837
- for _ in function_parameter_types ( ctx, function_id) ?. skip ( 1 ) {
2879
+ let closure_params: OrderedHashMap < TypeId , TypeId > =
2880
+ concrete_function_closure_params ( ctx. db , function_id) ?;
2881
+ for ty in function_parameter_types ( ctx, function_id) ?. skip ( 1 ) {
2838
2882
let Some ( arg_syntax) = args_iter. next ( ) else {
2839
2883
break ;
2840
2884
} ;
2841
- named_args. push ( compute_named_argument_clause ( ctx, arg_syntax) ) ;
2885
+ named_args. push ( compute_named_argument_clause (
2886
+ ctx,
2887
+ arg_syntax,
2888
+ closure_params. get ( & ty) . cloned ( ) ,
2889
+ ) ) ;
2842
2890
}
2843
2891
2844
2892
// Maybe coupon
2845
2893
if let Some ( arg_syntax) = args_iter. next ( ) {
2846
- named_args. push ( compute_named_argument_clause ( ctx, arg_syntax) ) ;
2894
+ named_args. push ( compute_named_argument_clause ( ctx, arg_syntax, None ) ) ;
2847
2895
}
2848
2896
2849
2897
expr_function_call ( ctx, function_id, named_args, & expr, stable_ptr)
0 commit comments