@@ -1926,6 +1926,8 @@ do_type_check_expr(Env, {lc, _, Expr, Qualifiers}) ->
19261926 type_check_comprehension (Env , lc , Expr , Qualifiers );
19271927do_type_check_expr (Env , {bc , _ , Expr , Qualifiers }) ->
19281928 type_check_comprehension (Env , bc , Expr , Qualifiers );
1929+ do_type_check_expr (Env , {mc , _ , Assoc , Qualifiers }) ->
1930+ type_check_comprehension (Env , mc , Assoc , Qualifiers );
19291931do_type_check_expr (Env , {block , _ , Block }) ->
19301932 type_check_block (Env , Block );
19311933
@@ -2505,6 +2507,11 @@ type_check_comprehension(Env, lc, Expr, []) ->
25052507 {Ty , _VB } = type_check_expr (Env , Expr ),
25062508 RetTy = {type , erl_anno :new (0 ), list , [Ty ]},
25072509 {RetTy , Env };
2510+ type_check_comprehension (Env , mc , {map_field_assoc , _ , KeyExpr , ValExpr }, []) ->
2511+ {KeyTy , _VB1 } = type_check_expr (Env , KeyExpr ),
2512+ {ValTy , _VB2 } = type_check_expr (Env , ValExpr ),
2513+ RetTy = type (map , [type_assoc (map_field_assoc , [KeyTy , ValTy ])]),
2514+ {RetTy , Env };
25082515type_check_comprehension (Env , bc , Expr , []) ->
25092516 {Ty , _VB } = type_check_expr (Env , Expr ),
25102517 RetTy = case normalize (Ty , Env ) of
@@ -2566,6 +2573,30 @@ type_check_comprehension(Env, Compr, Expr, [{BGenerateTag, _P, Pat, Gen} | Quals
25662573 {TyL , VarBinds2 } =
25672574 type_check_comprehension (NewEnv , Compr , Expr , Quals ),
25682575 {TyL , union_var_binds (VarBinds1 , VarBinds2 , Env )};
2576+ type_check_comprehension (Env , Compr , Expr , [{MGenerateTag , _ , {map_field_exact , _ , KeyPat , ValPat }, Gen } | Quals ])
2577+ when MGenerateTag =:= m_generate ; MGenerateTag =:= m_generate_strict ->
2578+ {Ty , _VB1 } = type_check_expr (Env , Gen ),
2579+ % % Generator patterns create fresh variable bindings (shadow outer vars)
2580+ GenEnv = remove_pat_vars (KeyPat , remove_pat_vars (ValPat , Env )),
2581+ case expect_map_type (normalize (Ty , Env ), Env ) of
2582+ {assoc_tys , AssocTys } when is_list (AssocTys ) ->
2583+ {KeyTys , ValTys } = lists :foldl (
2584+ fun ({type , _ , _AssocTag , [KT , VT ]}, {KAcc , VAcc }) ->
2585+ {[KT | KAcc ], [VT | VAcc ]}
2586+ end , {[], []}, AssocTys ),
2587+ KeyTy = normalize (type (union , KeyTys ), Env ),
2588+ ValTy = normalize (type (union , ValTys ), Env ),
2589+ {_PatTys1 , _UBounds1 , Env1 } =
2590+ add_types_pats ([KeyPat ], [KeyTy ], GenEnv , capture_vars ),
2591+ {_PatTys2 , _UBounds2 , NewEnv } =
2592+ add_types_pats ([ValPat ], [ValTy ], Env1 , capture_vars ),
2593+ type_check_comprehension (NewEnv , Compr , Expr , Quals );
2594+ any ->
2595+ NewEnv = add_any_types_pat (ValPat , add_any_types_pat (KeyPat , GenEnv )),
2596+ type_check_comprehension (NewEnv , Compr , Expr , Quals );
2597+ {type_error , BadTy } ->
2598+ throw (type_error (Gen , BadTy , type (map )))
2599+ end ;
25692600type_check_comprehension (Env , Compr , Expr , [Guard | Quals ]) ->
25702601 % % We don't require guards to return a boolean.
25712602 % % This decision is up for debate.
@@ -2825,6 +2856,8 @@ do_type_check_expr_in(Env, ResTy, {lc, P, Expr, Qualifiers} = OrigExpr) ->
28252856 type_check_comprehension_in (Env , ResTy , OrigExpr , lc , Expr , P , Qualifiers );
28262857do_type_check_expr_in (Env , ResTy , {bc , P , Expr , Qualifiers } = OrigExpr ) ->
28272858 type_check_comprehension_in (Env , ResTy , OrigExpr , bc , Expr , P , Qualifiers );
2859+ do_type_check_expr_in (Env , ResTy , {mc , P , Assoc , Qualifiers } = OrigExpr ) ->
2860+ type_check_comprehension_in (Env , ResTy , OrigExpr , mc , Assoc , P , Qualifiers );
28282861
28292862% % Functions
28302863do_type_check_expr_in (Env , Ty , {'fun' , _ , {clauses , Clauses }} = Fun ) ->
@@ -3279,14 +3312,15 @@ unary_op_arg_type('-', Ty = {type, _, float, []}) ->
32793312- spec type_check_comprehension_in (Env :: env (),
32803313 ResTy :: type (),
32813314 OrigExpr :: gradualizer_type :abstract_expr (),
3282- Compr :: lc | bc ,
3315+ Compr :: lc | bc | mc ,
32833316 Expr :: gradualizer_type :abstract_expr (),
32843317 Position :: erl_anno :anno (),
3285- Qualifiers :: [ListGen | BinGen | Filter ]) ->
3318+ Qualifiers :: [ListGen | BinGen | MapGen | Filter ]) ->
32863319 env ()
32873320 when
32883321 ListGen :: {generate | generate_strict , erl_anno :anno (), gradualizer_type :abstract_expr (), gradualizer_type :abstract_expr ()},
32893322 BinGen :: {b_generate | b_generate_strict , erl_anno :anno (), gradualizer_type :abstract_expr (), gradualizer_type :abstract_expr ()},
3323+ MapGen :: {m_generate | m_generate_strict , erl_anno :anno (), gradualizer_type :abstract_expr (), gradualizer_type :abstract_expr ()},
32903324 Filter :: gradualizer_type :abstract_expr ().
32913325type_check_comprehension_in (Env , ResTy , OrigExpr , lc , Expr , _P , []) ->
32923326 case expect_list_type (ResTy , allow_nil_type , Env ) of
@@ -3335,6 +3369,52 @@ type_check_comprehension_in(Env, ResTy, OrigExpr, bc, Expr, _P, []) ->
33353369 {type_error , Ty } ->
33363370 throw ({type_error , OrigExpr , Ty , ResTy })
33373371 end ;
3372+ type_check_comprehension_in (Env , ResTy , OrigExpr , mc ,
3373+ {map_field_assoc , _ , KeyExpr , ValExpr }, _P , []) ->
3374+ case expect_map_type (normalize (ResTy , Env ), Env ) of
3375+ any ->
3376+ {_KeyTy , _VB1 } = type_check_expr (Env , KeyExpr ),
3377+ {_ValTy , _VB2 } = type_check_expr (Env , ValExpr ),
3378+ Env ;
3379+ {assoc_tys , AssocTys } when is_list (AssocTys ) ->
3380+ {KeyTys , ValTys } = lists :foldl (
3381+ fun ({type , _ , _AssocTag , [KT , VT ]}, {KAcc , VAcc }) ->
3382+ {[KT | KAcc ], [VT | VAcc ]}
3383+ end , {[], []}, AssocTys ),
3384+ KeyTy = normalize (type (union , KeyTys ), Env ),
3385+ ValTy = normalize (type (union , ValTys ), Env ),
3386+ _VB1 = type_check_expr_in (Env , KeyTy , KeyExpr ),
3387+ _VB2 = type_check_expr_in (Env , ValTy , ValExpr ),
3388+ Env ;
3389+ {type_error , _ } ->
3390+ throw (type_error (OrigExpr , type (map ), ResTy ))
3391+ end ;
3392+ type_check_comprehension_in (Env , ResTy , OrigExpr , Compr , Expr , P ,
3393+ [{MGenerateTag , _ , {map_field_exact , _ , KeyPat , ValPat }, Gen } | Quals ])
3394+ when MGenerateTag =:= m_generate ; MGenerateTag =:= m_generate_strict ->
3395+ {Ty , _VB1 } = type_check_expr (Env , Gen ),
3396+ GenEnv = remove_pat_vars (KeyPat , remove_pat_vars (ValPat , Env )),
3397+ case expect_map_type (normalize (Ty , Env ), Env ) of
3398+ any ->
3399+ NewEnv = add_any_types_pat (ValPat , add_any_types_pat (KeyPat , GenEnv )),
3400+ _VB2 = type_check_comprehension_in (NewEnv , ResTy , OrigExpr , Compr , Expr , P , Quals ),
3401+ Env ;
3402+ {assoc_tys , AssocTys } when is_list (AssocTys ) ->
3403+ {KeyTys , ValTys } = lists :foldl (
3404+ fun ({type , _ , _AssocTag , [KT , VT ]}, {KAcc , VAcc }) ->
3405+ {[KT | KAcc ], [VT | VAcc ]}
3406+ end , {[], []}, AssocTys ),
3407+ KeyTy = normalize (type (union , KeyTys ), Env ),
3408+ ValTy = normalize (type (union , ValTys ), Env ),
3409+ {_PatTys1 , _UBounds1 , Env1 } =
3410+ add_types_pats ([KeyPat ], [KeyTy ], GenEnv , capture_vars ),
3411+ {_PatTys2 , _UBounds2 , NewEnv } =
3412+ add_types_pats ([ValPat ], [ValTy ], Env1 , capture_vars ),
3413+ _VB2 = type_check_comprehension_in (NewEnv , ResTy , OrigExpr , Compr , Expr , P , Quals ),
3414+ Env ;
3415+ {type_error , BadTy } ->
3416+ throw (type_error (Gen , BadTy , type (map )))
3417+ end ;
33383418type_check_comprehension_in (Env , ResTy , OrigExpr , Compr , Expr , P ,
33393419 [{GenerateTag , _ , Pat , Gen } | Quals ])
33403420 when GenerateTag =:= generate ; GenerateTag =:= generate_strict ->
0 commit comments