summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/typecheck/TcPatSyn.hs45
-rw-r--r--testsuite/tests/patsyn/should_compile/T13441.hs7
-rw-r--r--testsuite/tests/patsyn/should_compile/T13441a.hs11
-rw-r--r--testsuite/tests/patsyn/should_compile/T13441b.hs12
-rw-r--r--testsuite/tests/patsyn/should_compile/T13441b.stderr11
-rw-r--r--testsuite/tests/patsyn/should_compile/all.T2
6 files changed, 67 insertions, 21 deletions
diff --git a/compiler/typecheck/TcPatSyn.hs b/compiler/typecheck/TcPatSyn.hs
index 6f7764eb3a..01cb5420fd 100644
--- a/compiler/typecheck/TcPatSyn.hs
+++ b/compiler/typecheck/TcPatSyn.hs
@@ -149,14 +149,11 @@ tcCheckPatSynDecl psb@PSB{ psb_id = lname@(L _ name), psb_args = details
pushLevelAndCaptureConstraints $
tcExtendTyVarEnv univ_tvs $
tcPat PatSyn lpat (mkCheckExpType pat_ty) $
- do { let new_tv = case dir of
- ImplicitBidirectional -> newMetaSigTyVarX
- _ -> newMetaTyVarX
- -- new_tv: see the "Existential type variables"
- -- part of Note [Checking against a pattern signature]
- in_scope = mkInScopeSet (mkVarSet univ_tvs)
+ do { let in_scope = mkInScopeSet (mkVarSet univ_tvs)
empty_subst = mkEmptyTCvSubst in_scope
- ; (subst, ex_tvs') <- mapAccumLM new_tv empty_subst ex_tvs
+ ; (subst, ex_tvs') <- mapAccumLM newMetaTyVarX empty_subst ex_tvs
+ -- newMetaTyVarX: see the "Existential type variables"
+ -- part of Note [Checking against a pattern signature]
; traceTc "tcpatsyn1" (vcat [ ppr v <+> dcolon <+> ppr (tyVarKind v) | v <- ex_tvs])
; traceTc "tcpatsyn2" (vcat [ ppr v <+> dcolon <+> ppr (tyVarKind v) | v <- ex_tvs'])
; let prov_theta' = substTheta subst prov_theta
@@ -241,20 +238,26 @@ unify x := [a] during type checking, and then use the instantiating type
dl = $dfunEqList d
in k [a] dl ys
-This "concealing" story works for /uni-directional/ pattern synonyms.
-It also works for /explicitly-bidirectional/ pattern synonyms, where
-the constructor direction is typecheked entirely separately.
-
-But for /implicitly-bidirecitonal/ ones like
- pattern P x = MkS x
-we are trying to typecheck both directions at once. So for this we
-use SigTv, rather than a generic TauTv. But it's not quite done:
- - We should really check that those SigTvs don't get unified
- with each other.
- - Trac #13441 is rejected if you use an implicitly-bidirectional
- pattern.
-Maybe it'd be better to treat it like an explicitly-bidirectional
-pattern?
+All this applies when type-checking the /matching/ side of
+a pattern synonym. What about the /building/ side?
+
+* For Unidirectional, there is no builder
+
+* For ExplicitBidirectional, the builder is completely separate
+ code, typechecked in tcPatSynBuilderBind
+
+* For ImplicitBidirectional, the builder is still typechecked in
+ tcPatSynBuilderBind, by converting the pattern to an expression and
+ typechecking it.
+
+ At one point, for ImplicitBidirectional I used SigTvs (instead of
+ TauTvs) in tcCheckPatSynDecl. But (a) strengthening the check here
+ is redundant since tcPatSynBuilderBind does the job, (b) it was
+ still incomplete (SigTvs can unify with each other), and (c) it
+ didn't even work (Trac #13441 was accepted with
+ ExplicitBidirectional, but rejected if expressed in
+ ImplicitBidirectional form. Conclusion: trying to be too clever is
+ a bad idea.
-}
collectPatSynArgInfo :: HsPatSynDetails (Located Name) -> ([Name], [Name], Bool)
diff --git a/testsuite/tests/patsyn/should_compile/T13441.hs b/testsuite/tests/patsyn/should_compile/T13441.hs
index d7a339f782..738017500d 100644
--- a/testsuite/tests/patsyn/should_compile/T13441.hs
+++ b/testsuite/tests/patsyn/should_compile/T13441.hs
@@ -21,9 +21,16 @@ type family Replicate (n :: Nat) (x :: a) = (r :: [a]) where
type Vec n a = FList Identity (Replicate n a)
+-- Using explicitly-bidirectional pattern
pattern (:>) :: forall n a. n ~ Length (Replicate n a)
=> forall m. n ~ Succ m
=> a -> Vec m a -> Vec n a
pattern x :> xs <- Identity x :@ xs
where
x :> xs = Identity x :@ xs
+
+-- Using implicitly-bidirectional pattern
+pattern (:>>) :: forall n a. n ~ Length (Replicate n a)
+ => forall m. n ~ Succ m
+ => a -> Vec m a -> Vec n a
+pattern x :>> xs = Identity x :@ xs
diff --git a/testsuite/tests/patsyn/should_compile/T13441a.hs b/testsuite/tests/patsyn/should_compile/T13441a.hs
new file mode 100644
index 0000000000..77360946a2
--- /dev/null
+++ b/testsuite/tests/patsyn/should_compile/T13441a.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE PatternSynonyms, GADTs #-}
+module T13441a where
+
+data S where
+ MkS :: Eq a => [a] -> S
+
+-- Unidirectional pattern binding;
+-- the existential is more specific than needed
+-- c.f. T13441b
+pattern P :: () => Eq x => x -> S
+pattern P x <- MkS x
diff --git a/testsuite/tests/patsyn/should_compile/T13441b.hs b/testsuite/tests/patsyn/should_compile/T13441b.hs
new file mode 100644
index 0000000000..8f8d2ba5ca
--- /dev/null
+++ b/testsuite/tests/patsyn/should_compile/T13441b.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE PatternSynonyms, GADTs #-}
+module T13441a where
+
+data S where
+ MkS :: Eq a => [a] -> S
+
+-- Implicitly-bidirectional pattern binding;
+-- the existential is more specific than needed,
+-- and hence should be rejected
+-- c.f. T13441a
+pattern P :: () => Eq x => x -> S
+pattern P x = MkS x
diff --git a/testsuite/tests/patsyn/should_compile/T13441b.stderr b/testsuite/tests/patsyn/should_compile/T13441b.stderr
new file mode 100644
index 0000000000..4469086c82
--- /dev/null
+++ b/testsuite/tests/patsyn/should_compile/T13441b.stderr
@@ -0,0 +1,11 @@
+
+T13441b.hs:12:19: error:
+ • Couldn't match expected type ‘[a0]’ with actual type ‘x’
+ ‘x’ is a rigid type variable bound by
+ the signature for pattern synonym ‘P’ at T13441b.hs:12:1-19
+ • In the first argument of ‘MkS’, namely ‘x’
+ In the expression: MkS x
+ In an equation for ‘P’: P x = MkS x
+ • Relevant bindings include
+ x :: x (bound at T13441b.hs:12:19)
+ $bP :: x -> S (bound at T13441b.hs:12:9)
diff --git a/testsuite/tests/patsyn/should_compile/all.T b/testsuite/tests/patsyn/should_compile/all.T
index 1f36424640..8fce7e987d 100644
--- a/testsuite/tests/patsyn/should_compile/all.T
+++ b/testsuite/tests/patsyn/should_compile/all.T
@@ -65,3 +65,5 @@ test('T12746', normal, multi_compile, ['T12746', [('T12746A.hs', '-c')],'-v0'])
test('T12968', normal, compile, [''])
test('T13349b', normal, compile, [''])
test('T13441', normal, compile, [''])
+test('T13441a', normal, compile, [''])
+test('T13441b', normal, compile_fail, [''])