Stabel

Check-in [493d6a6a8b]
Login
Overview
Comment:Qualifier now respects (non-)exposed types.
Timelines: family | ancestors | descendants | both | module-definition
Files: files | file ages | folders
SHA3-256: 493d6a6a8bbd341cc676bf141856c4859c48d12c3e07f4bf341bc9e229ea53ff
User & Date: robin.hansen on 2021-05-27 09:48:30
Other Links: branch diff | manifest | tags
Context
2021-05-27
09:57
Added module definition to stdlib/core, and parsing fails. Needs investigation. check-in: 1e4ca8b20d user: robin.hansen tags: module-definition
09:48
Qualifier now respects (non-)exposed types. check-in: 493d6a6a8b user: robin.hansen tags: module-definition
2021-05-26
18:26
Add 'exposed' field to qualified ast types. check-in: a093546b3d user: robin.hansen tags: module-definition
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/Qualifier.elm from [63ed9445bb] to [44d7d10703].

279
280
281
282
283
284
285
286



287
288
289
290
291
292
293
294



295
296
297
298
299
300
301
...
385
386
387
388
389
390
391
392



393
394
395
396
397
398
399
400



401
402
403
404
405
406
407
...
666
667
668
669
670
671
672
673



674
675
676
677
678
679
680
...
701
702
703
704
705
706
707
708



709
710
711
712
713
714
715

                bindResult =
                    binds
                        |> List.map (qualifyMemberType config modRefs range)
                        |> Result.combine
            in
            case ( Dict.get qualifiedName config.inProgressAST.types, bindResult ) of
                ( Just (CustomTypeDef _ _ _ [] _), _ ) ->



                    Ok <| Type.Custom qualifiedName

                ( Just (CustomTypeDef _ _ _ _ _), Ok qualifiedBinds ) ->
                    Ok <| Type.CustomGeneric qualifiedName qualifiedBinds

                ( Just (UnionTypeDef _ _ _ _ memberTypes), _ ) ->
                    Ok <| Type.Union memberTypes




                _ ->
                    Err <| UnknownTypeRef range qualifiedName

        importsLookup name binds =
            case resolveImportedType config modRefs name of
                Just importedModule ->
                    if String.startsWith "/" importedModule then
................................................................................

                bindResult =
                    binds
                        |> List.map (qualifyMemberType config modRefs range)
                        |> Result.combine
            in
            case ( Dict.get qualifiedName config.inProgressAST.types, bindResult ) of
                ( Just (CustomTypeDef _ _ _ [] _), _ ) ->



                    Ok <| Type.Custom qualifiedName

                ( Just (CustomTypeDef _ _ _ _ _), Ok qualifiedBinds ) ->
                    Ok <| Type.CustomGeneric qualifiedName qualifiedBinds

                ( Just (UnionTypeDef _ _ _ _ memberTypes), _ ) ->
                    Ok <| Type.Union memberTypes




                _ ->
                    Err <| UnknownTypeRef range qualifiedName

        Parser.Generic sym ->
            Ok (Type.Generic sym)

        Parser.StackRange sym ->
................................................................................
    -> ModuleReferences
    -> Parser.TypeMatch
    -> Result Problem TypeMatch
qualifyMatch config qualifiedTypes modRefs typeMatch =
    let
        qualifiedNameToMatch range name patterns =
            case Dict.get name qualifiedTypes of
                Just (CustomTypeDef _ _ _ gens members) ->



                    let
                        memberNames =
                            members
                                |> List.map Tuple.first
                                |> Set.fromList

                        qualifiedPatternsResult =
................................................................................
                    case qualifiedPatternsResult of
                        Ok qualifiedPatterns ->
                            Ok <| TypeMatch range actualType qualifiedPatterns

                        Err err ->
                            Err err

                Just (UnionTypeDef _ _ _ _ types) ->



                    if List.isEmpty patterns then
                        Ok <| TypeMatch range (Type.Union types) []

                    else
                        Err <| UnionTypeMatchWithPatterns range

                Nothing ->







|
>
>
>


|


|


>
>
>







 







|
>
>
>


|


|


>
>
>







 







|
>
>
>







 







|
>
>
>







279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
...
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733

                bindResult =
                    binds
                        |> List.map (qualifyMemberType config modRefs range)
                        |> Result.combine
            in
            case ( Dict.get qualifiedName config.inProgressAST.types, bindResult ) of
                ( Just (CustomTypeDef _ False _ _ _), _ ) ->
                    Err <| TypeNotExposed range qualifiedName

                ( Just (CustomTypeDef _ True _ [] _), _ ) ->
                    Ok <| Type.Custom qualifiedName

                ( Just (CustomTypeDef _ True _ _ _), Ok qualifiedBinds ) ->
                    Ok <| Type.CustomGeneric qualifiedName qualifiedBinds

                ( Just (UnionTypeDef _ True _ _ memberTypes), _ ) ->
                    Ok <| Type.Union memberTypes

                ( Just (UnionTypeDef _ False _ _ _), _ ) ->
                    Err <| TypeNotExposed range qualifiedName

                _ ->
                    Err <| UnknownTypeRef range qualifiedName

        importsLookup name binds =
            case resolveImportedType config modRefs name of
                Just importedModule ->
                    if String.startsWith "/" importedModule then
