Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add injectivity annotations #9500

Merged
merged 16 commits into from Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions Changes
Expand Up @@ -3,6 +3,16 @@ Working version

### Language features:

* #9500: Injectivity annotations
One can now mark type parameters as injective, which is useful for
abstract types:
module Vec : sig type !'a t end = struct type 'a t = 'a array end
On non-abstract types, this can be used to check the injectivity of
parameters. Since all parameters of record and sum types are by definition
injective, this only makes sense for type abbreviations:
type !'a t = 'a list
(Jacques Garrigue, review by Jeremy Yallop and Leo White)

### Runtime system:

- #1795, #9543: modernize signal handling on Linux i386, PowerPC, and s390x,
Expand Down
2,053 changes: 1,135 additions & 918 deletions boot/menhir/parser.ml

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions manual/manual/refman/typedecl.etex
Expand Up @@ -36,12 +36,18 @@ type-params:
| '(' type-param { "," type-param } ')'
;
type-param:
[variance] "'" ident
[ext-variance] "'" ident
;
ext-variance:
variance [injectivity]
| injectivity [variance]
;
variance:
'+'
| '-'
;
injectivity: '!'
;
record-decl:
'{' field-decl { ';' field-decl } [';'] '}'
;
Expand Down Expand Up @@ -88,7 +94,9 @@ for type constructors with one parameter, or a list of type variables
@"('"ident_1,\ldots,"'"ident_n")"@, for type constructors with several
parameters. Each type parameter may be prefixed by a variance
constraint @"+"@ (resp. @"-"@) indicating that the parameter is
covariant (resp. contravariant). These type parameters can appear in
covariant (resp. contravariant), and an injectivity annotation @"!"@
indicating that the parameter can be deduced from the whole type.
These type parameters can appear in
the type expressions of the right-hand side of the definition,
optionally restricted by a variance constraint ; {\em i.e.\/} a
covariant parameter may only appear on the right side of a functional
Expand Down Expand Up @@ -200,6 +208,18 @@ constraints, the variance properties of the type constructor
are inferred from its definition, and the variance annotations are
only checked for conformance with the definition.

Injectivity annotations are only necessary for abstract types and
private row types, since they can otherwise be deduced from the type
declaration: all parameters are injective for record and variant type
declarations (including extensible types); for type abbreviations a
parameter is injective if it has an injective occurrence in its
defining equation (be it private or not). For constrained type
parameters in type abbreviations, they are injective if either they
appear at an injective position in the body, or if all their type
variables are injective; in particular, if a constrained type
parameter contains a variable that doesn't appear in the body, it
cannot be injective.
yallop marked this conversation as resolved.
Show resolved Hide resolved

\ikwd{constraint\@\texttt{constraint}}
The construct @ 'constraint' "'" ident '=' typexpr @ allows the
specification of
Expand Down
9 changes: 5 additions & 4 deletions parsing/ast_helper.mli
Expand Up @@ -204,7 +204,7 @@ module Val:
module Type:
sig
val mk: ?loc:loc -> ?attrs:attrs -> ?docs:docs -> ?text:text ->
?params:(core_type * variance) list ->
?params:(core_type * (variance * injectivity)) list ->
?cstrs:(core_type * core_type * loc) list ->
?kind:type_kind -> ?priv:private_flag -> ?manifest:core_type -> str ->
type_declaration
Expand All @@ -220,8 +220,8 @@ module Type:
module Te:
sig
val mk: ?loc:loc -> ?attrs:attrs -> ?docs:docs ->
?params:(core_type * variance) list -> ?priv:private_flag ->
lid -> extension_constructor list -> type_extension
?params:(core_type * (variance * injectivity)) list ->
?priv:private_flag -> lid -> extension_constructor list -> type_extension

val mk_exception: ?loc:loc -> ?attrs:attrs -> ?docs:docs ->
extension_constructor -> type_exception
Expand Down Expand Up @@ -454,7 +454,8 @@ module Cf:
module Ci:
sig
val mk: ?loc:loc -> ?attrs:attrs -> ?docs:docs -> ?text:text ->
?virt:virtual_flag -> ?params:(core_type * variance) list ->
?virt:virtual_flag ->
?params:(core_type * (variance * injectivity)) list ->
str -> 'a -> 'a class_infos
end

