Skip to content

Extensible types in pattern matching.#1459

Merged
maranget merged 7 commits intoocaml:trunkfrom
maranget:pr7661-squashed
Nov 21, 2017
Merged

Extensible types in pattern matching.#1459
maranget merged 7 commits intoocaml:trunkfrom
maranget:pr7661-squashed

Conversation

@maranget
Copy link
Copy Markdown
Contributor

@maranget maranget commented Oct 31, 2017

This pull request fixes MPR7661. The problem originated from incomplete handling of "extension" types.
Fixes mostly consist in

  1. Defining two compatibility functions in parmatch.ml (code sharing by functor): compat is the usual syntactic compatibility that considers all constructors to be distinct may_compat considers that constructors of identical arity from an extension type are identical (due to exception/constructor rebinding)
  2. In matching.ml, filtering of static data structures (such as the environment of handlers) is performed considering that constructors of identical arities from an extension type are the same. See functions ctx_matcher and constr_matcher in matching.ml.

Thanks to those fixes that apply to static data, compilation or or-patterns (split_or) can be simplified a bit and some functions that looked for constructor from extension types in patterns can be deleted.

@maranget maranget changed the title Handle extensible types Extensible types in pattern matching. Oct 31, 2017
Copy link
Copy Markdown
Member

@gasche gasche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic to distinguish extension constructors is duplicated in two places: in the MayCompat functor argument, and in the ctx_matcher function. Would it be possible to factor the logic out of an auxiliary function used in both places? (For example it could be a constructor_description -> constructor_description -> [Compatible | Incompatible | Unknown] function :-)

Could we improve this test by looking at the types of the parameters? For types as well we know that two types are equal, may be equal or must be different. If the extension constructors have an argument position where the two types must be different, we know they are distinct.

val compats : pattern list -> pattern list -> bool

(* Exported compatibility,
"may_compat p q" returns true when p and q never admit a common instance;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returns false?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done, read return false

typing/env.mli Outdated
| Env_type of summary * Ident.t * type_declaration
| Env_extension of summary * Ident.t * extension_constructor
| Env_module of summary * Ident.t * module_declaration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably didn't intend to commit that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

"may_compat p q" returns true when p and q never admit a common instance;
returns true when they may have a common instance. *)
val may_compat : pattern -> pattern -> bool
val may_compats : pattern list -> pattern list -> bool
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering that may_compat and may_compats are not used (and indeed shouldn't be used) in parmatch, instead of defining them in parmatch and exporting them, could we export the functor and define the functions in matching.ml?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather leave this to a later refactoring, such as the one you have started. The functor belongs to some utility module. I remember that have created such a utility module (for printing).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functor doesn't seem to belong to an external utility module any more than may_compat itself. And doing the change now instead of later reduces the probability of people using the wrong function by mistake.

Your choice. :)

| [], [] -> true
| p::ps, q::qs -> compat p q && compats ps qs
| _,_ -> assert false (* By typing *)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation looks weird.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is weird, thanks.

(* NB: matcher_constr applies to default matrices.

In that context matching by constructors of extemsible
types degardes to arity checking, due to potential rebinding.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extensible*, degrades*

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@maranget
Copy link
Copy Markdown
Contributor Author

@gashe The logics is very simple, and the code is not so easy to factorize. I see no reason to change
the strange macthing on arity by constr_matcher.

As to you suggestion of considering types, I would not delay bug fix for this.

@gasche
Copy link
Copy Markdown
Member

gasche commented Oct 31, 2017

My suggestion was not meant as an immediate implementation requirement, but I think that (if you find it reasonable) it suggests that this logic may evolve in the future and it's important to have it one place only.

Do I correctly understand, in your reply, that it is okay if the compatibility test becomes more permissive (for example reasoning on types), but ctx_matcher keeps the same implementation? Or do we need the two to evolve in synchronization for correctness? (My understanding is that it is okay if the two desynchronize, but I would still think it is better if they are factored.)

@maranget
Copy link
Copy Markdown
Contributor Author

maranget commented Oct 31, 2017

Well I am not sure I understood your suggestion correctly. Let us reconsider all this.

You suggest having a function somewhere (In Types where we already have Types.equal_tag) that would compare constructors with a three value result (Eq|Maybe|Ne). Maybe would be the returned value for constructors of extension types of identical arity, You then suggest that this function could be made more precise by, say, considering the types of arguments.

My answer is that I do not know without trying, whether such a solution is feasible, without significant alterations of typically constr_matcher. I can try... (Asbtracting away specific comparison functions for constructors does not necessarily means adopting the three value solution we can also have two functions Types.equal_tag and Types,may_equal_tag, wich I happen to prefer.

@lpw25
Copy link
Copy Markdown
Contributor

lpw25 commented Oct 31, 2017

It's not particularly important, but I would suggest that an extension constructor compatibility test should probably live in Ctype as something like mcomp_extension_constructor since, if it uses type information, it will be extremely similar to Ctype.mcomp_variant_description.

@maranget
Copy link
Copy Markdown
Contributor Author

maranget commented Oct 31, 2017

@gasche, @trefis Finally followed your suggestions. The rebinding aware constructor comparison function is in types.ml
@lpw25 Looking at ctype.ml frightened me, type based optimization postponed :)

@trefis
Copy link
Copy Markdown
Contributor

trefis commented Oct 31, 2017

The factorization looks nice.

type based optimization postponed :)