................................................................................

                bindResult =
                    binds
                        |> List.map (qualifyMemberType config modRefs range)
                        |> Result.combine
            in
            case ( Dict.get qualifiedName config.inProgressAST.types, bindResult ) of
                ( Just (CustomTypeDef _ False _ _ _), _ ) ->
                    Err <| TypeNotExposed range qualifiedName

                ( Just (CustomTypeDef _ True _ [] _), _ ) ->
                    Ok <| Type.Custom qualifiedName

                ( Just (CustomTypeDef _ True _ _ _), Ok qualifiedBinds ) ->
                    Ok <| Type.CustomGeneric qualifiedName qualifiedBinds

                ( Just (UnionTypeDef _ True _ _ memberTypes), _ ) ->
                    Ok <| Type.Union memberTypes

                ( Just (UnionTypeDef _ False _ _ _), _ ) ->
                    Err <| TypeNotExposed range qualifiedName

                _ ->
                    Err <| UnknownTypeRef range qualifiedName

        Parser.Generic sym ->
            Ok (Type.Generic sym)

        Parser.StackRange sym ->
................................................................................
    -> ModuleReferences
    -> Parser.TypeMatch
    -> Result Problem TypeMatch
qualifyMatch config qualifiedTypes modRefs typeMatch =
    let
        qualifiedNameToMatch range name patterns =
            case Dict.get name qualifiedTypes of
                Just (CustomTypeDef _ False _ _ _) ->
                    Err <| TypeNotExposed range name

                Just (CustomTypeDef _ True _ gens members) ->
                    let
                        memberNames =
                            members
                                |> List.map Tuple.first
                                |> Set.fromList

                        qualifiedPatternsResult =
................................................................................
                    case qualifiedPatternsResult of
                        Ok qualifiedPatterns ->
                            Ok <| TypeMatch range actualType qualifiedPatterns

                        Err err ->
                            Err err

                Just (UnionTypeDef _ False _ _ _) ->
                    Err <| TypeNotExposed range name

                Just (UnionTypeDef _ True _ _ types) ->
                    if List.isEmpty patterns then
                        Ok <| TypeMatch range (Type.Union types) []

                    else
                        Err <| UnionTypeMatchWithPatterns range

                Nothing ->

Modified src/Play/Qualifier/Problem.elm from [9c7d2aaeb2] to [cf36a1d3b1].

9
10
11
12
13
14
15

16
17
18
19
20
21
22
..
52
53
54
55
56
57
58







type Problem
    = UnknownWordRef SourceLocationRange String
    | UnknownTypeRef SourceLocationRange String
    | UnionTypeMatchWithPatterns SourceLocationRange
    | InvalidTypeMatch SourceLocationRange
    | NoSuchMemberOnType SourceLocationRange String String
    | WordNotExposed SourceLocationRange String



toString : String -> Problem -> String
toString source problem =
    case problem of
        UnknownWordRef range wordRef ->
            SourceLocation.extractFromString source range
................................................................................

        WordNotExposed range wordRef ->
            SourceLocation.extractFromString source range
                ++ "\n\n"
                ++ "Trying to call '"
                ++ wordRef
                ++ "' but this function is not exposed."














>







 







>
>
>
>
>
>
>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
type Problem
    = UnknownWordRef SourceLocationRange String
    | UnknownTypeRef SourceLocationRange String
    | UnionTypeMatchWithPatterns SourceLocationRange
    | InvalidTypeMatch SourceLocationRange
    | NoSuchMemberOnType SourceLocationRange String String
    | WordNotExposed SourceLocationRange String
    | TypeNotExposed SourceLocationRange String


toString : String -> Problem -> String
toString source problem =
    case problem of
        UnknownWordRef range wordRef ->
            SourceLocation.extractFromString source range
................................................................................

        WordNotExposed range wordRef ->
            SourceLocation.extractFromString source range
                ++ "\n\n"
                ++ "Trying to call '"
                ++ wordRef
                ++ "' but this function is not exposed."

        TypeNotExposed range typeRef ->
            SourceLocation.extractFromString source range
                ++ "\n\n"
                ++ "Referencing '"
                ++ typeRef
                ++ "' but this type is not exposed."

Modified tests/Test/Qualifier.elm from [6fde867bdb] to [1c4662c71d].

1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194



1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205






1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
....
2633
2634
2635
2636
2637
2638
2639
2640
2641




















2642