Expand Down
6 changes: 5 additions & 1 deletion parsing/asttypes.mli
Expand Up @@ -60,4 +60,8 @@ type 'a loc = 'a Location.loc = {
type variance =
| Covariant
| Contravariant
| Invariant
| NoVariance

type injectivity =
| Injective
| NoInjectivity
17 changes: 14 additions & 3 deletions parsing/parser.mly
Expand Up @@ -2942,9 +2942,20 @@ type_variable:
;

type_variance:
/* empty */ { Invariant }
| PLUS { Covariant }
| MINUS { Contravariant }
/* empty */ { NoVariance, NoInjectivity }
| PLUS { Covariant, NoInjectivity }
| MINUS { Contravariant, NoInjectivity }
| BANG { NoVariance, Injective }
| PLUS BANG | BANG PLUS { Covariant, Injective }
| MINUS BANG | BANG MINUS { Contravariant, Injective }
| INFIXOP2
{ if $1 = "+!" then Covariant, Injective else
if $1 = "-!" then Contravariant, Injective else
yallop marked this conversation as resolved.
Show resolved Hide resolved
expecting $loc($1) "type_variance" }
| PREFIXOP
{ if $1 = "!+" then Covariant, Injective else
if $1 = "!-" then Contravariant, Injective else
expecting $loc($1) "type_variance" }
;

(* A sequence of constructor declarations is either a single BAR, which
Expand Down
6 changes: 3 additions & 3 deletions parsing/parsetree.mli
Expand Up @@ -429,7 +429,7 @@ and value_description =
and type_declaration =
{
ptype_name: string loc;
ptype_params: (core_type * variance) list;
ptype_params: (core_type * (variance * injectivity)) list;
(* ('a1,...'an) t; None represents _*)
ptype_cstrs: (core_type * core_type * Location.t) list;
(* ... constraint T1=T1' ... constraint Tn=Tn' *)
Expand Down Expand Up @@ -497,7 +497,7 @@ and constructor_arguments =
and type_extension =
{
ptyext_path: Longident.t loc;
ptyext_params: (core_type * variance) list;
ptyext_params: (core_type * (variance * injectivity)) list;
ptyext_constructors: extension_constructor list;
ptyext_private: private_flag;
ptyext_loc: Location.t;
Expand Down Expand Up @@ -598,7 +598,7 @@ and class_type_field_desc =
and 'a class_infos =
{
pci_virt: virtual_flag;
pci_params: (core_type * variance) list;
pci_params: (core_type * (variance * injectivity)) list;
pci_name: string loc;
pci_expr: 'a;
pci_loc: Location.t;
Expand Down
10 changes: 7 additions & 3 deletions parsing/pprintast.ml
Expand Up @@ -118,10 +118,14 @@ let override = function

(* variance encoding: need to sync up with the [parser.mly] *)
let type_variance = function
| Invariant -> ""
| NoVariance -> ""
| Covariant -> "+"
| Contravariant -> "-"

let type_injectivity = function
| NoInjectivity -> ""
| Injective -> "!"

type construct =
[ `cons of expression list
| `list of expression list
Expand Down Expand Up @@ -1434,8 +1438,8 @@ and structure_item ctxt f x =
item_extension ctxt f e;
item_attributes ctxt f a

and type_param ctxt f (ct, a) =
pp f "%s%a" (type_variance a) (core_type ctxt) ct
and type_param ctxt f (ct, (a,b)) =
pp f "%s%s%a" (type_variance a) (type_injectivity b) (core_type ctxt) ct

and type_params ctxt f = function
| [] -> ()
Expand Down
4 changes: 2 additions & 2 deletions testsuite/tests/printing-types/disambiguation.ml
Expand Up @@ -6,14 +6,14 @@ type 'a x = private [> `x] as 'a;;
[%%expect {|
Line 1:
Error: Type declarations do not match:
type 'a x = private [> `x ] constraint 'a = 'a x
type !'a x = private [> `x ] constraint 'a = 'a x
is not included in
type 'a x
Their constraints differ.
|}, Principal{|
Line 1:
Error: Type declarations do not match:
type 'a x = private 'a constraint 'a = [> `x ]
type !'a x = private 'a constraint 'a = [> `x ]
is not included in
type 'a x
Their constraints differ.
Expand Down