Skip to content

Fix inclusion checks for primitives #661

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

Merged
merged 1 commit into from
May 23, 2022
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ocaml/lambda/translcore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ let rec iter_exn_names f pat =
let transl_ident loc env ty path desc kind =
match desc.val_kind, kind with
| Val_prim p, Id_prim pmode ->
let poly_mode = transl_alloc_mode pmode in
let poly_mode = Option.map transl_alloc_mode pmode in
Translprim.transl_primitive loc p env ty ~poly_mode (Some path)
| Val_anc _, Id_value ->
raise(Error(to_location loc, Free_super_var))
Expand Down Expand Up @@ -373,7 +373,7 @@ and transl_exp0 ~in_new_scope ~scopes e =
if extra_args = [] then transl_apply_position pos
else Rc_normal
in
let prim_mode = transl_alloc_mode pmode in
let prim_mode = Option.map transl_alloc_mode pmode in
let lam =
Translprim.transl_primitive_application
(of_location ~scopes e.exp_loc) p e.exp_env prim_type prim_mode
Expand Down
11 changes: 7 additions & 4 deletions ocaml/lambda/translmod.ml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ let rec apply_coercion loc strict restr arg =
let carg = apply_coercion loc Alias cc_arg (Lvar param) in
apply_coercion_result loc strict arg [param, Pgenval] [carg] cc_res
| Tcoerce_primitive { pc_desc; pc_env; pc_type; pc_poly_mode } ->
let poly_mode = Translcore.transl_alloc_mode pc_poly_mode in
let poly_mode = Option.map Translcore.transl_alloc_mode pc_poly_mode in
Translprim.transl_primitive loc pc_desc pc_env pc_type ~poly_mode None
| Tcoerce_alias (env, path, cc) ->
let lam = transl_module_path loc env path in
Expand Down Expand Up @@ -613,7 +613,8 @@ and transl_structure ~scopes loc fields cc rootpath final_env = function
| Tcoerce_primitive p ->
let loc = of_location ~scopes p.pc_loc in
let poly_mode =
Translcore.transl_alloc_mode p.pc_poly_mode
Option.map
Translcore.transl_alloc_mode p.pc_poly_mode
in
Translprim.transl_primitive
loc p.pc_desc p.pc_env p.pc_type ~poly_mode None
Expand Down Expand Up @@ -1039,7 +1040,7 @@ let field_of_str loc str =
fun (pos, cc) ->
match cc with
| Tcoerce_primitive { pc_desc; pc_env; pc_type; pc_poly_mode } ->
let poly_mode = Translcore.transl_alloc_mode pc_poly_mode in
let poly_mode = Option.map Translcore.transl_alloc_mode pc_poly_mode in
Translprim.transl_primitive loc pc_desc pc_env pc_type ~poly_mode None
| Tcoerce_alias (env, path, cc) ->
let lam = transl_module_path loc env path in
Expand Down Expand Up @@ -1380,7 +1381,9 @@ let transl_store_structure ~scopes glob map prims aliases str =
List.fold_right (add_ident may_coerce) idlist subst