2643

















































































































































































































































































                                    ]
                            }
                in
                Expect.equal expectedRequiredModules actualRequiredModules
        , describe "Module resolution" <|
            let
                dummyWord name =
                    ( name
                    , { name = name
                      , metadata = Metadata.default
                      , implementation =
                            SoloImpl []
                      }
                    )

                dummyWordUnexposed name =



                    ( name
                    , { name = name
                      , metadata =
                            Metadata.default
                                |> Metadata.isExposed False
                      , implementation =
                            SoloImpl []
                      }
                    )

                dummyType name =






                    let
                        genericName =
                            name ++ "Generic"

                        unionName =
                            name ++ "Union"
                    in
                    [ ( name
                      , CustomTypeDef name True emptyRange [] []
                      )
                    , ( genericName
                      , CustomTypeDef genericName True emptyRange [ "a" ] []
                      )
                    , ( unionName
                      , UnionTypeDef unionName
                            True
                            emptyRange
                            []
                            [ Type.Custom name
                            , Type.CustomGeneric genericName [ Type.Generic "a" ]
                            ]
                      )
                    ]
................................................................................
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed function is called"

                        Err [ Problem.WordNotExposed _ "/external/package/mod/add" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs




















            ]

        ]
























































































































































































































































































|
<
<
<
<
|
<
<

>
>
>




|






>
>
>
>
>
>








|


|



|







 









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1179
1180
1181
1182
1183
1184
1185
1186




1187


1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
....
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
                                    ]
                            }
                in
                Expect.equal expectedRequiredModules actualRequiredModules
        , describe "Module resolution" <|
            let
                dummyWord name =
                    dummyWordImpl name True







                dummyWordUnexposed name =
                    dummyWordImpl name False

                dummyWordImpl name isExposed =
                    ( name
                    , { name = name
                      , metadata =
                            Metadata.default
                                |> Metadata.isExposed isExposed
                      , implementation =
                            SoloImpl []
                      }
                    )

                dummyType name =
                    dummyTypeImpl name True

                dummyTypeUnexposed name =
                    dummyTypeImpl name False

                dummyTypeImpl name isExposed =
                    let
                        genericName =
                            name ++ "Generic"

                        unionName =
                            name ++ "Union"
                    in
                    [ ( name
                      , CustomTypeDef name isExposed emptyRange [] []
                      )
                    , ( genericName
                      , CustomTypeDef genericName isExposed emptyRange [ "a" ] []
                      )
                    , ( unionName
                      , UnionTypeDef unionName
                            isExposed
                            emptyRange
                            []
                            [ Type.Custom name
                            , Type.CustomGeneric genericName [ Type.Generic "a" ]
                            ]
                      )
                    ]
................................................................................
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed function is called"

                        Err [ Problem.WordNotExposed _ "/external/package/mod/add" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type signature from an external module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature =
                                            AST.UserProvided
                                                { input = [ AST.ExternalRef [ "mod" ] "Tipe" [] ]
                                                , output = []
                                                }
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.SoloImpl
                                                [ AST.Word emptyRange "drop"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "/external/package/mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules =
                                    Dict.fromList
                                        [ ( "/mod", "external/package" ) ]
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "/external/package/mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type definition from an external module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types =
                                Dict.fromList
                                    [ ( "BoxedTipe"
                                      , AST.CustomTypeDef
                                            emptyRange
                                            "BoxedTipe"
                                            []
                                            [ ( "value", AST.ExternalRef [ "mod" ] "TipeUnion" [] ) ]
                                      )
                                    ]
                            , words = Dict.empty
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "/external/package/mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules =
                                    Dict.fromList
                                        [ ( "/mod", "external/package" ) ]
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "/external/package/mod/TipeUnion" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type match from an external module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature = AST.NotProvided
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.MultiImpl
                                                [ ( AST.TypeMatch emptyRange (AST.ExternalRef [ "mod" ] "Tipe" []) []
                                                  , [ AST.Word emptyRange "drop"
                                                    ]
                                                  )
                                                ]
                                                [ AST.Word emptyRange "drop"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "/external/package/mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules =
                                    Dict.fromList
                                        [ ( "/mod", "external/package" ) ]
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "/external/package/mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type signature from an internal module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature =
                                            AST.UserProvided
                                                { input = [ AST.InternalRef [ "mod" ] "Tipe" [] ]
                                                , output = []
                                                }
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.SoloImpl
                                                [ AST.Word emptyRange "drop"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules = Dict.empty
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type definition from an internal module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types =
                                Dict.fromList
                                    [ ( "BoxedTipe"
                                      , AST.CustomTypeDef
                                            emptyRange
                                            "BoxedTipe"
                                            []
                                            [ ( "value", AST.InternalRef [ "mod" ] "TipeUnion" [] ) ]
                                      )
                                    ]
                            , words = Dict.empty
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules = Dict.empty
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "mod/TipeUnion" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "Referencing a type in a type match from an internal module which isn't exposed ends in a error" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature = AST.NotProvided
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.MultiImpl
                                                [ ( AST.TypeMatch emptyRange (AST.InternalRef [ "mod" ] "Tipe" []) []
                                                  , [ AST.Word emptyRange "drop"
                                                    ]
                                                  )
                                                ]
                                                [ AST.Word emptyRange "drop"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types =
                                Dict.fromList <|
                                    dummyTypeUnexposed "mod/Tipe"
                            , words = Dict.empty
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules = Dict.empty
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            ]
        ]