summaryrefslogtreecommitdiff
path: root/testsuite/tests
diff options
context:
space:
mode:
authorAdam Gundry <adam@well-typed.com>2020-12-23 22:22:08 +0000
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-02-16 04:34:43 -0500
commit2521b041bff00458cb2c84b8747ea60d6991e329 (patch)
tree091e47028c452050ee46fcb70aa9a01186120c1e /testsuite/tests
parentf422c12d26f183481ad8a833667cbfdd1c9b3e95 (diff)
downloadhaskell-2521b041bff00458cb2c84b8747ea60d6991e329.tar.gz
Implement NoFieldSelectors extension (ghc-proposals 160)
Fixes #5972. This adds an extension NoFieldSelectors to disable the generation of selector functions corresponding to record fields. When this extension is enabled, record field selectors are not accessible as functions, but users are still able to use them for record construction, pattern matching and updates. See Note [NoFieldSelectors] in GHC.Rename.Env for details. Defining the same field multiple times requires the DuplicateRecordFields extension to be enabled, even when NoFieldSelectors is in use. Along the way, this fixes the use of non-imported DuplicateRecordFields in GHCi with -fimplicit-import-qualified (fixes #18729). Moreover, it extends DisambiguateRecordFields to ignore non-fields when looking up fields in record updates (fixes #18999), as described by Note [DisambiguateRecordFields for updates]. Co-authored-by: Simon Hafner <hafnersimon@gmail.com> Co-authored-by: Fumiaki Kinoshita <fumiexcel@gmail.com>
Diffstat (limited to 'testsuite/tests')
-rw-r--r--testsuite/tests/driver/T4437.hs1
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/GHCiDRF.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/GHCiDRF.script11
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout48
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/all.T1
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NFSDRF.hs36
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NFSExport.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NFSImport.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NoFieldSelectors.hs30
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T18999_FieldSelectors.hs7
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T18999_NoFieldSelectors.hs9
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/all.T5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.hs10
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.stderr4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFS9156.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.hs10
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.stderr5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSExport.stderr5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr13
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSMixedA.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.hs9
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.hs16
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr40
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFailA.hs11
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr18
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/all.T8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr2
-rw-r--r--testsuite/tests/parser/should_compile/T14189.stderr6
-rw-r--r--testsuite/tests/patsyn/should_fail/all.T1
-rw-r--r--testsuite/tests/patsyn/should_fail/records-nofieldselectors.hs12
-rw-r--r--testsuite/tests/patsyn/should_fail/records-nofieldselectors.stderr5
36 files changed, 376 insertions, 3 deletions
diff --git a/testsuite/tests/driver/T4437.hs b/testsuite/tests/driver/T4437.hs
index ffb076e1e6..27be970d22 100644
--- a/testsuite/tests/driver/T4437.hs
+++ b/testsuite/tests/driver/T4437.hs
@@ -40,6 +40,7 @@ expectedGhcOnlyExtensions =
[ "RelaxedLayout"
, "AlternativeLayoutRule"
, "AlternativeLayoutRuleTransitional"
+ , "FieldSelectors"
]
expectedCabalOnlyExtensions :: [String]
diff --git a/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.hs b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.hs
new file mode 100644
index 0000000000..5b54ad5ba3
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module GHCiDRF where
+data T = MkT { foo :: Int, bar :: Int }
+data U = MkU { bar :: Bool }
diff --git a/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.script b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.script
new file mode 100644
index 0000000000..89a7623c8b
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.script
@@ -0,0 +1,11 @@
+:l GHCiDRF
+:t GHCiDRF.foo
+:t GHCiDRF.bar
+:info GHCiDRF.foo
+:info GHCiDRF.bar
+:m - GHCiDRF
+:t GHCiDRF.foo
+:t GHCiDRF.bar
+:info GHCiDRF.foo
+:info GHCiDRF.bar
+GHCiDRF.bar (GHCiDRF.MkU True :: GHCiDRF.U)
diff --git a/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout
new file mode 100644
index 0000000000..1a7b44e64e
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout
@@ -0,0 +1,48 @@
+GHCiDRF.foo :: T -> Int
+
+<interactive>:1:1: error:
+ Ambiguous occurrence ‘GHCiDRF.bar’
+ It could refer to
+ either the field ‘bar’, defined at GHCiDRF.hs:4:16
+ or the field ‘bar’, defined at GHCiDRF.hs:3:28
+type T :: *
+data T = MkT {foo :: Int, ...}
+ -- Defined at GHCiDRF.hs:3:16
+type U :: *
+data U = MkU {GHCiDRF.bar :: Bool}
+ -- Defined at GHCiDRF.hs:4:16
+
+type T :: *
+data T = MkT {..., GHCiDRF.bar :: Int}
+ -- Defined at GHCiDRF.hs:3:28
+GHCiDRF.foo :: GHCiDRF.T -> Int
+
+<interactive>:1:1: error:
+ Ambiguous occurrence ‘GHCiDRF.bar’
+ It could refer to
+ either the field ‘bar’,
+ imported qualified from ‘GHCiDRF’
+ (and originally defined at GHCiDRF.hs:3:28-30)
+ or the field ‘bar’,
+ imported qualified from ‘GHCiDRF’
+ (and originally defined at GHCiDRF.hs:4:16-18)
+type GHCiDRF.T :: *
+data GHCiDRF.T = GHCiDRF.MkT {GHCiDRF.foo :: Int, ...}
+ -- Defined at GHCiDRF.hs:3:16
+type GHCiDRF.T :: *
+data GHCiDRF.T = GHCiDRF.MkT {..., GHCiDRF.bar :: Int}
+ -- Defined at GHCiDRF.hs:3:28
+
+type GHCiDRF.U :: *
+data GHCiDRF.U = GHCiDRF.MkU {GHCiDRF.bar :: Bool}
+ -- Defined at GHCiDRF.hs:4:16
+
+<interactive>:11:1: error:
+ Ambiguous occurrence ‘GHCiDRF.bar’
+ It could refer to
+ either the field ‘bar’,
+ imported qualified from ‘GHCiDRF’
+ (and originally defined at GHCiDRF.hs:3:28-30)
+ or the field ‘bar’,
+ imported qualified from ‘GHCiDRF’
+ (and originally defined at GHCiDRF.hs:4:16-18)
diff --git a/testsuite/tests/overloadedrecflds/ghci/all.T b/testsuite/tests/overloadedrecflds/ghci/all.T
index e8c008d1df..7bddafd6fb 100644
--- a/testsuite/tests/overloadedrecflds/ghci/all.T
+++ b/testsuite/tests/overloadedrecflds/ghci/all.T
@@ -1,3 +1,4 @@
test('duplicaterecfldsghci01', combined_output, ghci_script, ['duplicaterecfldsghci01.script'])
test('overloadedlabelsghci01', combined_output, ghci_script, ['overloadedlabelsghci01.script'])
test('T13438', [expect_broken(13438), combined_output], ghci_script, ['T13438.script'])
+test('GHCiDRF', [extra_files(['GHCiDRF.hs']), combined_output], ghci_script, ['GHCiDRF.script'])
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NFSDRF.hs b/testsuite/tests/overloadedrecflds/should_compile/NFSDRF.hs
new file mode 100644
index 0000000000..a1e8744974
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NFSDRF.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module NFSDRF where
+
+import Prelude
+
+
+data Foo = Foo { foo :: Int, bar :: String }
+data Bar = Bar { foo :: Int, bar' :: String }
+
+foo = 3 -- should not conflict
+
+fooX = foo + 1
+
+rwcPatFoo Foo{..} = show (foo, bar)
+rwcConFoo = Foo{..} where
+ foo = 42
+ bar = "hello"
+
+foo1 :: Foo
+foo1 = Foo 3 "bar"
+
+foo2 = Foo { foo = 3, bar = "bar" } -- disambiguate foo
+
+
+-- foo3 :: Foo
+-- foo3 = foo1 { foo = 4 } -- currently rejected, see #18999
+
+foo4 = foo1 { bar = "baz" } -- unambiguous
+
+bar0 = Bar { foo = 0, bar' = "bar'" }
+
+-- bar1 :: Bar
+-- bar1 = bar0 { foo = 1 } -- currently rejected, see #18999
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NFSExport.hs b/testsuite/tests/overloadedrecflds/should_compile/NFSExport.hs
new file mode 100644
index 0000000000..8e83c085bf
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NFSExport.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE NoFieldSelectors #-}
+
+module NFSExport (T(foo), def) where
+
+data T = MkT { foo :: Bool }
+
+def :: T
+def = MkT False
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NFSImport.hs b/testsuite/tests/overloadedrecflds/should_compile/NFSImport.hs
new file mode 100644
index 0000000000..433e9f06fc
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NFSImport.hs
@@ -0,0 +1,5 @@
+module NFSImport where
+
+import NFSExport
+
+t = def { foo = True }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NoFieldSelectors.hs b/testsuite/tests/overloadedrecflds/should_compile/NoFieldSelectors.hs
new file mode 100644
index 0000000000..d114861672
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NoFieldSelectors.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE RecordWildCards #-}
+
+
+module NoFieldSelectors
+where
+
+import Prelude
+
+
+data Foo = Foo { foo :: Int, bar :: String }
+
+{-# ANN foo () #-}
+foo = 3 -- should not conflict
+
+fooX = foo + 1
+
+rwcPatFoo Foo{..} = show (foo, bar)
+rwcConFoo = Foo{..} where
+ foo = 42
+ bar = "hello"
+
+foo1 :: Foo
+foo1 = Foo 3 "bar"
+
+foo2 = Foo { foo = 3, bar = "bar" } -- disambiguate foo
+
+-- foo3 = foo1 { foo = 4 } -- currently rejected, see #18999
+
+foo4 = foo1 { bar = "baz" } -- bar is unambiguous
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T18999_FieldSelectors.hs b/testsuite/tests/overloadedrecflds/should_compile/T18999_FieldSelectors.hs
new file mode 100644
index 0000000000..8fb6e5f9df
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T18999_FieldSelectors.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE DisambiguateRecordFields #-}
+module T18999_FieldSelectors where
+
+data Foo = Foo { not :: Int }
+
+foo = Foo { not = 1 }
+y = foo { not = 2 }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T18999_NoFieldSelectors.hs b/testsuite/tests/overloadedrecflds/should_compile/T18999_NoFieldSelectors.hs
new file mode 100644
index 0000000000..69bf8fb427
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T18999_NoFieldSelectors.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE DisambiguateRecordFields #-}
+{-# LANGUAGE NoFieldSelectors #-}
+module T18999_NoFieldSelectors where
+
+data Foo = Foo { bar :: Int, baz :: Int }
+baz = 42
+
+foo = Foo { bar = 23, baz = 1 }
+y = foo { baz = baz }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/all.T b/testsuite/tests/overloadedrecflds/should_compile/all.T
index 515b19635f..a043570034 100644
--- a/testsuite/tests/overloadedrecflds/should_compile/all.T
+++ b/testsuite/tests/overloadedrecflds/should_compile/all.T
@@ -3,3 +3,8 @@ test('T12609', normal, compile, [''])
test('T16597', [], multimod_compile, ['T16597', '-v0'])
test('T17176', normal, compile, [''])
test('DRFPatSynExport', [], makefile_test, ['DRFPatSynExport'])
+test('NoFieldSelectors', normal, compile, [''])
+test('NFSDRF', normal, compile, [''])
+test('NFSImport', [extra_files(['NFSExport.hs'])], multimod_compile, ['NFSImport NFSExport', '-v0'])
+test('T18999_NoFieldSelectors', normal, compile, [''])
+test('T18999_FieldSelectors', normal, compile, [''])
diff --git a/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.hs b/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.hs
new file mode 100644
index 0000000000..e33f4c0971
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE FieldSelectors #-}
+
+module FieldSelectors
+where
+
+import Prelude
+
+data Foo = Foo { foo :: Int, bar :: String }
+
+foo = 3
diff --git a/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.stderr b/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.stderr
new file mode 100644
index 0000000000..8edc117f3d
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/FieldSelectors.stderr
@@ -0,0 +1,4 @@
+FieldSelectors.hs:10:1:
+ Multiple declarations of ‘foo’
+ Declared at: FieldSelectors.hs:8:18
+ FieldSelectors.hs:10:1 \ No newline at end of file
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFS9156.hs b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.hs
new file mode 100644
index 0000000000..4cc1091cf2
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE NoFieldSelectors #-}
+module NFS9156 where
+data D = D1 { f1 :: Int }
+ | D2 { f1, f1 :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr
new file mode 100644
index 0000000000..66ab58fcbd
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr
@@ -0,0 +1,5 @@
+
+NFS9156.hs:4:19: error:
+ Multiple declarations of ‘f1’
+ Declared at: NFS9156.hs:3:15
+ NFS9156.hs:4:19
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.hs
new file mode 100644
index 0000000000..5da0175a1e
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE NoDuplicateRecordFields #-}
+module NFSDuplicate where
+
+-- Two definitions of 'foo' as fields is an error, even though it is permitted
+-- to define it as a non-field.
+data S = MkS { foo :: Int }
+data T = MkT { foo :: Int }
+
+foo = ()
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.stderr
new file mode 100644
index 0000000000..f30bb1e490
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSDuplicate.stderr
@@ -0,0 +1,5 @@
+
+NFSDuplicate.hs:8:16: error:
+ Multiple declarations of ‘foo’
+ Declared at: NFSDuplicate.hs:7:16
+ NFSDuplicate.hs:8:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs
new file mode 100644
index 0000000000..839b32bae4
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs
@@ -0,0 +1,3 @@
+{-# LANGUAGE NoFieldSelectors #-}
+module NFSExport (T(foo), foo) where -- only T(foo) is supported
+data T = MkT { foo :: Bool }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSExport.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.stderr
new file mode 100644
index 0000000000..c704facfc9
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.stderr
@@ -0,0 +1,5 @@
+
+NFSExport.hs:2:27: error:
+ Not in scope: ‘foo’
+ NB: ‘foo’ is a field selector belonging to the type ‘T’
+ that has been suppressed by NoFieldSelectors
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs
new file mode 100644
index 0000000000..d2b3d8dd1b
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs
@@ -0,0 +1,5 @@
+module NFSMixed where
+
+import NFSMixedA
+
+test = \x -> x { foo = 0 }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr
new file mode 100644
index 0000000000..b569125c4a
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr
@@ -0,0 +1,13 @@
+
+NFSMixed.hs:5:18: error:
+ Ambiguous occurrence ‘foo’
+ It could refer to
+ either the field ‘foo’,
+ imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
+ (and originally defined at NFSMixedA.hs:4:18-20)
+ or the field ‘foo’,
+ imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
+ (and originally defined at NFSMixedA.hs:5:18-20)
+ or ‘NFSMixedA.foo’,
+ imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
+ (and originally defined at NFSMixedA.hs:8:1-3)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSMixedA.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSMixedA.hs
new file mode 100644
index 0000000000..626d5bfc35
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSMixedA.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+module NFSMixedA where
+data Foo = Foo { foo :: Int, bar :: String }
+data Bar = Bar { foo :: Int, bar' :: String }
+
+foo :: Int
+foo = 0
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.hs
new file mode 100644
index 0000000000..0eb415d032
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE NoFieldSelectors #-}
+
+module NFSSuppressed where
+
+import Prelude
+
+data Foo = Foo { foo :: Int }
+
+x = foo
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.stderr
new file mode 100644
index 0000000000..51415300e0
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSSuppressed.stderr
@@ -0,0 +1,6 @@
+
+NFSSuppressed.hs:9:5: error:
+ • Variable not in scope: foo
+ • Perhaps you meant data constructor ‘Foo’ (line 7)
+ NB: ‘foo’ is a field selector belonging to the type ‘Foo’
+ that has been suppressed by NoFieldSelectors
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.hs b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.hs
new file mode 100644
index 0000000000..c2ade91335
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE NoFieldSelectors #-}
+module NoFieldSelectorsFail (foo, bar) where
+
+import NoFieldSelectorsFailA
+
+foo1 :: Foo
+foo1 = Foo 3 "bar"
+
+bar0 = Bar { foo = 0, bar' = "bar'" }
+
+foo3 :: Foo
+foo3 = foo1 { foo = 4 } -- update
+
+bar1 = bar0 { foo = 1 }
+
+foo4 = foo1 { bar = "" } -- currently rejected, see #18999
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr
new file mode 100644
index 0000000000..13193f38d9
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr
@@ -0,0 +1,40 @@
+
+NoFieldSelectorsFail.hs:9:14: error:
+ Ambiguous occurrence ‘foo’
+ It could refer to
+ either the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
+ or the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+
+NoFieldSelectorsFail.hs:12:15: error:
+ Ambiguous occurrence ‘foo’
+ It could refer to
+ either the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
+ or the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+
+NoFieldSelectorsFail.hs:14:15: error:
+ Ambiguous occurrence ‘foo’
+ It could refer to
+ either the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
+ or the field ‘foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+
+NoFieldSelectorsFail.hs:16:15: error:
+ Ambiguous occurrence ‘bar’
+ It could refer to
+ either the field ‘bar’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:30-32)
+ or ‘NoFieldSelectorsFailA.bar’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:8:1-3)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFailA.hs b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFailA.hs
new file mode 100644
index 0000000000..1c542a869a
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFailA.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+module NoFieldSelectorsFailA where
+
+data Foo = Foo { foo :: Int, bar :: String }
+data Bar = Bar { foo :: Int, bar' :: String }
+
+bar = undefined
+
+foo4 = (Foo 3 "bar") { bar = "" } -- permitted thanks to DisambiguateRecordFields
+ -- (implied by DuplicateRecordFields), see #18999
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.hs b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.hs
new file mode 100644
index 0000000000..2a78c20d13
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE NoFieldSelectors #-}
+module T18999_NoDisambiguateRecordFields where
+
+data Foo = Foo { not :: Int }
+
+foo = Foo { not = 1 } -- ambiguous without DisambiguateRecordFields
+x = not -- unambiguous because of NoFieldSelectors
+y = foo { not = 2 } -- ambiguous without DisambiguateRecordFields
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr
new file mode 100644
index 0000000000..425e8d7245
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr
@@ -0,0 +1,18 @@
+
+T18999_NoDisambiguateRecordFields.hs:6:13: error:
+ Ambiguous occurrence ‘not’
+ It could refer to
+ either ‘Prelude.not’,
+ imported from ‘Prelude’ at T18999_NoDisambiguateRecordFields.hs:2:8-40
+ (and originally defined in ‘GHC.Classes’)
+ or the field ‘not’,
+ defined at T18999_NoDisambiguateRecordFields.hs:4:18
+
+T18999_NoDisambiguateRecordFields.hs:8:11: error:
+ Ambiguous occurrence ‘not’
+ It could refer to
+ either ‘Prelude.not’,
+ imported from ‘Prelude’ at T18999_NoDisambiguateRecordFields.hs:2:8-40
+ (and originally defined in ‘GHC.Classes’)
+ or the field ‘not’,
+ defined at T18999_NoDisambiguateRecordFields.hs:4:18
diff --git a/testsuite/tests/overloadedrecflds/should_fail/all.T b/testsuite/tests/overloadedrecflds/should_fail/all.T
index 09bee3ba06..644d3a8427 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/all.T
+++ b/testsuite/tests/overloadedrecflds/should_fail/all.T
@@ -36,4 +36,12 @@ test('T17965', normal, compile_fail, [''])
test('DRFHoleFits', extra_files(['DRFHoleFits_A.hs']), multimod_compile_fail, ['DRFHoleFits', ''])
test('DRFPartialFields', normal, compile_fail, [''])
test('T16745', extra_files(['T16745C.hs', 'T16745B.hs']), multimod_compile_fail, ['T16745A', ''])
+test('FieldSelectors', normal, compile_fail, [''])
+test('NoFieldSelectorsFail', normal, multimod_compile_fail, ['NoFieldSelectorsFail','-v0'])
+test('NFSSuppressed', normal, compile_fail, [''])
+test('NFSMixed', normal, multimod_compile_fail, ['NFSMixed','-v0'])
test('DRF9156', normal, compile_fail, [''])
+test('NFS9156', normal, compile_fail, [''])
+test('NFSDuplicate', normal, compile_fail, [''])
+test('NFSExport', normal, compile_fail, [''])
+test('T18999_NoDisambiguateRecordFields', normal, compile_fail, [''])
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
index 908996f39e..7a211fd366 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
@@ -1,5 +1,5 @@
overloadedrecfldsfail14.hs:12:7: error:
- ‘y’ is not a record selector
+ No type has all these fields: ‘x’, ‘y’
In the expression: r {x = 3, y = False}
In an equation for ‘f’: f r = r {x = 3, y = False}
diff --git a/testsuite/tests/parser/should_compile/T14189.stderr b/testsuite/tests/parser/should_compile/T14189.stderr
index 8e79b4bc9f..cee8ecdbf9 100644
--- a/testsuite/tests/parser/should_compile/T14189.stderr
+++ b/testsuite/tests/parser/should_compile/T14189.stderr
@@ -126,7 +126,8 @@
[({ T14189.hs:3:11 }
(FieldLabel
{FastString: "f"}
- (False)
+ (NoDuplicateRecordFields)
+ (FieldSelectors)
{Name: T14189.f}))]
({ T14189.hs:3:3-8 }
(IEName
@@ -146,7 +147,8 @@
,(FieldGreName
(FieldLabel
{FastString: "f"}
- (False)
+ (NoDuplicateRecordFields)
+ (FieldSelectors)
{Name: T14189.f}))])])])
(Nothing)))
diff --git a/testsuite/tests/patsyn/should_fail/all.T b/testsuite/tests/patsyn/should_fail/all.T
index 5faea83c88..9520cc0b77 100644
--- a/testsuite/tests/patsyn/should_fail/all.T
+++ b/testsuite/tests/patsyn/should_fail/all.T
@@ -16,6 +16,7 @@ test('records-no-uni-update2', normal, compile_fail, [''])
test('records-mixing-fields', normal, compile_fail, [''])
test('records-exquant', normal, compile_fail, [''])
test('records-poly-update', normal, compile_fail, [''])
+test('records-nofieldselectors', normal, compile_fail, [''])
test('mixed-pat-syn-record-sels', normal, compile_fail, [''])
test('T11039', normal, compile_fail, [''])
test('T11039a', normal, compile, [''])
diff --git a/testsuite/tests/patsyn/should_fail/records-nofieldselectors.hs b/testsuite/tests/patsyn/should_fail/records-nofieldselectors.hs
new file mode 100644
index 0000000000..17fa340905
--- /dev/null
+++ b/testsuite/tests/patsyn/should_fail/records-nofieldselectors.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE PatternSynonyms #-}
+module ShouldFail where
+
+pattern Single{x} = [x]
+
+-- Selector
+selector :: Int
+selector = x [5]
+
+update :: [String]
+update = ["String"] { x = "updated" }
diff --git a/testsuite/tests/patsyn/should_fail/records-nofieldselectors.stderr b/testsuite/tests/patsyn/should_fail/records-nofieldselectors.stderr
new file mode 100644
index 0000000000..26124310fc
--- /dev/null
+++ b/testsuite/tests/patsyn/should_fail/records-nofieldselectors.stderr
@@ -0,0 +1,5 @@
+
+records-nofieldselectors.hs:9:12: error:
+ • Variable not in scope: x :: [a0] -> Int
+ • NB: ‘x’ is a field selector
+ that has been suppressed by NoFieldSelectors