diff --git a/test/data/recomp/Setup.hs b/test/data/recomp/Setup.hs new file mode 100644 index 000000000..9a994af67 --- /dev/null +++ b/test/data/recomp/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/test/data/recomp/cabal.project b/test/data/recomp/cabal.project new file mode 100644 index 000000000..e6fdbadb4 --- /dev/null +++ b/test/data/recomp/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/test/data/recomp/hie.yaml b/test/data/recomp/hie.yaml new file mode 100644 index 000000000..57919a091 --- /dev/null +++ b/test/data/recomp/hie.yaml @@ -0,0 +1 @@ +cradle: {cabal: {component: "lib:recomp"}} diff --git a/test/data/recomp/lib/A.hs b/test/data/recomp/lib/A.hs new file mode 100644 index 000000000..ac1a62242 --- /dev/null +++ b/test/data/recomp/lib/A.hs @@ -0,0 +1,6 @@ +module A where + +import B + +x :: Int +x = y diff --git a/test/data/recomp/lib/B.hs b/test/data/recomp/lib/B.hs new file mode 100644 index 000000000..b3e34ed73 --- /dev/null +++ b/test/data/recomp/lib/B.hs @@ -0,0 +1,4 @@ +module B where + +y :: Int +y = undefined diff --git a/test/data/recomp/lib/P.hs b/test/data/recomp/lib/P.hs new file mode 100644 index 000000000..214a1373e --- /dev/null +++ b/test/data/recomp/lib/P.hs @@ -0,0 +1,5 @@ +module P where +import A +import B + +bar = x :: Int diff --git a/test/data/recomp/recomp.cabal b/test/data/recomp/recomp.cabal new file mode 100644 index 000000000..742ae8e68 --- /dev/null +++ b/test/data/recomp/recomp.cabal @@ -0,0 +1,13 @@ +cabal-version: >=1.10 +name: recomp +version: 0.1.0.0 +author: Zubin Duggal +maintainer: zubin@cmi.ac.in +build-type: Simple + +library + exposed-modules: A, B, P + ghc-options: -Wmissing-signatures + hs-source-dirs: lib + build-depends: base + default-language: Haskell2010 diff --git a/test/exe/Main.hs b/test/exe/Main.hs index 45baf9570..cc351236e 100644 --- a/test/exe/Main.hs +++ b/test/exe/Main.hs @@ -461,6 +461,7 @@ diagnosticTests = testGroup "diagnostics" Lens.filtered (T.isInfixOf ("/" <> name <> ".hs:")) failure msg = liftIO $ assertFailure $ "Expected file path to be stripped but got " <> T.unpack msg Lens.mapMOf_ offenders failure notification + , ifaceErrorTest ] codeActionTests :: TestTree @@ -2190,6 +2191,45 @@ simpleMultiTest2 = testCase "simple-multi-test2" $ withoutStackEnv $ runWithExtr checkDefs locs (pure [fooL]) expectNoMoreDiagnostics 0.5 +ifaceErrorTest :: TestTree +ifaceErrorTest = testCase "iface-error-test" $ withoutStackEnv $ runWithExtraFiles "recomp" $ \dir -> do + let aPath = dir "lib/A.hs" + bPath = dir "lib/B.hs" + pPath = dir "lib/P.hs" + + aSource <- liftIO $ readFileUtf8 aPath -- x = y :: Int + bSource <- liftIO $ readFileUtf8 bPath -- y :: Int + pSource <- liftIO $ readFileUtf8 pPath -- bar = x :: Int + + bdoc <- createDoc bPath "haskell" bSource + pdoc <- createDoc pPath "haskell" pSource + expectDiagnostics [("lib/P.hs", [(DsWarning,(4,0), "Top-level binding")]) -- So what we know P has been loaded + ] + + -- Change y from Int to B + changeDoc bdoc [TextDocumentContentChangeEvent Nothing Nothing $ T.unlines ["module B where", "y :: Bool", "y = undefined"]] + + -- Check that the error propogates to A + adoc <- createDoc aPath "haskell" aSource + expectDiagnostics + [("lib/A.hs", [(DsError, (5, 4), "Couldn't match expected type 'Int' with actual type 'Bool'")])] + closeDoc adoc -- Close A + + changeDoc pdoc [TextDocumentContentChangeEvent Nothing Nothing $ pSource <> "\nfoo = y :: Bool" ] + -- Now in P we have + -- bar = x :: Int + -- foo = y :: Bool + -- HOWEVER, in A... + -- x = y :: Int + -- This is clearly inconsistent, yet we don't get an error + expectDiagnostics [("lib/P.hs", [(DsWarning,(4,0), "Top-level binding")]) + ,("lib/P.hs", [(DsWarning,(6,0), "Top-level binding")]) + ] + expectDiagnostics + [("lib/A.hs", [(DsError, (5, 4), "Couldn't match expected type 'Int' with actual type 'Bool'")])] + expectNoMoreDiagnostics 2 + + sessionDepsArePickedUp :: TestTree sessionDepsArePickedUp = testSession' "session-deps-are-picked-up"