summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Scott <ryan.gl.scott@gmail.com>2020-08-26 09:23:54 -0400
committerRyan Scott <ryan.gl.scott@gmail.com>2020-08-26 19:16:56 -0400
commit222a878875b0e093e82f81d6f83fa39ac42d53b5 (patch)
tree932914ea810561e8ae98f82d6fb5ade7a39a7e73
parent8426a1364ba450fe48fc41a95b2ba76c8d1bb7c8 (diff)
downloadhaskell-wip/T18612.tar.gz
Make {hsExpr,hsType,pat}NeedsParens aware of boxed 1-tupleswip/T18612
`hsExprNeedsParens`, `hsTypeNeedsParens`, and `patNeedsParens` previously assumed that all uses of explicit tuples in the source syntax never need to be parenthesized. This is true save for one exception: boxed one-tuples, which use the `Solo` data type from `GHC.Tuple` instead of special tuple syntax. This patch adds the necessary logic to the three `*NeedsParens` functions to handle `Solo` correctly. Fixes #18612.
-rw-r--r--compiler/GHC/Hs/Expr.hs5
-rw-r--r--compiler/GHC/Hs/Pat.hs7
-rw-r--r--compiler/GHC/Hs/Type.hs14
-rw-r--r--testsuite/tests/th/T18612.hs14
-rw-r--r--testsuite/tests/th/T18612.stderr13
-rw-r--r--testsuite/tests/th/all.T1
6 files changed, 53 insertions, 1 deletions
diff --git a/compiler/GHC/Hs/Expr.hs b/compiler/GHC/Hs/Expr.hs
index e7b904736d..829a789d36 100644
--- a/compiler/GHC/Hs/Expr.hs
+++ b/compiler/GHC/Hs/Expr.hs
@@ -1320,6 +1320,11 @@ hsExprNeedsParens p = go
go (NegApp{}) = p > topPrec
go (SectionL{}) = True
go (SectionR{}) = True
+ -- Special-case unary boxed tuple applications so that they are
+ -- parenthesized as `Identity (Solo x)`, not `Identity Solo x` (#18612)
+ -- See Note [One-tuples] in GHC.Builtin.Types
+ go (ExplicitTuple _ [L _ Present{}] Boxed)
+ = p >= appPrec
go (ExplicitTuple{}) = False
go (ExplicitSum{}) = False
go (HsLam{}) = p > topPrec
diff --git a/compiler/GHC/Hs/Pat.hs b/compiler/GHC/Hs/Pat.hs
index 62de0ab182..b1507f0adc 100644
--- a/compiler/GHC/Hs/Pat.hs
+++ b/compiler/GHC/Hs/Pat.hs
@@ -857,7 +857,12 @@ patNeedsParens p = go
go (BangPat {}) = False
go (ParPat {}) = False
go (AsPat {}) = False
- go (TuplePat {}) = False
+ -- Special-case unary boxed tuple applications so that they are
+ -- parenthesized as `Identity (Solo x)`, not `Identity Solo x` (#18612)
+ -- See Note [One-tuples] in GHC.Builtin.Types
+ go (TuplePat _ [_] Boxed)
+ = p >= appPrec
+ go (TuplePat{}) = False
go (SumPat {}) = False
go (ListPat {}) = False
go (LitPat _ l) = hsLitNeedsParens p l
diff --git a/compiler/GHC/Hs/Type.hs b/compiler/GHC/Hs/Type.hs
index c6960c9c77..343cc1d1ba 100644
--- a/compiler/GHC/Hs/Type.hs
+++ b/compiler/GHC/Hs/Type.hs
@@ -1979,6 +1979,15 @@ hsTypeNeedsParens p = go_hs_ty
go_hs_ty (HsRecTy{}) = False
go_hs_ty (HsTyVar{}) = False
go_hs_ty (HsFunTy{}) = p >= funPrec
+ -- Special-case unary boxed tuple applications so that they are
+ -- parenthesized as `Identity (Solo x)`, not `Identity Solo x` (#18612)
+ -- See Note [One-tuples] in GHC.Builtin.Types
+ go_hs_ty (HsTupleTy _ con [L _ ty])
+ = case con of
+ HsBoxedTuple -> p >= appPrec
+ HsBoxedOrConstraintTuple -> p >= appPrec
+ HsConstraintTuple -> go_hs_ty ty
+ HsUnboxedTuple -> False
go_hs_ty (HsTupleTy{}) = False
go_hs_ty (HsSumTy{}) = False
go_hs_ty (HsKindSig{}) = p >= sigPrec
@@ -1986,6 +1995,11 @@ hsTypeNeedsParens p = go_hs_ty
go_hs_ty (HsIParamTy{}) = p > topPrec
go_hs_ty (HsSpliceTy{}) = False
go_hs_ty (HsExplicitListTy{}) = False
+ -- Special-case unary boxed tuple applications so that they are
+ -- parenthesized as `Proxy ('Solo x)`, not `Proxy 'Solo x` (#18612)
+ -- See Note [One-tuples] in GHC.Builtin.Types
+ go_hs_ty (HsExplicitTupleTy _ [_])
+ = p >= appPrec
go_hs_ty (HsExplicitTupleTy{}) = False
go_hs_ty (HsTyLit{}) = False
go_hs_ty (HsWildCardTy{}) = False
diff --git a/testsuite/tests/th/T18612.hs b/testsuite/tests/th/T18612.hs
new file mode 100644
index 0000000000..ea7c007c51
--- /dev/null
+++ b/testsuite/tests/th/T18612.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -ddump-splices #-}
+module T18612 where
+
+import Data.Functor.Identity
+import Data.Proxy
+import Language.Haskell.TH
+
+f :: $(arrowT `appT` (conT ''Identity `appT` (tupleT 1 `appT` (tupleT 0)))
+ `appT` (conT ''Identity `appT` (tupleT 1 `appT` (tupleT 0))))
+f $(conP 'Identity [tupP [tupP []]]) = $(conE 'Identity `appE` tupE [tupE []])
+
+type G = $(conT ''Proxy `appT` (promotedTupleT 1 `appT` (tupleT 0)))
diff --git a/testsuite/tests/th/T18612.stderr b/testsuite/tests/th/T18612.stderr
new file mode 100644
index 0000000000..25286ef671
--- /dev/null
+++ b/testsuite/tests/th/T18612.stderr
@@ -0,0 +1,13 @@
+T18612.hs:14:11-68: Splicing type
+ conT ''Proxy `appT` (promotedTupleT 1 `appT` (tupleT 0))
+ ======>
+ Proxy ('Solo ())
+T18612.hs:(10,7)-(11,75): Splicing type
+ arrowT `appT` (conT ''Identity `appT` (tupleT 1 `appT` (tupleT 0)))
+ `appT` (conT ''Identity `appT` (tupleT 1 `appT` (tupleT 0)))
+ ======>
+ Identity (Solo ()) -> Identity (Solo ())
+T18612.hs:12:4-36: Splicing pattern
+ conP 'Identity [tupP [tupP []]] ======> Identity (Solo())
+T18612.hs:12:41-78: Splicing expression
+ conE 'Identity `appE` tupE [tupE []] ======> Identity (Solo ())
diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T
index 6d4a5036d7..e53b0d872a 100644
--- a/testsuite/tests/th/all.T
+++ b/testsuite/tests/th/all.T
@@ -513,3 +513,4 @@ test('T18102b', extra_files(['T18102b_aux.hs']), compile_and_run, [''])
test('T18121', normal, compile, [''])
test('T18123', normal, compile, [''])
test('T18388', normal, compile, [''])
+test('T18612', normal, compile, [''])