Sounds fine to me.

@gasche
Copy link
Copy Markdown
Member

gasche commented Oct 31, 2017

Yes, the factorization is nice -- I didn't mean to seriously insist about the three-value return idea. Thanks!

(I haven't had the time yet to do a careful review of the whole patch.)

@damiendoligez damiendoligez added this to the 4.07-or-later milestone Nov 2, 2017
@maranget
Copy link
Copy Markdown
Contributor Author

maranget commented Nov 10, 2017

@gasche, @trefis, @damiendoligez I believe this patch is ready for being merged, would you do a formal review, please?

Tu veux bien être mon ami ?

@trefis
Copy link
Copy Markdown
Contributor

trefis commented Nov 10, 2017

Hi,

As I said off-line, I currently do not understand all of the bits in matching.ml. I'll give it a proper look this week-end or early next week.
(Of course that should not discourage Gabriel from doing a careful review :) )

Copy link
Copy Markdown
Contributor

@trefis trefis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the Changes nitpick this looks correct to me.

Changes Outdated
### Bug fixes
- MPR#7661: fix faulty compilation of patterns of extension types
(Luc Maranget, review by Thomas Refis and Gabriel Scherer, report by
Abdelraouf Ouadjaout and Thibault Suzanne)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC we want to keep things ordered by MPR/GPR number in the changelog, so this is misplaced.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and the entry should also reference the GPR: MPR#7661, GPR#1459: ...

Copy link
Copy Markdown
Member

@gasche gasche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on the basis of @trefis' review: while I agree with the broad lines of the patch and It looks correct, I have not had the time to review it in details.

@gasche
Copy link
Copy Markdown
Member

gasche commented Nov 21, 2017

@maranget I changed the way you rebased your PR -- next time we can do it together so that I show you my workflow.

It would be nice to squash all the commits into one, as they don't mean much independently of each other (and the commit messages, such as "Oups", do not need to be preserved for eternity). Would you like to do it yourself or should I take care of it?

@maranget
Copy link
Copy Markdown
Contributor Author

maranget commented Nov 21, 2017 via email

@maranget maranget merged commit 7f5f82d into ocaml:trunk Nov 21, 2017
@gasche
Copy link
Copy Markdown
Member

gasche commented Nov 21, 2017

This was not the right way to do it (the commit message sucks and the global squash is too large), but I guess I should have complained earlier.

When you use "squash and merge", (1) you lose any ability to have more than one commit, and (2) you have to remove the useless junk in the commit message (and hopefully write something readable) because by default it concatenates all the commit messages of all squash commits.

@maranget
Copy link
Copy Markdown
Contributor Author

Too late...

hhugo pushed a commit to janestreet/ocaml that referenced this pull request Nov 26, 2017
* Handle extensible types

* various typos

* Oups.

* Astract constructor equality that considers potential rebinding into Types.may_equal_constr

* Moved rebinbing aware pattern compatibility functions from parmatch.ml to
matching.ml. Various consequences.

* Change Changes

* change the Changes change
@hhugo
Copy link
Copy Markdown
Contributor

hhugo commented Nov 27, 2017

compiling jbuilder with trunk gives me the following error:

Fatal error: exception Invalid_argument("index out of bounds")
Raised by primitive operation at file "bytecomp/matching.ml", line 1582, characters 34-59
Called from file "list.ml", line 100, characters 12-15
Called from file "bytecomp/matching.ml", line 1582, characters 2-73
Called from file "bytecomp/matching.ml", line 1589, characters 4-48
Called from file "bytecomp/matching.ml", line 155, characters 16-28
Called from file "bytecomp/matching.ml", line 176, characters 14-39
Called from file "bytecomp/matching.ml", line 1618, characters 15-56
Called from file "bytecomp/matching.ml", line 1175, characters 25-39
Called from file "bytecomp/matching.ml", line 1179, characters 8-27
Called from file "bytecomp/matching.ml", line 2756, characters 40-59
Called from file "bytecomp/matching.ml", line 2683, characters 6-145
Called from file "bytecomp/matching.ml", line 2501, characters 36-64
Called from file "bytecomp/matching.ml", line 2543, characters 14-47
Called from file "bytecomp/matching.ml", line 2620, characters 20-131
Called from file "bytecomp/matching.ml", line 2623, characters 18-151
Called from file "bytecomp/matching.ml", line 2634, characters 6-31
Called from file "bytecomp/matching.ml", line 2683, characters 6-145
Called from file "bytecomp/matching.ml", line 2879, characters 28-71
Called from file "bytecomp/translcore.ml", line 700, characters 59-76
Called from file "bytecomp/translcore.ml", line 1074, characters 30-46
Called from file "bytecomp/translcore.ml", line 1081, characters 9-35
Called from file "list.ml", line 82, characters 20-23
Called from file "bytecomp/translcore.ml", line 1204, characters 9-29
Called from file "bytecomp/translcore.ml", line 1181, characters 8-68
Called from file "bytecomp/translcore.ml", line 1181, characters 8-68
Called from file "bytecomp/translcore.ml", line 1181, characters 8-68
Called from file "bytecomp/translcore.ml", line 703, characters 8-213
Called from file "bytecomp/translobj.ml", line 182, characters 17-20
Re-raised at file "bytecomp/translobj.ml", line 199, characters 4-13
Called from file "bytecomp/translcore.ml", line 1213, characters 20-35
Called from file "bytecomp/translmod.ml", line 519, characters 10-48
Called from file "bytecomp/translmod.ml", line 517, characters 12-69
Called from file "bytecomp/translmod.ml", line 517, characters 12-69
Called from file "bytecomp/translmod.ml", line 517, characters 12-69
Called from file "bytecomp/translmod.ml", line 435, characters 14-52
Called from file "bytecomp/translmod.ml", line 904, characters 16-74
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 871, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 915, characters 27-78
Called from file "bytecomp/translmod.ml", line 898, characters 37-188
Called from file "bytecomp/translmod.ml", line 871, characters 37-188
Called from file "bytecomp/translmod.ml", line 871, characters 37-188
Called from file "bytecomp/translmod.ml", line 871, characters 37-188
Called from file "bytecomp/translmod.ml", line 1031, characters 21-78
Called from file "bytecomp/translobj.ml", line 138, characters 13-18
Called from file "bytecomp/translmod.ml", line 1097, characters 18-65
Called from file "utils/misc.ml", line 28, characters 20-27
Re-raised at file "utils/misc.ml", line 28, characters 50-57
Called from file "driver/optcompile.ml" (inlined), line 67, characters 15-18
Called from file "driver/optcompile.ml", line 121, characters 10-133
Called from file "driver/optcompile.ml", line 139, characters 8-68
Re-raised at file "driver/optcompile.ml", line 144, characters 6-13
Called from file "utils/misc.ml", line 28, characters 20-27
Re-raised at file "utils/misc.ml", line 28, characters 50-57
Called from file "driver/compenv.ml", line 576, characters 6-35
Called from file "list.ml", line 100, characters 12-15
Called from file "driver/compenv.ml", line 652, characters 2-61
Called from file "driver/optmain.ml", line 253, characters 6-163
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Called from file "parsing/location.ml" (inlined), line 470, characters 31-61
Called from file "driver/optmain.ml", line 313, characters 6-37
Called from file "driver/optmain.ml", line 317, characters 2-9

@gasche gasche mentioned this pull request Dec 7, 2017
Octachron added a commit to Octachron/ocaml that referenced this pull request Dec 10, 2017
Octachron added a commit to Octachron/ocaml that referenced this pull request Dec 11, 2017
Octachron added a commit to Octachron/ocaml that referenced this pull request Dec 11, 2017
Octachron added a commit to Octachron/ocaml that referenced this pull request Dec 11, 2017
gasche pushed a commit to gasche/ocaml that referenced this pull request Dec 19, 2017
@gasche gasche mentioned this pull request Dec 19, 2017
xavierleroy added a commit that referenced this pull request Dec 21, 2017
Pattern matching fixes (cherry-pick of #1459 and #1538 against the bugfix branch 4.06).
EmileTrotignon pushed a commit to EmileTrotignon/ocaml that referenced this pull request Jan 12, 2024
- local blogs get their own dedicated page that lists their posts at https://ocaml.org/blog/[SOURCE_ID], as well as their own RSS feed at https://ocaml.org/blog/[SOURCE_ID]/feed.xml.
- For more clarity regarding the input format: we explicitly distinguish between the local blogs hosted on ocaml.org (they now live in the folder data/planet-local-blogs), and the external sources and individual posts (living in data/planet) when parsing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants