summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHécate Moonlight <hecate+gitlab@glitchbra.in>2022-02-23 21:21:14 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-04-12 11:11:06 -0400
commit5440f63ec4a584b8805a8ff49ba1bd26bc2c032d (patch)
tree51543906a90223699e436bdf781d32d968dc2e2e
parent20eca489df8c3dae80a584dede8fea40728bde3b (diff)
downloadhaskell-5440f63ec4a584b8805a8ff49ba1bd26bc2c032d.tar.gz
Document that DuplicateRecordFields doesn't tolerates ambiguous fields
Fix #19891
-rw-r--r--docs/users_guide/exts/duplicate_record_fields.rst117
-rw-r--r--docs/users_guide/exts/record_field_resolution.rst58
-rw-r--r--docs/users_guide/exts/records.rst1
3 files changed, 70 insertions, 106 deletions
diff --git a/docs/users_guide/exts/duplicate_record_fields.rst b/docs/users_guide/exts/duplicate_record_fields.rst
index 8f0ace158b..086aab731a 100644
--- a/docs/users_guide/exts/duplicate_record_fields.rst
+++ b/docs/users_guide/exts/duplicate_record_fields.rst
@@ -29,110 +29,12 @@ names. For example, the following are permitted (just as with
f (MkT { x = b }) = b
-Field names used as selector functions or in record updates must be unambiguous,
-either because there is only one such field in scope, or because a type
-signature is supplied, as described in the following sections.
-
While :extension:`DuplicateRecordFields` permits multiple fields with the same
name in a single module, it does not permit a field and a normal value binding
to have the same name. For that, use :extension:`NoFieldSelectors`.
-Selector functions
-~~~~~~~~~~~~~~~~~~
-
-Fields may be used as selector functions only if they are unambiguous, so this
-is still not allowed if both ``S(x)`` and ``T(x)`` are in scope: ::
-
- bad r = x r
-
-**Warning**: the type-based disambiguation rules described in the remainder of
-this section are being removed (see the proposal `DuplicateRecordFields without
-ambiguous field access
-<https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst>`_).
-The :ghc-flag:`-Wambiguous-fields` option will warn about code that relies on
-these rules. In a future GHC release, such code will produce ambiguity errors.
-
-An ambiguous selector may be disambiguated by the type being "pushed down" to
-the occurrence of the selector (see :ref:`higher-rank-type-inference` for more
-details on what "pushed down" means). For example, the following are permitted: ::
-
- ok1 = x :: S -> Int
-
- ok2 :: S -> Int
- ok2 = x
-
- ok3 = k x -- assuming we already have k :: (S -> Int) -> _
-
-In addition, the datatype that is meant may be given as a type signature on the
-argument to the selector: ::
-
- ok4 s = x (s :: S)
-
-However, we do not infer the type of the argument to determine the datatype, or
-have any way of deferring the choice to the constraint solver. Thus the
-following is ambiguous: ::
-
- bad :: S -> Int
- bad s = x s
-
-Even though a field label is duplicated in its defining module, it may be
-possible to use the selector unambiguously elsewhere. For example, another
-module could import ``S(x)`` but not ``T(x)``, and then use ``x`` unambiguously.
-
-Record updates
-~~~~~~~~~~~~~~
-
-In a record update such as ``e { x = 1 }``, if there are multiple ``x`` fields
-in scope, then the type of the context must fix which record datatype is
-intended, or a type annotation must be supplied. Consider the following
-definitions: ::
-
- data S = MkS { foo :: Int }
- data T = MkT { foo :: Int, bar :: Int }
- data U = MkU { bar :: Int, baz :: Int }
-
-Without :extension:`DuplicateRecordFields`, an update mentioning ``foo`` will always be
-ambiguous if all these definitions were in scope. When the extension is enabled,
-and there is exactly one type that has all the fields being updated, that type will be used.
-For example: ::
-
- f x = x { foo = 3, bar = 2 }
-
-Here ``f`` must be updating ``T`` because neither ``S`` nor ``U`` have both
-fields.
-
-If there are multiple types with all the fields, type information may be used to
-disambiguate which record type is meant. **Warning**: the following rules are
-being removed (see the proposal `DuplicateRecordFields without ambiguous field
-access
-<https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst>`_).
-The :ghc-flag:`-Wambiguous-fields` option will warn about code that relies on
-these rules. In a future GHC release, such code will produce ambiguity errors.
-
-- Use the type being pushed in to the record update, as in the following: ::
-
- g1 :: T -> T
- g1 x = x { foo = 3 }
-
- g2 x = x { foo = 3 } :: T
-
- g3 = k (x { foo = 3 }) -- assuming we already have k :: T -> _
-
-- Use an explicit type signature on the record expression, as in: ::
-
- h x = (x :: T) { foo = 3 }
-
-The type of the expression being updated will not be inferred, and no
-constraint-solving will be performed, so the following will be rejected as
-ambiguous: ::
-
- let x :: T
- x = blah
- in x { foo = 3 }
-
- \x -> [x { foo = 3 }, blah :: T ]
-
- \ (x :: T) -> x { foo = 3 }
+As of GHC 9.4.1, selector names have to be entirely unambiguous (under the usual name resolution rules),
+while for record updates, there must be at most one datatype that has all the field names being updated.
Import and export of record fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -141,14 +43,17 @@ When :extension:`DuplicateRecordFields` is enabled, an ambiguous field must be e
as part of its datatype, rather than at the top level. For example, the
following is legal: ::
- module M (S(x), T(..)) where
- data S = MkS { x :: Int }
- data T = MkT { x :: Bool }
+ module M
+ ( S(x)
+ , T(..)
+ ) where
-However, this would not be permitted, because ``x`` is ambiguous: ::
+ data S = MkS { x :: Int }
- module M (x) where ...
+ data T = MkT { x :: Bool }
-Similar restrictions apply on import.
+However, this would not be permitted, because ``x`` is ambiguous: ::
+ module M (x) where ...
+The same restrictions apply on imports.
diff --git a/docs/users_guide/exts/record_field_resolution.rst b/docs/users_guide/exts/record_field_resolution.rst
new file mode 100644
index 0000000000..3209387d26
--- /dev/null
+++ b/docs/users_guide/exts/record_field_resolution.rst
@@ -0,0 +1,58 @@
+.. _record_field_resolution:
+
+Record field name resolution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A record field name `x` can be used in four contexts:
+
+#. In a record *construction*: ``C{ x = 3 }``
+#. In a record *update*: ``r{ x = 4 }``
+#. In a record *pattern match*: ``case r of C{ x = value } -> …``
+#. As a standalone record *selector*: ``x r``
+
+In these four cases, here are the rules for field name resolution:
+
+#. An unqualified name "x" is unambiguous *if and only if* there is just one "x" in scope unqualified.
+
+#. A qualified name "M.x" is unambiguous *if and only if* there is just one "M.x" in scope.
+
+Those rules are amended by the following extensions:
+
+* :extension:`DisambiguateRecordFields`: In record construction and pattern matching
+ (``C{ x = …}``), an unqualified field name ``x`` is unambiguous if and only if the data constructor (``C``)
+ has a field ``x``, and that field is in scope unqualified, or qualified as ``Q.x``, regardless of ``Q``.
+ Similarly, in record construction and pattern matching, a qualified field name ``M.x`` is unambiguous if and only if the the data
+ constructor (``C``) has a field ``x``, and that field is in scope qualified as ``M.x``.
+
+ In record updates (``r{ x = 3 }``), the field name x is unambiguous if and only if there is just one field name x in scope unqualified.
+ Similarly, the record update with a qualified field ``r{ M.x = 3 }`` is unambiguous if just one
+ field name is in scope as ``M.x``.
+ In both cases, non-field names are ignored.
+* :extension:`DuplicateRecordFields`: This extension allows record updates if exactly
+ one type has all the fields being updated, even if they are individually ambiguous according to the two rules for field name resolution above.
+
+ For example::
+
+ data S = MkS1 { x :: Int, y :: Bool }
+ | MkS2 { x :: Int }
+
+ data T = MkT1 { x :: Int, z :: Bool }
+ | MkT2 { z :: Bool }
+
+ f r = r{ x=3, y=True }
+
+The only data type that has both ``x`` and ``y`` as fields is ``S``, so the field names ``x`` and ``y``
+refer unambiguously to data type ``S``.
+
+* :extension:`NoFieldSelectors`: This extension being enabled means that field selector names in scope will be ignored in an expression context.
+
+ For example::
+
+ data T = MkT { x :: Int }
+
+ x :: String
+ x = "Hello
+
+ f = x
+
+With ``NoFieldSelectors`` the ``x`` in ``f``'s right hand side refers to the ``x :: String``, not to the field ``x``.
diff --git a/docs/users_guide/exts/records.rst b/docs/users_guide/exts/records.rst
index b1e3f84a7c..56cd733213 100644
--- a/docs/users_guide/exts/records.rst
+++ b/docs/users_guide/exts/records.rst
@@ -6,6 +6,7 @@ Records
.. toctree::
:maxdepth: 1
+ record_field_resolution
traditional_record_syntax
field_selectors_and_type_applications
disambiguate_record_fields