and store_primitive (pos, prim) cont =
let poly_mode = Translcore.transl_alloc_mode prim.pc_poly_mode in
let poly_mode =
Option.map Translcore.transl_alloc_mode prim.pc_poly_mode
in
Lsequence(Lprim(mod_setfield pos,
[Lprim(Pgetglobal glob, [], Loc_unknown);
Translprim.transl_primitive Loc_unknown
Expand Down
9 changes: 6 additions & 3 deletions ocaml/lambda/translprim.ml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ let prim_sys_argv =
let to_alloc_mode ~poly = function
| Prim_global, _ -> alloc_heap
| Prim_local, _ -> alloc_local
| Prim_poly, _ -> poly
| Prim_poly, _ ->
match poly with
| None -> assert false
| Some mode -> mode

let lookup_primitive loc poly pos p =
let mode = to_alloc_mode ~poly p.prim_native_repr_res in
Expand Down Expand Up @@ -714,8 +717,8 @@ let lambda_of_prim prim_name prim loc args arg_exps =
let check_primitive_arity loc p =
let mode =
match p.prim_native_repr_res with
| Prim_global, _ | Prim_poly, _ -> alloc_heap
| Prim_local, _ -> alloc_local
| Prim_global, _ | Prim_poly, _ -> Some alloc_heap
| Prim_local, _ -> Some alloc_local
in
let prim = lookup_primitive loc mode Rc_normal p in
let ok =
Expand Down
4 changes: 2 additions & 2 deletions ocaml/lambda/translprim.mli
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ val check_primitive_arity :
val transl_primitive :
Lambda.scoped_location -> Primitive.description -> Env.t ->
Types.type_expr ->
poly_mode:Lambda.alloc_mode ->
poly_mode:Lambda.alloc_mode option ->
Path.t option ->
Lambda.lambda

val transl_primitive_application :
Lambda.scoped_location -> Primitive.description -> Env.t ->
Types.type_expr -> Lambda.alloc_mode -> Path.t ->
Types.type_expr -> Lambda.alloc_mode option -> Path.t ->
Typedtree.expression option ->
Lambda.lambda list -> Typedtree.expression list ->
Lambda.region_close -> Lambda.lambda
Expand Down
11 changes: 11 additions & 0 deletions ocaml/testsuite/tests/typing-local/local.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,17 @@ Error: Signature mismatch:
is not included in
val add : local_ int32 -> local_ int32 -> int32
|}]

module Contravariant_instantiation : sig
external to_int_trunc : Int64.t -> int = "%int64_to_int"
end = struct
external to_int_trunc : (Int64.t [@local_opt]) -> int = "%int64_to_int"
end
[%%expect{|
module Contravariant_instantiation :
sig external to_int_trunc : Int64.t -> int = "%int64_to_int" end
|}]

(* Return modes *)
let zx : int ref -> (int -> unit) = (:=)
let zz : local_ (int ref) -> int -> unit = (:=)
Expand Down
6 changes: 6 additions & 0 deletions ocaml/typing/btype.ml
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,12 @@ module Alloc_mode = struct
| Ok (), Ok () -> Ok ()
| Error (), _ | _, Error () -> Error ()

let make_global_exn t =
submode_exn t global

let make_local_exn t =
submode_exn local t

let next_id = ref (-1)
let fresh () =
incr next_id;
Expand Down
4 changes: 4 additions & 0 deletions ocaml/typing/btype.mli
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ module Alloc_mode : sig

val equate : t -> t -> (unit, unit) result

val make_global_exn : t -> unit

val make_local_exn : t -> unit

val join_const : const -> const -> const

val join : t list -> t
Expand Down
13 changes: 8 additions & 5 deletions ocaml/typing/ctype.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1543,12 +1543,15 @@ let instance_label fixed lbl =
let prim_mode mvar = function
| Primitive.Prim_global, _ -> Alloc_mode.global
| Primitive.Prim_local, _ -> Alloc_mode.local
| Primitive.Prim_poly, _ -> mvar
| Primitive.Prim_poly, _ ->
match mvar with
| Some mvar -> mvar
| None -> assert false

let rec instance_prim_locals locals mvar macc finalret ty =
match locals, (repr ty).desc with
| l :: locals, Tarrow ((lbl,_,mret),arg,ret,commu) ->
let marg = prim_mode mvar l in
let marg = prim_mode (Some mvar) l in
let macc = Alloc_mode.join [marg; mret; macc] in
let mret =
match locals with
Expand All @@ -1566,12 +1569,12 @@ let instance_prim_mode (desc : Primitive.description) ty =
if is_poly desc.prim_native_repr_res ||
List.exists is_poly desc.prim_native_repr_args then
let mode = Alloc_mode.newvar () in
let finalret = prim_mode mode desc.prim_native_repr_res in
let finalret = prim_mode (Some mode) desc.prim_native_repr_res in
instance_prim_locals desc.prim_native_repr_args
mode Alloc_mode.global finalret ty,
mode
Some mode
else
ty, Alloc_mode.global
ty, None

(**** Instantiation with parameter substitution ****)

Expand Down
5 changes: 3 additions & 2 deletions ocaml/typing/ctype.mli
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,10 @@ val instance_label:
bool -> label_description -> type_expr list * type_expr * type_expr
(* Same, for a label *)
val prim_mode :
alloc_mode -> (Primitive.mode * Primitive.native_repr) -> alloc_mode
alloc_mode option -> (Primitive.mode * Primitive.native_repr)
-> alloc_mode
val instance_prim_mode:
Primitive.description -> type_expr -> type_expr * alloc_mode
Primitive.description -> type_expr -> type_expr * alloc_mode option

val apply:
Env.t -> type_expr list -> type_expr -> type_expr list -> type_expr
Expand Down
93 changes: 76 additions & 17 deletions ocaml/typing/includecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,62 @@ open Path
open Types
open Typedtree

type position = Ctype.Unification_trace.position = First | Second

(* Inclusion between value descriptions *)

exception Dont_match

type primitive_mismatch =
| Name
| Arity
| No_alloc of position
| Builtin
| Effects
| Coeffects
| Native_name
| Result_repr
| Argument_repr of int

let native_repr_args nra1 nra2 =
let rec loop i nra1 nra2 =
match nra1, nra2 with
| [], [] -> None
| [], _ :: _ -> assert false
| _ :: _, [] -> assert false
| (_, nr1) :: nra1, (_, nr2) :: nra2 ->
if not (Primitive.equal_native_repr nr1 nr2) then Some (Argument_repr i)
else loop (i+1) nra1 nra2
in
loop 1 nra1 nra2

let primitive_descriptions pd1 pd2 =
let open Primitive in
if not (String.equal pd1.prim_name pd2.prim_name) then
Some Name
else if not (Int.equal pd1.prim_arity pd2.prim_arity) then
Some Arity
else if (not pd1.prim_alloc) && pd2.prim_alloc then
Some (No_alloc First)
else if pd1.prim_alloc && (not pd2.prim_alloc) then
Some (No_alloc Second)
else if pd1.prim_c_builtin && pd2.prim_c_builtin then
Some Builtin
else if not (Primitive.equal_effects pd1.prim_effects pd2.prim_effects) then
Some Effects
else if not
(Primitive.equal_coeffects
pd1.prim_coeffects pd2.prim_coeffects) then
Some Coeffects
else if not (String.equal pd1.prim_native_name pd2.prim_native_name) then
Some Native_name
else if not
(Primitive.equal_native_repr
(snd pd1.prim_native_repr_res) (snd pd2.prim_native_repr_res)) then
Some Result_repr
else
native_repr_args pd1.prim_native_repr_args pd2.prim_native_repr_args

let value_descriptions ~loc env name
(vd1 : Types.value_description)
(vd2 : Types.value_description) =
Expand All @@ -34,22 +86,31 @@ let value_descriptions ~loc env name
vd1.val_attributes vd2.val_attributes
name;
match vd1.val_kind with
| Val_prim p1 ->
let ty1, mode1 = Ctype.instance_prim_mode p1 vd1.val_type in
begin match vd2.val_kind with
| Val_prim p2 ->
let ty2, _mode2 = Ctype.instance_prim_mode p2 vd2.val_type in
if not (Ctype.moregeneral env true ty1 ty2) then
raise Dont_match;
let mode1 : Primitive.mode =
match Btype.Alloc_mode.check_const mode1 with
| Some Global -> Prim_global
| Some Local -> Prim_local
| None -> Prim_poly
in
let p1 = Primitive.inst_mode mode1 p1 in
if p1 = p2 then Tcoerce_none else raise Dont_match
| Val_prim p1 -> begin
match vd2.val_kind with
| Val_prim p2 -> begin
let ty1_global, _ = Ctype.instance_prim_mode p1 vd1.val_type in
let ty2_global =
let ty2, mode2 = Ctype.instance_prim_mode p2 vd2.val_type in
Option.iter Btype.Alloc_mode.make_global_exn mode2;
ty2
in
if not (Ctype.moregeneral env true ty1_global ty2_global) then
raise Dont_match;
let ty1_local, _ = Ctype.instance_prim_mode p1 vd1.val_type in
let ty2_local =
let ty2, mode2 = Ctype.instance_prim_mode p2 vd2.val_type in
Option.iter Btype.Alloc_mode.make_local_exn mode2;
ty2
in
if not (Ctype.moregeneral env true ty1_local ty2_local) then
raise Dont_match;
match primitive_descriptions p1 p2 with
| None -> Tcoerce_none
| Some _ -> raise Dont_match
end
| _ ->
let ty1, mode1 = Ctype.instance_prim_mode p1 vd1.val_type in
if not (Ctype.moregeneral env true ty1 vd2.val_type) then
raise Dont_match;
let pc =
Expand Down Expand Up @@ -141,8 +202,6 @@ let type_manifest env ty1 params1 ty2 params2 priv2 =

(* Inclusion between type declarations *)

type position = Ctype.Unification_trace.position = First | Second

let choose ord first second =
match ord with
| First -> first
Expand Down
49 changes: 40 additions & 9 deletions ocaml/typing/primitive.ml
Original file line number Diff line number Diff line change
Expand Up @@ -276,19 +276,50 @@ let native_name p =
let byte_name p =
p.prim_name

let equal_boxed_integer bi1 bi2 =
match bi1, bi2 with
| Pnativeint, Pnativeint
| Pint32, Pint32
| Pint64, Pint64 ->
true
| (Pnativeint | Pint32 | Pint64), _ ->
false

let equal_native_repr nr1 nr2 =
match nr1, nr2 with
| Same_as_ocaml_repr, Same_as_ocaml_repr -> true
| Same_as_ocaml_repr,
(Unboxed_float | Unboxed_integer _ | Untagged_int) -> false
| Unboxed_float, Unboxed_float -> true
| Unboxed_float,
(Same_as_ocaml_repr | Unboxed_integer _ | Untagged_int) -> false
| Unboxed_integer bi1, Unboxed_integer bi2 -> equal_boxed_integer bi1 bi2
| Unboxed_integer _,
(Same_as_ocaml_repr | Unboxed_float | Untagged_int) -> false
| Untagged_int, Untagged_int -> true
| Untagged_int,
(Same_as_ocaml_repr | Unboxed_float | Unboxed_integer _) -> false

let equal_effects ef1 ef2 =
match ef1, ef2 with
| No_effects, No_effects -> true
| No_effects, (Only_generative_effects | Arbitrary_effects) -> false
| Only_generative_effects, Only_generative_effects -> true
| Only_generative_effects, (No_effects | Arbitrary_effects) -> false
| Arbitrary_effects, Arbitrary_effects -> true
| Arbitrary_effects, (No_effects | Only_generative_effects) -> false

let equal_coeffects cf1 cf2 =
match cf1, cf2 with
| No_coeffects, No_coeffects -> true
| No_coeffects, Has_coeffects -> false
| Has_coeffects, Has_coeffects -> true
| Has_coeffects, No_coeffects -> false

let native_name_is_external p =
let nat_name = native_name p in
nat_name <> "" && nat_name.[0] <> '%'

let inst_mode mode p =
let inst_repr = function
| Prim_poly, r -> mode, r
| (Prim_global|Prim_local) as m, r -> m, r
in
{ p with
prim_native_repr_args = List.map inst_repr p.prim_native_repr_args;
prim_native_repr_res = inst_repr p.prim_native_repr_res }

let report_error ppf err =
match err with
| Old_style_float_with_native_repr_attribute ->
Expand Down
7 changes: 5 additions & 2 deletions ocaml/typing/primitive.mli
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,16 @@ val print
val native_name: description -> string
val byte_name: description -> string

val equal_boxed_integer : boxed_integer -> boxed_integer -> bool
val equal_native_repr : native_repr -> native_repr -> bool
val equal_effects : effects -> effects -> bool
val equal_coeffects : coeffects -> coeffects -> bool

(** [native_name_is_externa] returns [true] iff the [native_name] for the
given primitive identifies that the primitive is not implemented in the
compiler itself. *)
val native_name_is_external : description -> bool

val inst_mode : mode -> description -> description

type error =
| Old_style_float_with_native_repr_attribute
| Old_style_noalloc_with_noalloc_attribute
Expand Down
4 changes: 2 additions & 2 deletions ocaml/typing/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4712,8 +4712,8 @@ and type_ident env ?(recarg=Rejected) lid =
match desc.val_kind with
| Val_prim prim ->
let ty, mode = instance_prim_mode prim (instance desc.val_type) in
begin match prim.prim_native_repr_res with
| Prim_poly, _ -> register_allocation_mode mode
begin match prim.prim_native_repr_res, mode with
| (Prim_poly, _), Some mode -> register_allocation_mode mode
| _ -> ()
end;
ty, Id_prim mode
Expand Down
Loading