Skip to content

Commit

Permalink
Merge pull request #20 from Zokka-Dev/fix-occurs-check-bug
Browse files Browse the repository at this point in the history
Fix occurs check bug
  • Loading branch information
changlinli authored Jul 25, 2024
2 parents 8a958a6 + d29cf28 commit 90425fb
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/haskell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ jobs:
- name: Run elm-test-rs tests
run: python3 run-test-rs-tests.py

- name: Run compiler-output tests
run: python3 run-compiler-output-tests.py

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ jobs:
- name: Run elm-test-rs tests
run: python3 run-test-rs-tests.py

- name: Run compiler-output tests
run: python3 run-compiler-output-tests.py

# Extract the current git tag
- name: Extract Git Tag
id: get_version
Expand Down
25 changes: 25 additions & 0 deletions compiler-output-tests/elm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0"
},
"indirect": {
"elm/json": "1.1.3",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.3"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
},
"zokka-package-overrides": []
}
12 changes: 12 additions & 0 deletions compiler-output-tests/src/BadOccursCheck.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module BadOccursCheck exposing (..)

-- https://github.com/elm/compiler/issues/2241

foldMap : (a -> b) -> (a -> c) -> (b -> c -> c) -> a -> c
foldMap fab fac fbc a = fac a

f : a -> a -> a
f x y = x

break : Float -> (Float, Float)
break input = foldMap identity (\x -> (x, x)) (\( low, high ) x -> ( f low x, f high x )) input
40 changes: 40 additions & 0 deletions compiler-output-tests/src/BadOccursCheck1.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module BadOccursCheck1 exposing (..)
-- From an error that showed up on incremental-elm Slack

-- This file will cause the vanilla Elm compiler to hang when compiling.

type Effect msg = Effect

type Msg = Msg1 Int | Msg2 Int

-- All our functions will be infinite loops since this is only meant to test
-- type checking and we don't care about any runtime stuff
-- We won't use Debug.todo just in case we want to double-check that all of
-- this works fine when we run `--optimize` (although presently I can't
-- think of any reason why --optimize would change anything WRT
-- typechecking, but just in case!)
applyIf : Bool -> (a -> a) -> a -> a
applyIf x = applyIf x

update : model -> ( model, Effect msg )
update x = update x

withQuery : (data -> msg) -> Effect msg -> ( model, Effect msg ) -> ( model, Effect msg )
withQuery f = withQuery f

-- A nice hack to get us values without resorting to Debug.todo
-- Can't just directly do x = x because the Elm compiler detects that
makeAnything : a -> b
makeAnything x = makeAnything x

query1 = makeAnything ()

query2 = makeAnything ()

model = makeAnything ()

result condition =
model
|> update
|> applyIf condition withQuery Msg1 query1
|> applyIf condition withQuery Msg1 query2
1 change: 0 additions & 1 deletion compiler/src/Generate/JavaScript.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import qualified Generate.Mode as Mode
import qualified Reporting.Doc as D
import qualified Reporting.Render.Type as RT
import qualified Reporting.Render.Type.Localizer as L
import qualified Debug.Trace as Debug
import Control.Exception (Exception, throw)
import qualified Elm.Package as Pkg
import qualified Data.Maybe as Maybe
Expand Down
1 change: 0 additions & 1 deletion compiler/src/Generate/JavaScript/Expression.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import qualified Json.Encode as Encode
import Json.Encode ((==>))
import qualified Optimize.DecisionTree as DT
import qualified Reporting.Annotation as A
import qualified Debug.Trace as Debug



Expand Down
34 changes: 26 additions & 8 deletions compiler/src/Type/Unify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,33 @@ fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
guardedUnify :: Variable -> Variable -> Unify ()
guardedUnify left right =
Unify $ \vars ok err ->
do equivalent <- UF.equivalent left right
if equivalent
then ok vars ()
do -- It might be possible to actually just do == instead of >. This is
-- because it might be the case that if a variable is not infinite
-- right now, it won't ever be infinite during this particular unify
-- call. But I haven't really thought that through enough to be
-- confident putting it in.
--
-- Note that we ultimately decided against doing a recursion depth check
-- as detailed in
-- https://github.com/Zokka-Dev/zokka-compiler/pull/20#issuecomment-2234089482
-- This is because we didn't want to have an unpredictable performance
-- profile (i.e. mysterious immediate slowdown).
-- If we see slowdown we want to know soon so that we can think about a
-- better fix. So far benchmarks seem to show that this causes minimal slowdown.
occursLeft <- Occurs.occurs left
occursRight <- Occurs.occurs right
equivalent <- UF.equivalent left right
if occursLeft || occursRight
then err vars ()
else
do leftDesc <- UF.get left
rightDesc <- UF.get right
case actuallyUnify (Context left leftDesc right rightDesc) of
Unify k ->
k vars ok err
if equivalent
then ok vars ()
else
do leftDesc <- UF.get left
rightDesc <- UF.get right
case actuallyUnify (Context left leftDesc right rightDesc) of
Unify k ->
k vars ok err


subUnify :: Variable -> Variable -> Unify ()
Expand Down
2 changes: 1 addition & 1 deletion elm-test-rs-tests/tests/Tests.elm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import TCOMiscompilation4 exposing (tcoMiscompilation4Test0, tcoMiscompilation4T


suite : Test
suite = describe "TCO tests"
suite = describe "All tests"
[ anotherBadClosureTest
, tcoProducesBadClosuresTest
, tcoMiscompilation0Test
Expand Down
40 changes: 40 additions & 0 deletions run-compiler-output-tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import subprocess
import os
import timeit

def run_zokka_make(zokka_cmd, file_to_make, project_dir):
return subprocess.run([zokka_cmd, "make", file_to_make], cwd=project_dir)

if __name__ == "__main__":

start_time = timeit.default_timer()

find_zokka_cmd = ["cabal", "list-bin", "zokka"]


zokka_exec_location = \
subprocess.run(find_zokka_cmd, capture_output=True).stdout.strip()

run_zokka_make_cmd = [zokka_exec_location, ]

current_dir = "."

top_level_tests_dir = os.path.join(current_dir, "compiler-output-tests")

print(f"=========\nRunning compiler-output tests found in {top_level_tests_dir}\n=========\n")

bad_occurs_check_test_0 =\
run_zokka_make(zokka_exec_location, os.path.join("src", "BadOccursCheck.elm"), top_level_tests_dir)

if bad_occurs_check_test_0.returncode == 0:
raise Exception("Our bad occurs check failed! The compiler succeeded when it should have failed!")

bad_occurs_check_test_1 =\
run_zokka_make(zokka_exec_location, os.path.join("src", "BadOccursCheck1.elm"), top_level_tests_dir)

if bad_occurs_check_test_1.returncode == 0:
raise Exception("Our bad occurs check failed! The compiler succeeded when it should have failed!")

total_test_duration = timeit.default_timer() - start_time

print(f"=========\nTotal test duration: {total_test_duration} seconds\n=========\n")

0 comments on commit 90425fb

Please sign in to comment.