summaryrefslogtreecommitdiff
path: root/compiler/typecheck/TcPatSyn.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/typecheck/TcPatSyn.hs')
-rw-r--r--compiler/typecheck/TcPatSyn.hs56
1 files changed, 51 insertions, 5 deletions
diff --git a/compiler/typecheck/TcPatSyn.hs b/compiler/typecheck/TcPatSyn.hs
index 58d1506812..283127215c 100644
--- a/compiler/typecheck/TcPatSyn.hs
+++ b/compiler/typecheck/TcPatSyn.hs
@@ -20,6 +20,7 @@ import TcPat
import Type( mkEmptyTCvSubst, tidyTyVarBinders, tidyTypes, tidyType )
import TcRnMonad
import TcSigs( emptyPragEnv, completeSigFromId )
+import TcType( mkMinimalBySCs )
import TcEnv
import TcMType
import TcHsSyn( zonkTyVarBindersX, zonkTcTypeToTypes
@@ -88,18 +89,44 @@ tcInferPatSynDecl PSB{ psb_id = lname@(L _ name), psb_args = details,
; let (ex_tvs, prov_dicts) = tcCollectEx lpat'
ex_tv_set = mkVarSet ex_tvs
univ_tvs = filterOut (`elemVarSet` ex_tv_set) qtvs
- prov_theta = map evVarPred prov_dicts
req_theta = map evVarPred req_dicts
+ ; prov_dicts <- mapM zonkId prov_dicts
+ ; let filtered_prov_dicts = mkMinimalBySCs evVarPred prov_dicts
+ prov_theta = map evVarPred filtered_prov_dicts
+ -- Filtering: see Note [Remove redundant provided dicts]
+
; traceTc "tcInferPatSynDecl }" $ (ppr name $$ ppr ex_tvs)
; tc_patsyn_finish lname dir is_infix lpat'
(mkTyVarBinders Inferred univ_tvs
, req_theta, ev_binds, req_dicts)
(mkTyVarBinders Inferred ex_tvs
- , mkTyVarTys ex_tvs, prov_theta, map EvId prov_dicts)
+ , mkTyVarTys ex_tvs, prov_theta, map EvId filtered_prov_dicts)
(map nlHsVar args, map idType args)
pat_ty rec_fields }
+{- Note [Remove redundant provided dicts]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Recall that
+ HRefl :: forall k1 k2 (a1:k1) (a2:k2). (k1 ~ k2, a1 ~ a2)
+ => a1 :~~: a2
+(NB: technically the (k1~k2) existential dictionary is not necessary,
+but it's there at the moment.)
+
+Now consider (Trac #14394):
+ pattern Foo = HRefl
+in a non-poly-kinded module. We don't want to get
+ pattern Foo :: () => (* ~ *, b ~ a) => a :~~: b
+with that redundant (* ~ *). We'd like to remove it; hence the call to
+mkMinimalWithSCs.
+
+Similarly consider
+ data S a where { MkS :: Ord a => a -> S a }
+ pattern Bam x y <- (MkS (x::a), MkS (y::a)))
+
+The pattern (Bam x y) binds two (Ord a) dictionaries, but we only
+need one. Agian mkMimimalWithSCs removes the redundant one.
+-}
tcCheckPatSynDecl :: PatSynBind GhcRn GhcRn
-> TcPatSynInfo
@@ -332,7 +359,7 @@ tc_patsyn_finish lname dir is_infix lpat'
(ze, univ_tvs') <- zonkTyVarBindersX emptyZonkEnv univ_tvs
; req_theta' <- zonkTcTypeToTypes ze req_theta
; (ze, ex_tvs') <- zonkTyVarBindersX ze ex_tvs
- ; prov_theta' <- zonkTcTypeToTypes ze prov_theta
+ ; prov_theta' <- zonkTcTypeToTypes ze prov_theta
; pat_ty' <- zonkTcTypeToType ze pat_ty
; arg_tys' <- zonkTcTypeToTypes ze arg_tys
@@ -813,10 +840,13 @@ tcCheckPatSynPat = go
go = addLocM go1
go1 :: Pat GhcRn -> TcM ()
+ -- See Note [Bad patterns]
+ go1 p@(AsPat _ _) = asPatInPatSynErr p
+ go1 p@NPlusKPat{} = nPlusKPatInPatSynErr p
+
go1 (ConPatIn _ info) = mapM_ go (hsConPatArgs info)
go1 VarPat{} = return ()
go1 WildPat{} = return ()
- go1 p@(AsPat _ _) = asPatInPatSynErr p
go1 (LazyPat pat) = go pat
go1 (ParPat pat) = go pat
go1 (BangPat pat) = go pat
@@ -833,7 +863,6 @@ tcCheckPatSynPat = go
= do addModFinalizersWithLclEnv mod_finalizers
go1 pat
| otherwise = panic "non-pattern from spliced thing"
- go1 p@NPlusKPat{} = nPlusKPatInPatSynErr p
go1 ConPatOut{} = panic "ConPatOut in output of renamer"
go1 SigPatOut{} = panic "SigPatOut in output of renamer"
go1 CoPat{} = panic "CoPat in output of renamer"
@@ -850,6 +879,23 @@ nPlusKPatInPatSynErr pat
hang (text "Pattern synonym definition cannot contain n+k-pattern:")
2 (ppr pat)
+{- Note [Bad patterns]
+~~~~~~~~~~~~~~~~~~~~~~
+We don't currently allow as-patterns or n+k patterns in a pattern synonym.
+Reason: consider
+ pattern P x y = x@(Just y)
+
+What would
+ f (P Nothing False) = e
+mean? Presumably something like
+ f Nothing@(Just False) = e
+But as-patterns don't allow a pattern before the @ sign! Perhaps they
+should -- with p1@p2 meaning match both p1 and p2 -- but they don't
+currently. Hence bannning them in pattern synonyms. Actually lifting
+the restriction would be simple and well-defined. See Trac #9793.
+-}
+
+
nonBidirectionalErr :: Outputable name => name -> TcM a
nonBidirectionalErr name = failWithTc $
text "non-bidirectional pattern synonym"