diff options
author | Hécate Moonlight <hecate+gitlab@glitchbra.in> | 2022-02-23 21:21:14 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-04-12 11:11:06 -0400 |
commit | 5440f63ec4a584b8805a8ff49ba1bd26bc2c032d (patch) | |
tree | 51543906a90223699e436bdf781d32d968dc2e2e | |
parent | 20eca489df8c3dae80a584dede8fea40728bde3b (diff) | |
download | haskell-5440f63ec4a584b8805a8ff49ba1bd26bc2c032d.tar.gz |
Document that DuplicateRecordFields doesn't tolerates ambiguous fields
Fix #19891
-rw-r--r-- | docs/users_guide/exts/duplicate_record_fields.rst | 117 | ||||
-rw-r--r-- | docs/users_guide/exts/record_field_resolution.rst | 58 | ||||
-rw-r--r-- | docs/users_guide/exts/records.rst | 1 |
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 |