summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/HsToCore/Pmc/Solver.hs41
-rw-r--r--compiler/GHC/HsToCore/Pmc/Solver/Types.hs6
-rw-r--r--testsuite/tests/pmcheck/should_compile/T20631.hs24
-rw-r--r--testsuite/tests/pmcheck/should_compile/all.T2
4 files changed, 56 insertions, 17 deletions
diff --git a/compiler/GHC/HsToCore/Pmc/Solver.hs b/compiler/GHC/HsToCore/Pmc/Solver.hs
index aafac14516..41d6eb5ea2 100644
--- a/compiler/GHC/HsToCore/Pmc/Solver.hs
+++ b/compiler/GHC/HsToCore/Pmc/Solver.hs
@@ -560,7 +560,7 @@ data PhiCt
-- ^ @PhiConCt x K tvs dicts ys@ encodes @K \@tvs dicts ys <- x@, matching @x@
-- against the 'PmAltCon' application @K \@tvs dicts ys@, binding @tvs@,
-- @dicts@ and possibly unlifted fields @ys@ in the process.
- -- See Note [Strict fields and fields of unlifted type].
+ -- See Note [Strict fields and variables of unlifted type].
| PhiNotConCt !Id !PmAltCon
-- ^ @PhiNotConCt x K@ encodes "x ≁ K", asserting that @x@ can't be headed
-- by @K@.
@@ -685,9 +685,13 @@ addBotCt nabla@MkNabla{ nabla_tm_st = ts@TmSt{ ts_facts=env } } x = do
case bot of
IsNotBot -> mzero -- There was x ≁ ⊥. Contradiction!
IsBot -> pure nabla -- There already is x ~ ⊥. Nothing left to do
- MaybeBot -> do -- We add x ~ ⊥
- let vi' = vi{ vi_bot = IsBot }
- pure nabla{ nabla_tm_st = ts{ts_facts = addToUSDFM env y vi' } }
+ MaybeBot -> -- We add x ~ ⊥
+ -- Case (3) in Note [Strict fields and variables of unlifted type]
+ if isUnliftedType (idType x)
+ then mzero -- unlifted vars can never be ⊥
+ else do
+ let vi' = vi{ vi_bot = IsBot }
+ pure nabla{ nabla_tm_st = ts{ts_facts = addToUSDFM env y vi' } }
-- | Adds the constraint @x ~/ ⊥@ to 'Nabla'. Quite similar to 'addNotConCt',
-- but only cares for the ⊥ "constructor".
@@ -1102,12 +1106,12 @@ storing required arguments along with the PmAltConLike in 'vi_neg'.
Note [Strict fields and variables of unlifted type]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Binders of unlifted type (and strict fields) are unlifted by construction;
-they are conceived with an implicit @≁⊥@ constraint to begin with. Hence,
-desugaring in "GHC.HsToCore.Pmc" is entirely unconcerned by strict fields,
-since the forcing happens *before* pattern matching.
-And the φ constructor constraints emitted by 'GHC.HsToCore.Pmc.checkGrd'
-have complex binding semantics (binding type constraints and unlifted fields),
-so unliftedness semantics are entirely confined to the oracle.
+they are conceived with an implicit (but delayed checked) @≁⊥@ constraint to
+begin with. Hence, desugaring in "GHC.HsToCore.Pmc" is entirely unconcerned
+by strict fields, since the forcing happens *before* pattern matching. And
+the φ constructor constraints emitted by 'GHC.HsToCore.Pmc.checkGrd' have
+complex binding semantics (binding type constraints and unlifted fields), so
+unliftedness semantics are entirely confined to the oracle.
These are the moving parts:
@@ -1138,11 +1142,18 @@ These are the moving parts:
constructor constraint.
3. The preceding points handle unlifted constructor fields, but there also
- are regular binders of unlifted type.
- Since the oracle as implemented has no notion of scoping and bindings,
- we can't know *when* an unlifted variable comes into scope. But that's
- not actually a problem, because we can just add the @x ≁ ⊥@ to the
- 'emptyVarInfo' when we first encounter it.
+ are regular binders of unlifted type. We simply fail in 'addBotCt' for
+ any binder of unlifted type.
+ It would be enough to check for unliftedness once, when the binder comes
+ into scope, but we haven't really a way to track that.
+
+ 4. Why not start an 'emptyVarInfo' of unlifted type with @vi_bot = IsNotBot@?
+ Because then we'd need to trigger an inhabitation test, because the var
+ might actually be void to begin with. But we can't trigger the test from
+ 'emptyVarInfo'.
+ Historically, that is what we did and not doing the test led to #20631,
+ where 'addNotBotCt' trivially succeeded, because the 'VarInfo' already
+ said 'IsNotBot', implying that a prior inhabitation test succeeded.
-}
-------------------------
diff --git a/compiler/GHC/HsToCore/Pmc/Solver/Types.hs b/compiler/GHC/HsToCore/Pmc/Solver/Types.hs
index 1fcaf44a4f..d602335692 100644
--- a/compiler/GHC/HsToCore/Pmc/Solver/Types.hs
+++ b/compiler/GHC/HsToCore/Pmc/Solver/Types.hs
@@ -291,9 +291,11 @@ emptyVarInfo x
{ vi_id = x
, vi_pos = []
, vi_neg = emptyPmAltConSet
- -- Case (3) in Note [Strict fields and fields of unlifted type]
+ -- Why not set IsNotBot for unlifted type here?
+ -- Because we'd have to trigger an inhabitation test, which we can't.
+ -- See case (4) in Note [Strict fields and variables of unlifted type]
-- in GHC.HsToCore.Pmc.Solver
- , vi_bot = if isUnliftedType (idType x) then IsNotBot else MaybeBot
+ , vi_bot = MaybeBot
, vi_rcm = emptyRCM
}
diff --git a/testsuite/tests/pmcheck/should_compile/T20631.hs b/testsuite/tests/pmcheck/should_compile/T20631.hs
new file mode 100644
index 0000000000..d255c521ba
--- /dev/null
+++ b/testsuite/tests/pmcheck/should_compile/T20631.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE UnliftedDatatypes #-}
+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
+module Lib where
+import Data.Kind (Type)
+import GHC.Exts (UnliftedType)
+
+type Foo :: UnliftedType -> Type -> Type
+data Foo a b =
+ Bar a -- no need for strictness annotation
+ | Baz b
+
+type MyVoid :: UnliftedType
+data MyVoid
+
+v :: Foo MyVoid Char
+v = Baz 'c'
+
+main :: IO ()
+main = case v of
+ -- The Baz case is impossible
+ -- MyVoid has no values, and it can't
+ -- be undefined because it's unlifted.
+ Baz c -> putChar c
+
diff --git a/testsuite/tests/pmcheck/should_compile/all.T b/testsuite/tests/pmcheck/should_compile/all.T
index c732ef5691..f1cc928151 100644
--- a/testsuite/tests/pmcheck/should_compile/all.T
+++ b/testsuite/tests/pmcheck/should_compile/all.T
@@ -168,6 +168,8 @@ test('T18932', normal, compile,
['-fwarn-incomplete-patterns -fwarn-overlapping-patterns'])
test('T19622', normal, compile,
['-fwarn-incomplete-patterns -fwarn-overlapping-patterns'])
+test('T20631', normal, compile,
+ ['-fwarn-incomplete-patterns -fwarn-overlapping-patterns'])
# Other tests
test('pmc001', [], compile,