summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Doligez <damien.doligez@inria.fr>2016-05-25 16:29:05 +0200
committerDamien Doligez <damien.doligez@inria.fr>2016-07-21 13:51:46 +0200
commitd5a6e50ebee73ff98c4179bba7570cdd9e488a35 (patch)
treee47a161d4a0d06c3266ddd3eabb0abd6a9e1ba3d
parente82191fea3890426e4499668041c14694fef8dd2 (diff)
downloadocaml-d5a6e50ebee73ff98c4179bba7570cdd9e488a35.tar.gz
GPR#606: add unboxed types
-rw-r--r--.depend110
-rw-r--r--Changes5
-rw-r--r--asmcomp/cmmgen.ml2
-rwxr-xr-xboot/ocamlcbin10843725 -> 2113161 bytes
-rwxr-xr-xboot/ocamldepbin698545 -> 710372 bytes
-rwxr-xr-xboot/ocamllexbin265766 -> 267603 bytes
-rw-r--r--bytecomp/bytegen.ml3
-rw-r--r--bytecomp/matching.ml14
-rw-r--r--bytecomp/printlambda.ml2
-rw-r--r--bytecomp/translcore.ml23
-rw-r--r--bytecomp/typeopt.ml15
-rw-r--r--byterun/caml/alloc.h15
-rw-r--r--driver/compenv.ml1
-rw-r--r--driver/main.ml2
-rw-r--r--driver/main_args.ml22
-rw-r--r--driver/main_args.mli2
-rw-r--r--driver/optmain.ml2
-rw-r--r--man/ocaml.m11
-rw-r--r--man/ocamlc.m16
-rw-r--r--man/ocamlopt.m15
-rw-r--r--manual/manual/cmds/comp.etex13
-rw-r--r--manual/manual/cmds/intf-c.etex40
-rw-r--r--manual/manual/cmds/native.etex13
-rw-r--r--manual/manual/refman/exten.etex16
-rw-r--r--ocamldoc/odoc_args.ml2
-rwxr-xr-xparsing/builtin_attributes.ml16
-rwxr-xr-xparsing/builtin_attributes.mli4
-rw-r--r--testsuite/tests/typing-unboxed-types/Makefile3
-rw-r--r--testsuite/tests/typing-unboxed-types/test.ml121
-rw-r--r--testsuite/tests/typing-unboxed-types/test.ml.reference162
-rw-r--r--tools/ocamlcp.ml2
-rw-r--r--tools/ocamloptp.ml2
-rw-r--r--toplevel/genprintval.ml28
-rw-r--r--toplevel/opttopmain.ml2
-rw-r--r--toplevel/topmain.ml2
-rw-r--r--typing/ctype.ml2
-rw-r--r--typing/datarepr.ml28
-rw-r--r--typing/datarepr.mli8
-rw-r--r--typing/includecore.ml16
-rw-r--r--typing/includecore.mli1
-rw-r--r--typing/oprint.ml6
-rw-r--r--typing/outcometree.mli1
-rw-r--r--typing/parmatch.ml3
-rw-r--r--typing/predef.ml1
-rw-r--r--typing/printtyp.ml2
-rw-r--r--typing/subst.ml1
-rw-r--r--typing/typeclass.ml3
-rw-r--r--typing/typecore.ml5
-rw-r--r--typing/typedecl.ml181
-rw-r--r--typing/typedecl.mli7
-rw-r--r--typing/typemod.ml1
-rw-r--r--typing/types.ml9
-rw-r--r--typing/types.mli9
-rw-r--r--utils/clflags.ml2
-rw-r--r--utils/clflags.mli2
-rw-r--r--utils/config.mlp4
-rw-r--r--utils/warnings.ml16
-rw-r--r--utils/warnings.mli1
58 files changed, 882 insertions, 113 deletions
diff --git a/.depend b/.depend
index d650e1aefb..482bf580d8 100644
--- a/.depend
+++ b/.depend
@@ -1,5 +1,5 @@
-utils/arg_helper.cmo : utils/arg_helper.cmi
-utils/arg_helper.cmx : utils/arg_helper.cmi
+utils/arg_helper.cmo : utils/misc.cmi utils/arg_helper.cmi
+utils/arg_helper.cmx : utils/misc.cmx utils/arg_helper.cmi
utils/arg_helper.cmi :
utils/ccomp.cmo : utils/misc.cmi utils/config.cmi utils/clflags.cmi \
utils/ccomp.cmi
@@ -180,11 +180,11 @@ typing/ctype.cmx : typing/types.cmx typing/subst.cmx typing/predef.cmx \
typing/ctype.cmi : typing/types.cmi typing/path.cmi parsing/longident.cmi \
typing/ident.cmi typing/env.cmi parsing/asttypes.cmi
typing/datarepr.cmo : typing/types.cmi typing/path.cmi parsing/location.cmi \
- typing/ident.cmi typing/btype.cmi parsing/asttypes.cmi \
- typing/datarepr.cmi
+ typing/ident.cmi parsing/builtin_attributes.cmi typing/btype.cmi \
+ parsing/asttypes.cmi typing/datarepr.cmi
typing/datarepr.cmx : typing/types.cmx typing/path.cmx parsing/location.cmx \
- typing/ident.cmx typing/btype.cmx parsing/asttypes.cmi \
- typing/datarepr.cmi
+ typing/ident.cmx parsing/builtin_attributes.cmx typing/btype.cmx \
+ parsing/asttypes.cmi typing/datarepr.cmi
typing/datarepr.cmi : typing/types.cmi typing/path.cmi typing/ident.cmi
typing/env.cmo : utils/warnings.cmi typing/types.cmi utils/tbl.cmi \
typing/subst.cmi typing/predef.cmi typing/path.cmi utils/misc.cmi \
@@ -218,12 +218,12 @@ typing/includeclass.cmx : typing/types.cmx typing/printtyp.cmx \
typing/includeclass.cmi : typing/types.cmi typing/env.cmi typing/ctype.cmi
typing/includecore.cmo : typing/types.cmi typing/typedtree.cmi \
typing/path.cmi utils/misc.cmi typing/ident.cmi typing/env.cmi \
- typing/ctype.cmi typing/btype.cmi parsing/asttypes.cmi \
- typing/includecore.cmi
+ typing/ctype.cmi parsing/builtin_attributes.cmi typing/btype.cmi \
+ parsing/asttypes.cmi typing/includecore.cmi
typing/includecore.cmx : typing/types.cmx typing/typedtree.cmx \
typing/path.cmx utils/misc.cmx typing/ident.cmx typing/env.cmx \
- typing/ctype.cmx typing/btype.cmx parsing/asttypes.cmi \
- typing/includecore.cmi
+ typing/ctype.cmx parsing/builtin_attributes.cmx typing/btype.cmx \
+ parsing/asttypes.cmi typing/includecore.cmi
typing/includecore.cmi : typing/types.cmi typing/typedtree.cmi \
typing/ident.cmi typing/env.cmi
typing/includemod.cmo : typing/types.cmi typing/typedtree.cmi utils/tbl.cmi \
@@ -382,19 +382,19 @@ typing/typedecl.cmo : utils/warnings.cmi typing/typetexp.cmi \
typing/printtyp.cmi typing/primitive.cmi typing/predef.cmi \
typing/path.cmi parsing/parsetree.cmi utils/misc.cmi \
parsing/longident.cmi parsing/location.cmi typing/includecore.cmi \
- typing/ident.cmi typing/env.cmi typing/ctype.cmi utils/config.cmi \
- utils/clflags.cmi parsing/builtin_attributes.cmi typing/btype.cmi \
- parsing/attr_helper.cmi parsing/asttypes.cmi parsing/ast_iterator.cmi \
- parsing/ast_helper.cmi typing/typedecl.cmi
+ typing/ident.cmi typing/env.cmi typing/datarepr.cmi typing/ctype.cmi \
+ utils/config.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \
+ typing/btype.cmi parsing/attr_helper.cmi parsing/asttypes.cmi \
+ parsing/ast_iterator.cmi parsing/ast_helper.cmi typing/typedecl.cmi
typing/typedecl.cmx : utils/warnings.cmx typing/typetexp.cmx \
typing/types.cmx typing/typedtree.cmx typing/subst.cmx \
typing/printtyp.cmx typing/primitive.cmx typing/predef.cmx \
typing/path.cmx parsing/parsetree.cmi utils/misc.cmx \
parsing/longident.cmx parsing/location.cmx typing/includecore.cmx \
- typing/ident.cmx typing/env.cmx typing/ctype.cmx utils/config.cmx \
- utils/clflags.cmx parsing/builtin_attributes.cmx typing/btype.cmx \
- parsing/attr_helper.cmx parsing/asttypes.cmi parsing/ast_iterator.cmx \
- parsing/ast_helper.cmx typing/typedecl.cmi
+ typing/ident.cmx typing/env.cmx typing/datarepr.cmx typing/ctype.cmx \
+ utils/config.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \
+ typing/btype.cmx parsing/attr_helper.cmx parsing/asttypes.cmi \
+ parsing/ast_iterator.cmx parsing/ast_helper.cmx typing/typedecl.cmi
typing/typedecl.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
typing/includecore.cmi typing/ident.cmi typing/env.cmi \
@@ -441,9 +441,9 @@ typing/typemod.cmx : utils/warnings.cmx typing/typetexp.cmx typing/types.cmx \
parsing/asttypes.cmi parsing/ast_iterator.cmx typing/annot.cmi \
typing/typemod.cmi
typing/typemod.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
- parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \
- parsing/location.cmi typing/includemod.cmi typing/ident.cmi \
- typing/env.cmi parsing/asttypes.cmi
+ parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
+ typing/includemod.cmi typing/ident.cmi typing/env.cmi \
+ parsing/asttypes.cmi
typing/types.cmo : typing/primitive.cmi typing/path.cmi \
parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
typing/ident.cmi parsing/asttypes.cmi typing/types.cmi
@@ -533,17 +533,14 @@ bytecomp/dll.cmi :
bytecomp/emitcode.cmo : bytecomp/translmod.cmi typing/primitive.cmi \
bytecomp/opcodes.cmo utils/misc.cmi bytecomp/meta.cmi \
parsing/location.cmi bytecomp/lambda.cmi bytecomp/instruct.cmi \
- typing/ident.cmi typing/env.cmi utils/config.cmi bytecomp/cmo_format.cmi \
- utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \
- bytecomp/emitcode.cmi
+ typing/env.cmi utils/config.cmi bytecomp/cmo_format.cmi utils/clflags.cmi \
+ typing/btype.cmi parsing/asttypes.cmi bytecomp/emitcode.cmi
bytecomp/emitcode.cmx : bytecomp/translmod.cmx typing/primitive.cmx \
bytecomp/opcodes.cmx utils/misc.cmx bytecomp/meta.cmx \
parsing/location.cmx bytecomp/lambda.cmx bytecomp/instruct.cmx \
- typing/ident.cmx typing/env.cmx utils/config.cmx bytecomp/cmo_format.cmi \
- utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \
- bytecomp/emitcode.cmi
-bytecomp/emitcode.cmi : bytecomp/instruct.cmi typing/ident.cmi \
- bytecomp/cmo_format.cmi
+ typing/env.cmx utils/config.cmx bytecomp/cmo_format.cmi utils/clflags.cmx \
+ typing/btype.cmx parsing/asttypes.cmi bytecomp/emitcode.cmi
+bytecomp/emitcode.cmi : bytecomp/instruct.cmi bytecomp/cmo_format.cmi
bytecomp/instruct.cmo : typing/types.cmi typing/subst.cmi \
parsing/location.cmi bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi \
bytecomp/instruct.cmi
@@ -606,8 +603,8 @@ bytecomp/simplif.cmx : utils/warnings.cmx utils/tbl.cmx typing/stypes.cmx \
utils/misc.cmx parsing/location.cmx bytecomp/lambda.cmx typing/ident.cmx \
utils/config.cmx utils/clflags.cmx parsing/asttypes.cmi typing/annot.cmi \
bytecomp/simplif.cmi
-bytecomp/simplif.cmi : utils/misc.cmi parsing/location.cmi \
- bytecomp/lambda.cmi typing/ident.cmi
+bytecomp/simplif.cmi : parsing/location.cmi bytecomp/lambda.cmi \
+ typing/ident.cmi
bytecomp/switch.cmo : bytecomp/switch.cmi
bytecomp/switch.cmx : bytecomp/switch.cmi
bytecomp/switch.cmi :
@@ -689,10 +686,12 @@ bytecomp/translobj.cmx : typing/primitive.cmx utils/misc.cmx \
bytecomp/translobj.cmi : bytecomp/lambda.cmi typing/ident.cmi typing/env.cmi
bytecomp/typeopt.cmo : typing/types.cmi typing/typedtree.cmi \
typing/predef.cmi typing/path.cmi bytecomp/lambda.cmi typing/ident.cmi \
- typing/env.cmi typing/ctype.cmi bytecomp/typeopt.cmi
+ typing/env.cmi typing/ctype.cmi parsing/builtin_attributes.cmi \
+ bytecomp/typeopt.cmi
bytecomp/typeopt.cmx : typing/types.cmx typing/typedtree.cmx \
typing/predef.cmx typing/path.cmx bytecomp/lambda.cmx typing/ident.cmx \
- typing/env.cmx typing/ctype.cmx bytecomp/typeopt.cmi
+ typing/env.cmx typing/ctype.cmx parsing/builtin_attributes.cmx \
+ bytecomp/typeopt.cmi
bytecomp/typeopt.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
bytecomp/lambda.cmi typing/env.cmi
asmcomp/CSE.cmo : asmcomp/mach.cmi asmcomp/CSEgen.cmi asmcomp/arch.cmo
@@ -712,12 +711,12 @@ asmcomp/asmgen.cmo : asmcomp/un_anf.cmi bytecomp/translmod.cmi \
typing/primitive.cmi utils/misc.cmi asmcomp/mach.cmi parsing/location.cmi \
asmcomp/liveness.cmi middle_end/base_types/linkage_name.cmi \
asmcomp/linearize.cmi bytecomp/lambda.cmi asmcomp/interf.cmi \
- typing/ident.cmi asmcomp/flambda_to_clambda.cmi middle_end/flambda.cmi \
- asmcomp/emitaux.cmi asmcomp/emit.cmi asmcomp/deadcode.cmi \
- utils/config.cmi asmcomp/compilenv.cmi asmcomp/comballoc.cmi \
- asmcomp/coloring.cmi asmcomp/cmmgen.cmi asmcomp/cmm.cmi \
- asmcomp/closure.cmi utils/clflags.cmi asmcomp/clambda.cmi asmcomp/CSE.cmo \
- asmcomp/build_export_info.cmi asmcomp/asmgen.cmi
+ asmcomp/flambda_to_clambda.cmi middle_end/flambda.cmi asmcomp/emitaux.cmi \
+ asmcomp/emit.cmi asmcomp/deadcode.cmi utils/config.cmi \
+ asmcomp/compilenv.cmi asmcomp/comballoc.cmi asmcomp/coloring.cmi \
+ asmcomp/cmmgen.cmi asmcomp/cmm.cmi asmcomp/closure.cmi utils/clflags.cmi \
+ asmcomp/clambda.cmi asmcomp/CSE.cmo asmcomp/build_export_info.cmi \
+ asmcomp/asmgen.cmi
asmcomp/asmgen.cmx : asmcomp/un_anf.cmx bytecomp/translmod.cmx \
utils/timings.cmx middle_end/base_types/symbol.cmx asmcomp/split.cmx \
asmcomp/spill.cmx asmcomp/selection.cmx asmcomp/scheduling.cmx \
@@ -726,13 +725,13 @@ asmcomp/asmgen.cmx : asmcomp/un_anf.cmx bytecomp/translmod.cmx \
typing/primitive.cmx utils/misc.cmx asmcomp/mach.cmx parsing/location.cmx \
asmcomp/liveness.cmx middle_end/base_types/linkage_name.cmx \
asmcomp/linearize.cmx bytecomp/lambda.cmx asmcomp/interf.cmx \
- typing/ident.cmx asmcomp/flambda_to_clambda.cmx middle_end/flambda.cmx \
- asmcomp/emitaux.cmx asmcomp/emit.cmx asmcomp/deadcode.cmx \
- utils/config.cmx asmcomp/compilenv.cmx asmcomp/comballoc.cmx \
- asmcomp/coloring.cmx asmcomp/cmmgen.cmx asmcomp/cmm.cmx \
- asmcomp/closure.cmx utils/clflags.cmx asmcomp/clambda.cmx asmcomp/CSE.cmx \
- asmcomp/build_export_info.cmx asmcomp/asmgen.cmi
-asmcomp/asmgen.cmi : utils/timings.cmi bytecomp/lambda.cmi typing/ident.cmi \
+ asmcomp/flambda_to_clambda.cmx middle_end/flambda.cmx asmcomp/emitaux.cmx \
+ asmcomp/emit.cmx asmcomp/deadcode.cmx utils/config.cmx \
+ asmcomp/compilenv.cmx asmcomp/comballoc.cmx asmcomp/coloring.cmx \
+ asmcomp/cmmgen.cmx asmcomp/cmm.cmx asmcomp/closure.cmx utils/clflags.cmx \
+ asmcomp/clambda.cmx asmcomp/CSE.cmx asmcomp/build_export_info.cmx \
+ asmcomp/asmgen.cmi
+asmcomp/asmgen.cmi : utils/timings.cmi bytecomp/lambda.cmi \
middle_end/flambda.cmi asmcomp/cmm.cmi middle_end/backend_intf.cmi
asmcomp/asmlibrarian.cmo : utils/misc.cmi parsing/location.cmi \
asmcomp/export_info.cmi utils/config.cmi asmcomp/compilenv.cmi \
@@ -1949,7 +1948,6 @@ middle_end/base_types/variable.cmx : utils/misc.cmx utils/identifiable.cmx \
middle_end/base_types/variable.cmi
middle_end/base_types/variable.cmi : utils/identifiable.cmi typing/ident.cmi \
middle_end/base_types/compilation_unit.cmi
-driver/compdynlink.cmi :
driver/compenv.cmo : utils/warnings.cmi utils/misc.cmi parsing/location.cmi \
utils/config.cmi utils/clflags.cmi driver/compenv.cmi
driver/compenv.cmx : utils/warnings.cmx utils/misc.cmx parsing/location.cmx \
@@ -1960,7 +1958,7 @@ driver/compile.cmo : utils/warnings.cmi typing/typemod.cmi \
utils/timings.cmi typing/stypes.cmi bytecomp/simplif.cmi \
typing/printtyped.cmi typing/printtyp.cmi bytecomp/printlambda.cmi \
bytecomp/printinstr.cmi parsing/printast.cmi parsing/pprintast.cmi \
- driver/pparse.cmi utils/misc.cmi parsing/location.cmi bytecomp/lambda.cmi \
+ driver/pparse.cmi utils/misc.cmi parsing/location.cmi \
typing/includemod.cmi typing/env.cmi bytecomp/emitcode.cmi \
driver/compmisc.cmi driver/compenv.cmi utils/clflags.cmi utils/ccomp.cmi \
bytecomp/bytegen.cmi parsing/builtin_attributes.cmi driver/compile.cmi
@@ -1969,7 +1967,7 @@ driver/compile.cmx : utils/warnings.cmx typing/typemod.cmx \
utils/timings.cmx typing/stypes.cmx bytecomp/simplif.cmx \
typing/printtyped.cmx typing/printtyp.cmx bytecomp/printlambda.cmx \
bytecomp/printinstr.cmx parsing/printast.cmx parsing/pprintast.cmx \
- driver/pparse.cmx utils/misc.cmx parsing/location.cmx bytecomp/lambda.cmx \
+ driver/pparse.cmx utils/misc.cmx parsing/location.cmx \
typing/includemod.cmx typing/env.cmx bytecomp/emitcode.cmx \
driver/compmisc.cmx driver/compenv.cmx utils/clflags.cmx utils/ccomp.cmx \
bytecomp/bytegen.cmx parsing/builtin_attributes.cmx driver/compile.cmi
@@ -2056,7 +2054,7 @@ driver/pparse.cmx : utils/timings.cmx parsing/parsetree.cmi \
parsing/parse.cmx utils/misc.cmx parsing/location.cmx utils/config.cmx \
utils/clflags.cmx utils/ccomp.cmx parsing/ast_mapper.cmx \
parsing/ast_invariants.cmx driver/pparse.cmi
-driver/pparse.cmi : parsing/parsetree.cmi utils/misc.cmi
+driver/pparse.cmi : parsing/parsetree.cmi
toplevel/expunge.cmo : bytecomp/symtable.cmi bytecomp/runtimedef.cmi \
utils/misc.cmi typing/ident.cmi bytecomp/bytesections.cmi
toplevel/expunge.cmx : bytecomp/symtable.cmx bytecomp/runtimedef.cmx \
@@ -2064,13 +2062,13 @@ toplevel/expunge.cmx : bytecomp/symtable.cmx bytecomp/runtimedef.cmx \
toplevel/genprintval.cmo : typing/types.cmi typing/printtyp.cmi \
typing/predef.cmi typing/path.cmi typing/outcometree.cmi \
typing/oprint.cmi utils/misc.cmi parsing/longident.cmi typing/ident.cmi \
- typing/env.cmi typing/datarepr.cmi typing/ctype.cmi typing/btype.cmi \
- toplevel/genprintval.cmi
+ typing/env.cmi typing/datarepr.cmi typing/ctype.cmi \
+ parsing/builtin_attributes.cmi typing/btype.cmi toplevel/genprintval.cmi
toplevel/genprintval.cmx : typing/types.cmx typing/printtyp.cmx \
typing/predef.cmx typing/path.cmx typing/outcometree.cmi \
typing/oprint.cmx utils/misc.cmx parsing/longident.cmx typing/ident.cmx \
- typing/env.cmx typing/datarepr.cmx typing/ctype.cmx typing/btype.cmx \
- toplevel/genprintval.cmi
+ typing/env.cmx typing/datarepr.cmx typing/ctype.cmx \
+ parsing/builtin_attributes.cmx typing/btype.cmx toplevel/genprintval.cmi
toplevel/genprintval.cmi : typing/types.cmi typing/path.cmi \
typing/outcometree.cmi typing/env.cmi
toplevel/opttopdirs.cmo : utils/warnings.cmi typing/types.cmi \
@@ -2160,7 +2158,7 @@ toplevel/toploop.cmo : utils/warnings.cmi typing/typetexp.cmi \
parsing/location.cmi parsing/lexer.cmi typing/includemod.cmi \
typing/ident.cmi toplevel/genprintval.cmi typing/env.cmi \
bytecomp/emitcode.cmi bytecomp/dll.cmi utils/consistbl.cmi \
- utils/config.cmi driver/compmisc.cmi driver/compenv.cmi utils/clflags.cmi \
+ utils/config.cmi driver/compmisc.cmi utils/clflags.cmi \
bytecomp/bytegen.cmi typing/btype.cmi parsing/asttypes.cmi \
parsing/ast_helper.cmi toplevel/toploop.cmi
toplevel/toploop.cmx : utils/warnings.cmx typing/typetexp.cmx \
@@ -2174,7 +2172,7 @@ toplevel/toploop.cmx : utils/warnings.cmx typing/typetexp.cmx \
parsing/location.cmx parsing/lexer.cmx typing/includemod.cmx \
typing/ident.cmx toplevel/genprintval.cmx typing/env.cmx \
bytecomp/emitcode.cmx bytecomp/dll.cmx utils/consistbl.cmx \
- utils/config.cmx driver/compmisc.cmx driver/compenv.cmx utils/clflags.cmx \
+ utils/config.cmx driver/compmisc.cmx utils/clflags.cmx \
bytecomp/bytegen.cmx typing/btype.cmx parsing/asttypes.cmi \
parsing/ast_helper.cmx toplevel/toploop.cmi
toplevel/toploop.cmi : utils/warnings.cmi typing/types.cmi typing/path.cmi \
diff --git a/Changes b/Changes
index a9380ab906..4576b194b2 100644
--- a/Changes
+++ b/Changes
@@ -14,6 +14,11 @@ OCaml 4.04.0:
- GPR#508: Allow shortcut for extension on semicolons: ;%foo
(Jeremie Dimino)
+- GPR#606: optimized representation for immutable records with a single
+ field, and concrete types with a single constructor with a single argument.
+ This is triggered with a [@@unboxed] attribute on the type definition.
+ (Damien Doligez)
+
- PR#7233: Support GADT equations on non-local abstract types
(Jacques Garrigue)
diff --git a/asmcomp/cmmgen.ml b/asmcomp/cmmgen.ml
index 7c907ffaf1..d278ba8996 100644
--- a/asmcomp/cmmgen.ml
+++ b/asmcomp/cmmgen.ml
@@ -708,6 +708,8 @@ let rec expr_size env = function
RHS_floatblock (List.length args)
| Uprim (Pduprecord ((Record_regular | Record_inlined _), sz), _, _) ->
RHS_block sz
+ | Uprim (Pduprecord (Record_unboxed _, _), _, _) ->
+ assert false
| Uprim (Pduprecord (Record_extension, sz), _, _) ->
RHS_block (sz + 1)
| Uprim (Pduprecord (Record_float, sz), _, _) ->
diff --git a/boot/ocamlc b/boot/ocamlc
index 71a53c14c1..ddfed73cad 100755
--- a/boot/ocamlc
+++ b/boot/ocamlc
Binary files differ
diff --git a/boot/ocamldep b/boot/ocamldep
index 5d0fe22698..5bef2cebee 100755
--- a/boot/ocamldep
+++ b/boot/ocamldep
Binary files differ
diff --git a/boot/ocamllex b/boot/ocamllex
index aa242e1a3c..c6905e5d44 100755
--- a/boot/ocamllex
+++ b/boot/ocamllex
Binary files differ
diff --git a/bytecomp/bytegen.ml b/bytecomp/bytegen.ml
index 3e5c947255..96fdb5702b 100644
--- a/bytecomp/bytegen.ml
+++ b/bytecomp/bytegen.ml
@@ -150,6 +150,7 @@ let rec size_of_lambda = function
when check_recordwith_updates id body ->
begin match kind with
| Record_regular | Record_inlined _ -> RHS_block size
+ | Record_unboxed _ -> assert false
| Record_float -> RHS_floatblock size
| Record_extension -> RHS_block (size + 1)
end
@@ -163,6 +164,8 @@ let rec size_of_lambda = function
| Lprim (Pmakearray (Pgenarray, _), _, _) -> assert false
| Lprim (Pduprecord ((Record_regular | Record_inlined _), size), _, _) ->
RHS_block size
+ | Lprim (Pduprecord (Record_unboxed _, _), _, _) ->
+ assert false
| Lprim (Pduprecord (Record_extension, size), _, _) ->
RHS_block (size + 1)
| Lprim (Pduprecord (Record_float, size), _, _) -> RHS_floatblock size
diff --git a/bytecomp/matching.ml b/bytecomp/matching.ml
index c352abaf44..51f299f49e 100644
--- a/bytecomp/matching.ml
+++ b/bytecomp/matching.ml
@@ -1355,6 +1355,7 @@ let make_constr_matching p def ctx = function
else match cstr.cstr_tag with
Cstr_constant _ | Cstr_block _ ->
make_field_args p.pat_loc Alias arg 0 (cstr.cstr_arity - 1) argl
+ | Cstr_unboxed -> (arg, Alias) :: argl
| Cstr_extension _ ->
make_field_args p.pat_loc Alias arg 1 cstr.cstr_arity argl in
{pm=
@@ -1637,15 +1638,17 @@ let make_record_matching loc all_labels def = function
let lbl = all_labels.(pos) in
let access =
match lbl.lbl_repres with
- Record_regular | Record_inlined _ -> Pfield lbl.lbl_pos
- | Record_float -> Pfloatfield lbl.lbl_pos
- | Record_extension -> Pfield (lbl.lbl_pos + 1)
+ | Record_regular | Record_inlined _ ->
+ Lprim (Pfield lbl.lbl_pos, [arg], loc)
+ | Record_unboxed _ -> arg
+ | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [arg], loc)
+ | Record_extension -> Lprim (Pfield (lbl.lbl_pos + 1), [arg], loc)
in
let str =
match lbl.lbl_mut with
Immutable -> Alias
| Mutable -> StrictOpt in
- (Lprim(access, [arg], loc), str) :: make_args(pos + 1)
+ (access, str) :: make_args(pos + 1)
end in
let nfields = Array.length all_labels in
let def= make_default (matcher_record nfields) def in
@@ -2288,7 +2291,8 @@ let split_cases tag_lambda_list =
match cstr with
Cstr_constant n -> ((n, act) :: consts, nonconsts)
| Cstr_block n -> (consts, (n, act) :: nonconsts)
- | _ -> assert false in
+ | Cstr_unboxed -> (consts, (0, act) :: nonconsts)
+ | Cstr_extension _ -> assert false in
let const, nonconst = split_rec tag_lambda_list in
sort_int_lambda_list const,
sort_int_lambda_list nonconst
diff --git a/bytecomp/printlambda.ml b/bytecomp/printlambda.ml
index 1797cdb6af..4ac9c2505a 100644
--- a/bytecomp/printlambda.ml
+++ b/bytecomp/printlambda.ml
@@ -103,6 +103,8 @@ let record_rep ppf r =
match r with
| Record_regular -> fprintf ppf "regular"
| Record_inlined i -> fprintf ppf "inlined(%i)" i
+ | Record_unboxed false -> fprintf ppf "unboxed"
+ | Record_unboxed true -> fprintf ppf "inlined(unboxed)"
| Record_float -> fprintf ppf "float"
| Record_extension -> fprintf ppf "ext"
;;
diff --git a/bytecomp/translcore.ml b/bytecomp/translcore.ml
index ae293ba709..a505a01842 100644
--- a/bytecomp/translcore.ml
+++ b/bytecomp/translcore.ml
@@ -836,6 +836,8 @@ and transl_exp0 e =
end else begin match cstr.cstr_tag with
Cstr_constant n ->
Lconst(Const_pointer n)
+ | Cstr_unboxed ->
+ (match ll with [v] -> v | _ -> assert false)
| Cstr_block n ->
begin try
Lconst(Const_block(n, List.map extract_constant ll))
@@ -868,19 +870,22 @@ and transl_exp0 e =
transl_record e.exp_loc e.exp_env fields representation
extended_expression
| Texp_field(arg, _, lbl) ->
- let access =
- match lbl.lbl_repres with
- Record_regular | Record_inlined _ -> Pfield lbl.lbl_pos
- | Record_float -> Pfloatfield lbl.lbl_pos
- | Record_extension -> Pfield (lbl.lbl_pos + 1)
- in
- Lprim(access, [transl_exp arg], e.exp_loc)
+ let targ = transl_exp arg in
+ begin match lbl.lbl_repres with
+ Record_regular | Record_inlined _ ->
+ Lprim (Pfield lbl.lbl_pos, [targ], e.exp_loc)
+ | Record_unboxed _ -> targ
+ | Record_float -> Lprim (Pfloatfield lbl.lbl_pos, [targ], e.exp_loc)
+ | Record_extension ->
+ Lprim (Pfield (lbl.lbl_pos + 1), [targ], e.exp_loc)
+ end
| Texp_setfield(arg, _, lbl, newval) ->
let access =
match lbl.lbl_repres with
Record_regular
| Record_inlined _ ->
Psetfield(lbl.lbl_pos, maybe_pointer newval, Assignment)
+ | Record_unboxed _ -> assert false
| Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment)
| Record_extension ->
Psetfield (lbl.lbl_pos + 1, maybe_pointer newval, Assignment)
@@ -1278,6 +1283,7 @@ and transl_record loc env fields repres opt_init_expr =
let access =
match repres with
Record_regular | Record_inlined _ -> Pfield i
+ | Record_unboxed _ -> assert false
| Record_extension -> Pfield (i + 1)
| Record_float -> Pfloatfield i in
Lprim(access, [Lvar init_id], loc), field_kind
@@ -1298,6 +1304,7 @@ and transl_record loc env fields repres opt_init_expr =
match repres with
| Record_regular -> Lconst(Const_block(0, cl))
| Record_inlined tag -> Lconst(Const_block(tag, cl))
+ | Record_unboxed _ -> Lconst(match cl with [v] -> v | _ -> assert false)
| Record_float ->
Lconst(Const_float_array(List.map extract_float cl))
| Record_extension ->
@@ -1308,6 +1315,7 @@ and transl_record loc env fields repres opt_init_expr =
Lprim(Pmakeblock(0, mut, Some shape), ll, loc)
| Record_inlined tag ->
Lprim(Pmakeblock(tag, mut, Some shape), ll, loc)
+ | Record_unboxed _ -> (match ll with [v] -> v | _ -> assert false)
| Record_float ->
Lprim(Pmakearray (Pfloatarray, mut), ll, loc)
| Record_extension ->
@@ -1340,6 +1348,7 @@ and transl_record loc env fields repres opt_init_expr =
Record_regular
| Record_inlined _ ->
Psetfield(lbl.lbl_pos, maybe_pointer expr, Assignment)
+ | Record_unboxed _ -> assert false
| Record_float -> Psetfloatfield (lbl.lbl_pos, Assignment)
| Record_extension ->
Psetfield(lbl.lbl_pos + 1, maybe_pointer expr, Assignment)
diff --git a/bytecomp/typeopt.ml b/bytecomp/typeopt.ml
index bd42def19e..3aa05bbf85 100644
--- a/bytecomp/typeopt.ml
+++ b/bytecomp/typeopt.ml
@@ -21,7 +21,20 @@ open Typedtree
open Lambda
let scrape env ty =
- (Ctype.repr (Ctype.expand_head_opt env (Ctype.correct_levels ty))).desc
+ match
+ (Ctype.repr (Ctype.expand_head_opt env (Ctype.correct_levels ty))).desc
+ with
+ | Tconstr (p, _, _) as desc ->
+ begin match Env.find_type p env with
+ | {type_unboxed = {unboxed = true; _}; _} ->
+ begin match Typedecl.get_unboxed_type_representation env ty with
+ | None -> desc
+ | Some ty2 -> ty2.desc
+ end
+ | _ -> desc
+ | exception Not_found -> desc
+ end
+ | desc -> desc
let is_function_type env ty =
match scrape env ty with
diff --git a/byterun/caml/alloc.h b/byterun/caml/alloc.h
index 6942cf409e..48a2fbce45 100644
--- a/byterun/caml/alloc.h
+++ b/byterun/caml/alloc.h
@@ -50,6 +50,21 @@ CAMLextern value caml_alloc_final (mlsize_t wosize,
CAMLextern int caml_convert_flag_list (value, int *);
+/* Convenience functions to deal with unboxable types. */
+static inline value caml_alloc_unboxed (value arg) { return arg; }
+static inline value caml_alloc_boxed (value arg) {
+ value result = caml_alloc_small (1, 0);
+ Field (result, 0) = arg;
+ return result;
+}
+static inline value caml_field_unboxed (value arg) { return arg; }
+static inline value caml_field_boxed (value arg) { return Field (arg, 0); }
+
+/* Unannotated unboxable types are boxed by default. (may change in the
+ future) */
+#define caml_alloc_unboxable caml_alloc_boxed
+#define caml_field_unboxable caml_field_boxed
+
#ifdef __cplusplus
}
#endif
diff --git a/driver/compenv.ml b/driver/compenv.ml
index 338d4c36a1..e3f7812163 100644
--- a/driver/compenv.ml
+++ b/driver/compenv.ml
@@ -205,6 +205,7 @@ let read_one_param ppf position name v =
| "strict-sequence" -> set "strict-sequence" [ strict_sequence ] v
| "strict-formats" -> set "strict-formats" [ strict_formats ] v
| "thread" -> set "thread" [ use_threads ] v
+ | "unboxed-types" -> set "unboxed-types" [ unboxed_types ] v
| "unsafe" -> set "unsafe" [ fast ] v
| "verbose" -> set "verbose" [ verbose ] v
| "nopervasives" -> set "nopervasives" [ nopervasives ] v
diff --git a/driver/main.ml b/driver/main.ml
index 87086c10c9..dc8b9dff97 100644
--- a/driver/main.ml
+++ b/driver/main.ml
@@ -145,6 +145,8 @@ module Options = Main_args.Make_bytecomp_options (struct
let _no_strict_formats = unset strict_formats
let _thread = set use_threads
let _vmthread = set use_vmthreads
+ let _unboxed_types = set unboxed_types
+ let _no_unboxed_types = unset unboxed_types
let _unsafe = set fast
let _unsafe_string = set unsafe_string
let _use_prims s = use_prims := s
diff --git a/driver/main_args.ml b/driver/main_args.ml
index c4f2bad06d..55e6f5c219 100644
--- a/driver/main_args.ml
+++ b/driver/main_args.ml
@@ -472,6 +472,16 @@ let mk_unbox_closures_factor f =
Clflags.default_unbox_closures_factor
;;
+let mk_unboxed_types f =
+ "-unboxed-types", Arg.Unit f,
+ " unannotated unboxable types will be unboxed"
+;;
+
+let mk_no_unboxed_types f =
+ "-no-unboxed-types", Arg.Unit f,
+ " unannotated unboxable types will not be unboxed (default)"
+;;
+
let mk_unsafe f =
"-unsafe", Arg.Unit f,
" Do not compile bounds checking on array and string access"
@@ -742,6 +752,8 @@ module type Common_options = sig
val _no_strict_sequence : unit -> unit
val _strict_formats : unit -> unit
val _no_strict_formats : unit -> unit
+ val _unboxed_types : unit -> unit
+ val _no_unboxed_types : unit -> unit
val _unsafe : unit -> unit
val _unsafe_string : unit -> unit
val _version : unit -> unit
@@ -991,6 +1003,8 @@ struct
mk_strict_formats F._strict_formats;
mk_no_strict_formats F._no_strict_formats;
mk_thread F._thread;
+ mk_unboxed_types F._unboxed_types;
+ mk_no_unboxed_types F._no_unboxed_types;
mk_unsafe F._unsafe;
mk_unsafe_string F._unsafe_string;
mk_use_runtime F._use_runtime;
@@ -1050,6 +1064,8 @@ struct
mk_no_strict_sequence F._no_strict_sequence;
mk_strict_formats F._strict_formats;
mk_no_strict_formats F._no_strict_formats;
+ mk_unboxed_types F._unboxed_types;
+ mk_no_unboxed_types F._no_unboxed_types;
mk_unsafe F._unsafe;
mk_unsafe_string F._unsafe_string;
mk_version F._version;
@@ -1154,6 +1170,8 @@ struct
mk_unbox_closures F._unbox_closures;
mk_unbox_closures_factor F._unbox_closures_factor;
mk_inline_max_unroll F._inline_max_unroll;
+ mk_unboxed_types F._unboxed_types;
+ mk_no_unboxed_types F._no_unboxed_types;
mk_unsafe F._unsafe;
mk_unsafe_string F._unsafe_string;
mk_v F._v;
@@ -1251,6 +1269,8 @@ module Make_opttop_options (F : Opttop_options) = struct
mk_no_strict_formats F._no_strict_formats;
mk_unbox_closures F._unbox_closures;
mk_unbox_closures_factor F._unbox_closures_factor;
+ mk_unboxed_types F._unboxed_types;
+ mk_no_unboxed_types F._no_unboxed_types;
mk_unsafe F._unsafe;
mk_unsafe_string F._unsafe_string;
mk_verbose F._verbose;
@@ -1321,6 +1341,8 @@ struct
mk_strict_formats F._strict_formats;
mk_no_strict_formats F._no_strict_formats;
mk_thread F._thread;
+ mk_unboxed_types F._unboxed_types;
+ mk_no_unboxed_types F._no_unboxed_types;
mk_unsafe_string F._unsafe_string;
mk_v F._v;
mk_verbose F._verbose;
diff --git a/driver/main_args.mli b/driver/main_args.mli
index 5e146e25d7..b5b0eaaedb 100644
--- a/driver/main_args.mli
+++ b/driver/main_args.mli
@@ -39,6 +39,8 @@ module type Common_options = sig
val _no_strict_sequence : unit -> unit
val _strict_formats : unit -> unit
val _no_strict_formats : unit -> unit
+ val _unboxed_types : unit -> unit
+ val _no_unboxed_types : unit -> unit
val _unsafe : unit -> unit
val _unsafe_string : unit -> unit
val _version : unit -> unit
diff --git a/driver/optmain.ml b/driver/optmain.ml
index e9ae7fd6a6..6a8ea204d8 100644
--- a/driver/optmain.ml
+++ b/driver/optmain.ml
@@ -231,6 +231,8 @@ module Options = Main_args.Make_optcomp_options (struct
let _thread = set use_threads
let _unbox_closures = set unbox_closures
let _unbox_closures_factor f = unbox_closures_factor := f
+ let _unboxed_types = set unboxed_types
+ let _no_unboxed_types = clear unboxed_types
let _unsafe = set fast
let _unsafe_string = set unsafe_string
let _v () = print_version_and_library "native-code compiler"
diff --git a/man/ocaml.m b/man/ocaml.m
index 0214bdf5ec..1d32002296 100644
--- a/man/ocaml.m
+++ b/man/ocaml.m
@@ -190,6 +190,17 @@ interactive session.
.B \-strict\-sequence
Force the left-hand part of each sequence to have type unit.
.TP
+.B \-unboxed\-types
+When a type is unboxable (i.e. a record with a single argument or a
+concrete datatype with a single constructor of one argument) it will
+be unboxed unless annotated with
+.BR [@@ocaml.boxed] .
+.TP
+.B \-no-unboxed\-types
+When a type is unboxable it will be boxed unless annotated with
+.BR [@@ocaml.unboxed] .
+This is the default.
+.TP
.B \-unsafe
Turn bound checking off on array and string accesses (the
.BR v.(i) and s.[i]
diff --git a/man/ocamlc.m b/man/ocamlc.m
index ca064a89d8..23c98170bf 100644
--- a/man/ocamlc.m
+++ b/man/ocamlc.m
@@ -602,6 +602,17 @@ Compile or link multithreaded programs, in combination with the
system "threads" library described in
.IR The\ OCaml\ user's\ manual .
.TP
+.B \-unboxed\-types
+When a type is unboxable (i.e. a record with a single argument or a
+concrete datatype with a single constructor of one argument) it will
+be unboxed unless annotated with
+.BR [@@ocaml.boxed] .
+.TP
+.B \-no-unboxed\-types
+When a type is unboxable it will be boxed unless annotated with
+.BR [@@ocaml.unboxed] .
+This is the default.
+.TP
.B \-unsafe
Turn bound checking off for array and string accesses (the
.BR v.(i) and s.[i]
@@ -894,6 +905,9 @@ mutually recursive types.
60
\ \ Unused module declaration.
+61
+\ \ Unannotated unboxable type in primitive declaration.
+
The letters stand for the following sets of warnings. Any letter not
mentioned here corresponds to the empty set.
@@ -977,7 +991,7 @@ warnings or modify existing warnings.
The default setting is
.B \-warn\-error \-a+31
-(all warnings are non-fatal except 31).
+(only warning 31 is fatal).
.TP
.B \-warn\-help
Show the description of all available warning numbers.
diff --git a/man/ocamlopt.m b/man/ocamlopt.m
index a44c09e340..f3fb3470c4 100644
--- a/man/ocamlopt.m
+++ b/man/ocamlopt.m
@@ -548,6 +548,17 @@ Compile or link multithreaded programs, in combination with the
system threads library described in
.IR "The OCaml user's manual" .
.TP
+.B \-unboxed\-types
+When a type is unboxable (i.e. a record with a single argument or a
+concrete datatype with a single constructor of one argument) it will
+be unboxed unless annotated with
+.BR [@@ocaml.boxed] .
+.TP
+.B \-no-unboxed\-types
+When a type is unboxable it will be boxed unless annotated with
+.BR [@@ocaml.unboxed] .
+This is the default.
+.TP
.B \-unsafe
Turn bound checking off for array and string accesses (the
.BR v.(i) and s.[i]
@@ -615,8 +626,8 @@ compiling your program with later versions of OCaml when they add new
warnings or modify existing warnings.
The default setting is
-.B \-warn\-error \-a
-(all warnings are non-fatal).
+.B \-warn\-error \-a+31
+(only warning 31 is fatal).
.TP
.B \-warn\-help
Show the description of all available warning numbers.
diff --git a/manual/manual/cmds/comp.etex b/manual/manual/cmds/comp.etex
index 6ee5ce8d98..cf1f51abdf 100644
--- a/manual/manual/cmds/comp.etex
+++ b/manual/manual/cmds/comp.etex
@@ -429,6 +429,15 @@ invalid formats, as they will be rejected by future OCaml versions.
Compile or link multithreaded programs, in combination with the
system "threads" library described in chapter~\ref{c:threads}.
+\item["-unboxed-types"]
+When a type is unboxable (i.e. a record with a single argument or a
+concrete datatype with a single constructor of one argument) it will
+be unboxed unless annotated with "[@@ocaml.boxed]".
+
+\item["-no-unboxed-types"]
+When a type is unboxable it will be boxed unless annotated with
+"[@@ocaml.unboxed]". This is the default.
+
\item["-unsafe"]
Turn bound checking off for array and string accesses (the "v.(i)" and
"s.[i]" constructs). Programs compiled with "-unsafe" are therefore
@@ -507,7 +516,7 @@ that are currently defined are ignored. The warnings are as follows.
\end{options}
Some warnings are described in more detail in section~\ref{s:comp-warnings}.
-The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45".
+The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45-48-50".
It is displayed by "ocamlc -help".
Note that warnings 5 and 10 are not always triggered, depending on
the internals of the type checker.
@@ -526,7 +535,7 @@ arguments to "-warn-error"
in production code, because this can break your build when future versions
of OCaml add some new warnings.
-The default setting is "-warn-error -a" (all warnings are non-fatal).
+The default setting is "-warn-error -a+31" (only warning 31 is fatal).
\item["-warn-help"]
Show the description of all available warning numbers.
diff --git a/manual/manual/cmds/intf-c.etex b/manual/manual/cmds/intf-c.etex
index cab842f078..a9ec807800 100644
--- a/manual/manual/cmds/intf-c.etex
+++ b/manual/manual/cmds/intf-c.etex
@@ -522,6 +522,7 @@ This section describes how OCaml data types are encoded in the
\end{tableau}
\subsection{Tuples and records}
+\label{ss:tuples-and-records}
Tuples are represented by pointers to blocks, with tag~0.
@@ -535,6 +536,23 @@ As an optimization, records whose fields all have static type "float"
are represented as arrays of floating-point numbers, with tag
"Double_array_tag". (See the section below on arrays.)
+As another optimization, unboxable record types are represented
+specially; unboxable record types are the immutable record types that
+have only one field. An unboxable type will be represented in one of
+two ways: boxed or unboxed. Boxed record types are represented as
+described above (by a block with tag 0 or "Double_array_tag"). An
+unboxed record type is represented directly by the value of its field
+(i.e. there is no block to represent the record itself).
+
+The representation is chosen according to the following, in decreasing
+order of priority:
+\begin{itemize}
+\item An attribute ("[\@\@boxed]" or "[\@\@unboxed]") on the type declaration.
+\item A compiler option ("-unboxed-types" or "-no-unboxed-types").
+\item The default representation. In the present version of OCaml, the
+default is the boxed representation.
+\end{itemize}
+
\subsection{Arrays}
Arrays of integers and pointers are represented like tuples,
@@ -583,6 +601,14 @@ type t =
| E of t * t (* Third non-constant constructor -> block with tag 2 *)
\end{verbatim}
+
+As an optimization, unboxable concrete data types are represented
+specially; a concrete data type is unboxable if it has exactly one
+constructor and this constructor has exactly one argument. Unboxable
+concrete data types are represented in the same ways as unboxable
+record types: see the description in
+section~\ref{ss:tuples-and-records}.
+
\subsection{Objects}
Objects are represented as blocks with tag "Object_tag". The first
@@ -700,6 +726,13 @@ in the "int32" \var{v}.
in the "int64" \var{v}.
\item "Nativeint_val("\var{v}")" returns the long integer contained
in the "nativeint" \var{v}.
+\item "caml_field_unboxed("\var{v}")" returns the value of the field
+of a value \var{v} of any unboxed type (record or concrete data type).
+\item "caml_field_boxed("\var{v}")" returns the value of the field
+of a value \var{v} of any boxed type (record or concrete data type).
+\item "caml_field_unboxable("\var{v}")" calls either
+"caml_field_unboxed" or "caml_field_boxed" according to the default
+representation of unboxable types in the current version of OCaml.
\end{itemize}
The expressions "Field("\var{v}", "\var{n}")",
"Byte("\var{v}", "\var{n}")" and
@@ -757,6 +790,13 @@ sequences, copied from the pointer to a string array \var{p}
(a "char **"). \var{p} must be NULL-terminated.
\item "caml_alloc_float_array("\var{n}")" allocates an array of floating point
numbers of size \var{n}. The array initially contains uninitialized values.
+\item "caml_alloc_unboxed("\var{v}")" returns the value (of any unboxed
+type) whose field is the value \var{v}.
+\item "caml_alloc_boxed("\var{v}")" allocates and returns a value (of
+any boxed type) whose field is the value \var{v}.
+\item "caml_alloc_unboxable("\var{v}")" calls either
+"caml_alloc_unboxed" or "caml_alloc_boxed" according to the default
+representation of unboxable types in the current version of OCaml.
\end{itemize}
\subsubsection{Low-level interface}
diff --git a/manual/manual/cmds/native.etex b/manual/manual/cmds/native.etex
index 4033b598e3..4c3c4be9f7 100644
--- a/manual/manual/cmds/native.etex
+++ b/manual/manual/cmds/native.etex
@@ -408,6 +408,15 @@ invalid formats, as they will be rejected by future OCaml versions.
Compile or link multithreaded programs, in combination with the
system "threads" library described in chapter~\ref{c:threads}.
+\item["-unboxed-types"]
+When a type is unboxable (i.e. a record with a single argument or a
+concrete datatype with a single constructor of one argument) it will
+be unboxed unless annotated with "[@@ocaml.boxed]".
+
+\item["-no-unboxed-types"]
+When a type is unboxable it will be boxed unless annotated with
+"[@@ocaml.unboxed]". This is the default.
+
\item["-unsafe"]
Turn bound checking off for array and string accesses (the "v.(i)" and
"s.[i]" constructs). Programs compiled with "-unsafe" are therefore
@@ -478,7 +487,7 @@ that are currently defined are ignored. The warning are as follows.
\input{warnings-help.tex}
\end{options}
-The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45".
+The default setting is "-w +a-4-6-7-9-27-29-32..39-41..42-44-45-48-50".
It is displayed by "ocamlopt -help".
Note that warnings 5 and 10 are not always triggered, depending on
the internals of the type checker.
@@ -498,7 +507,7 @@ arguments to "-warn-error"
in production code, because this can break your build when future versions
of OCaml add some new warnings.
-The default setting is "-warn-error -a" (all warnings are non-fatal).
+The default setting is "-warn-error -a+31" (only warning 31 is fatal).
\item["-warn-help"]
Show the description of all available warning numbers.
diff --git a/manual/manual/refman/exten.etex b/manual/manual/refman/exten.etex
index f454b4c738..46a34ab615 100644
--- a/manual/manual/refman/exten.etex
+++ b/manual/manual/refman/exten.etex
@@ -1758,6 +1758,22 @@ Some attributes are understood by the type-checker:
enumerated types). Mutation of these immediate types does not activate the
garbage collector's write barrier, which can significantly boost performance in
programs relying heavily on mutable state.
+\item
+ "ocaml.unboxed" or "unboxed" can be used on a type definition if the
+ type is a single-field record or a concrete type with a single
+ constructor that has a single argument. It tells the compiler to
+ optimize the representation of the type by removing the block that
+ represents the record or the constructor (i.e. a value of this type
+ is physically equal to its argument). In the case of GADTs, an
+ additional restriction applies: the argument must not be an
+ existential variable, represented by an existential type variable,
+ or an abstract type constructor applied to an existential type
+ variable.
+\item
+ "ocaml.boxed" or "boxed" can be used on type definitions to mean
+ the opposite of "ocaml.unboxed": keep the unoptimized
+ representation of the type. When there is no annotation, the
+ default is currently "boxed" but it may change in the future.
\end{itemize}
\begin{verbatim}
diff --git a/ocamldoc/odoc_args.ml b/ocamldoc/odoc_args.ml
index 32028947d9..039c8d7000 100644
--- a/ocamldoc/odoc_args.ml
+++ b/ocamldoc/odoc_args.ml
@@ -222,6 +222,8 @@ module Options = Main_args.Make_ocamldoc_options(struct
let _no_strict_formats = unset Clflags.strict_formats
let _thread = set Clflags.use_threads
let _vmthread = set Clflags.use_vmthreads
+ let _unboxed_types = set Clflags.unboxed_types
+ let _no_unboxed_types = unset Clflags.unboxed_types
let _unsafe () = assert false
let _unsafe_string = set Clflags.unsafe_string
let _v () = Compenv.print_version_and_library "documentation generator"
diff --git a/parsing/builtin_attributes.ml b/parsing/builtin_attributes.ml
index a295d7dddb..bdbefcdf5e 100755
--- a/parsing/builtin_attributes.ml
+++ b/parsing/builtin_attributes.ml
@@ -195,3 +195,19 @@ let immediate =
| ({txt="ocaml.immediate"|"immediate"; _}, _) -> true
| _ -> false
)
+
+(* The "ocaml.boxed (default)" and "ocaml.unboxed (default)"
+ attributes cannot be input by the user, they are added by the
+ compiler when applying the default setting. This is done to record
+ in the .cmi the default used by the compiler when compiling the
+ source file because the default can change between compiler
+ invocations. *)
+
+let check l (x, _) = List.mem x.txt l
+
+let has_unboxed attr =
+ List.exists (check ["ocaml.unboxed"; "unboxed"])
+ attr
+
+let has_boxed attr =
+ List.exists (check ["ocaml.boxed"; "boxed"]) attr
diff --git a/parsing/builtin_attributes.mli b/parsing/builtin_attributes.mli
index 7c9b294999..9add63733f 100755
--- a/parsing/builtin_attributes.mli
+++ b/parsing/builtin_attributes.mli
@@ -24,6 +24,7 @@
ocaml.warn_on_literal_pattern
ocaml.deprecated_mutable
ocaml.immediate
+ ocaml.boxed / ocaml.unboxed
*)
@@ -49,3 +50,6 @@ val explicit_arity: Parsetree.attributes -> bool
val immediate: Parsetree.attributes -> bool
+
+val has_unboxed: Parsetree.attributes -> bool
+val has_boxed: Parsetree.attributes -> bool
diff --git a/testsuite/tests/typing-unboxed-types/Makefile b/testsuite/tests/typing-unboxed-types/Makefile
new file mode 100644
index 0000000000..9625a3fbc3
--- /dev/null
+++ b/testsuite/tests/typing-unboxed-types/Makefile
@@ -0,0 +1,3 @@
+BASEDIR=../..
+include $(BASEDIR)/makefiles/Makefile.toplevel
+include $(BASEDIR)/makefiles/Makefile.common
diff --git a/testsuite/tests/typing-unboxed-types/test.ml b/testsuite/tests/typing-unboxed-types/test.ml
new file mode 100644
index 0000000000..f187b76d81
--- /dev/null
+++ b/testsuite/tests/typing-unboxed-types/test.ml
@@ -0,0 +1,121 @@
+(* Check the unboxing *)
+
+(* For concrete types *)
+type t1 = A of string [@@ocaml.unboxed];;
+
+let x = A "foo" in
+Obj.repr x == Obj.repr (match x with A s -> s)
+;;
+
+(* For records *)
+type t2 = { f : string } [@@ocaml.unboxed];;
+
+let x = { f = "foo" } in
+Obj.repr x == Obj.repr x.f
+;;
+
+(* For inline records *)
+type t3 = B of { g : string } [@@ocaml.unboxed];;
+
+let x = B { g = "foo" } in
+Obj.repr x == Obj.repr (match x with B {g} -> g)
+;;
+
+(* Check unboxable types *)
+type t4 = C [@@ocaml.unboxed];; (* no argument *)
+type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *)
+type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *)
+type t6 = G of int | H [@@ocaml.unboxed];;
+type t7 = I of string | J of bool [@@ocaml.unboxed];;
+
+type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *)
+type t9 = K of { j : string; l : int } [@@ocaml.unboxed];;
+
+(* let rec must be rejected *)
+type t10 = A of t10 [@@ocaml.unboxed];;
+let rec x = A x;;
+
+(* Representation mismatch between module and signature must be rejected *)
+module M : sig
+ type t = A of string
+end = struct
+ type t = A of string [@@ocaml.unboxed]
+end;;
+
+module N : sig
+ type t = A of string [@@ocaml.unboxed]
+end = struct
+ type t = A of string
+end;;
+
+module O : sig
+ type t = { f : string }
+end = struct
+ type t = { f : string } [@@ocaml.unboxed]
+end;;
+
+module P : sig
+ type t = { f : string } [@@ocaml.unboxed]
+end = struct
+ type t = { f : string }
+end;;
+
+module Q : sig
+ type t = A of { f : string }
+end = struct
+ type t = A of { f : string } [@@ocaml.unboxed]
+end;;
+
+module R : sig
+ type t = A of { f : string } [@@ocaml.unboxed]
+end = struct
+ type t = A of { f : string }
+end;;
+
+
+(* Check interference with representation of float arrays. *)
+type t11 = L of float [@@ocaml.unboxed];;
+let x = Array.make 10 (L 3.14) (* represented as a flat array *)
+and f (a : t11 array) = a.(0) (* might wrongly assume an array of pointers *)
+in assert (f x = L 3.14);;
+
+
+(* Check for a potential infinite loop in the typing algorithm. *)
+type 'a t12 = M of 'a t12 [@@ocaml.unboxed];;
+let f (a : int t12 array) = a.(0);;
+
+(* Check for another possible loop *)
+type t13 = A : _ t12 -> t13 [@@ocaml.unboxed];;
+
+
+
+(* should work *)
+type t14;;
+type t15 = A of t14 [@@ocaml.unboxed];;
+
+(* should fail *)
+type 'a abs;;
+type t16 = A : _ abs -> t16 [@@ocaml.unboxed];;
+
+(* should work *)
+type t18 = A : _ list abs -> t18 [@@ocaml.unboxed];;
+
+(* should fail because the compiler knows that t is actually float and
+ optimizes the record's representation *)
+module S : sig
+ type t
+ type u = { f1 : t; f2 : t }
+end = struct
+ type t = A of float [@@ocaml.unboxed]
+ type u = { f1 : t; f2 : t }
+end;;
+
+
+(* implementing [@@immediate] with [@@ocaml.unboxed]: this works because the
+ representation of [t] is [int]
+ *)
+module T : sig
+ type t [@@immediate]
+end = struct
+ type t = A of int [@@ocaml.unboxed]
+end;;
diff --git a/testsuite/tests/typing-unboxed-types/test.ml.reference b/testsuite/tests/typing-unboxed-types/test.ml.reference
new file mode 100644
index 0000000000..b555db8d12
--- /dev/null
+++ b/testsuite/tests/typing-unboxed-types/test.ml.reference
@@ -0,0 +1,162 @@
+
+# type t1 = A of string [@@unboxed]
+# - : bool = true
+# type t2 = { f : string; } [@@unboxed]
+# - : bool = true
+# type t3 = B of { g : string; } [@@unboxed]
+# - : bool = true
+# Characters 29-58:
+ type t4 = C [@@ocaml.unboxed];; (* no argument *)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because its constructor has no argument.
+# Characters 0-45:
+ type t5 = D of int * string [@@ocaml.unboxed];; (* more than one argument *)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because
+ its constructor has more than one argument.
+# Characters 0-33:
+ type t5 = E | F [@@ocaml.unboxed];; (* more than one constructor *)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because it has more than one constructor.
+# Characters 0-40:
+ type t6 = G of int | H [@@ocaml.unboxed];;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because it has more than one constructor.
+# Characters 0-51:
+ type t7 = I of string | J of bool [@@ocaml.unboxed];;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because it has more than one constructor.
+# Characters 1-50:
+ type t8 = { h : bool; i : int } [@@ocaml.unboxed];; (* more than one field *)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because it has more than one field.
+# Characters 0-56:
+ type t9 = K of { j : string; l : int } [@@ocaml.unboxed];;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because
+ its constructor has more than one argument.
+# type t10 = A of t10 [@@unboxed]
+# Characters 12-15:
+ let rec x = A x;;
+ ^^^
+Error: This kind of expression is not allowed as right-hand side of `let rec'
+# Characters 121-172:
+ ......struct
+ type t = A of string [@@ocaml.unboxed]
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = A of string [@@unboxed] end
+ is not included in
+ sig type t = A of string end
+ Type declarations do not match:
+ type t = A of string [@@unboxed]
+ is not included in
+ type t = A of string
+ Their internal representations differ:
+ the first declaration uses unboxed representation.
+# Characters 63-96:
+ ......struct
+ type t = A of string
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = A of string end
+ is not included in
+ sig type t = A of string [@@unboxed] end
+ Type declarations do not match:
+ type t = A of string
+ is not included in
+ type t = A of string [@@unboxed]
+ Their internal representations differ:
+ the second declaration uses unboxed representation.
+# Characters 48-102:
+ ......struct
+ type t = { f : string } [@@ocaml.unboxed]
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = { f : string; } [@@unboxed] end
+ is not included in
+ sig type t = { f : string; } end
+ Type declarations do not match:
+ type t = { f : string; } [@@unboxed]
+ is not included in
+ type t = { f : string; }
+ Their internal representations differ:
+ the first declaration uses unboxed representation.
+# Characters 66-102:
+ ......struct
+ type t = { f : string }
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = { f : string; } end
+ is not included in
+ sig type t = { f : string; } [@@unboxed] end
+ Type declarations do not match:
+ type t = { f : string; }
+ is not included in
+ type t = { f : string; } [@@unboxed]
+ Their internal representations differ:
+ the second declaration uses unboxed representation.
+# Characters 53-112:
+ ......struct
+ type t = A of { f : string } [@@ocaml.unboxed]
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = A of { f : string; } [@@unboxed] end
+ is not included in
+ sig type t = A of { f : string; } end
+ Type declarations do not match:
+ type t = A of { f : string; } [@@unboxed]
+ is not included in
+ type t = A of { f : string; }
+ Their internal representations differ:
+ the first declaration uses unboxed representation.
+# Characters 71-112:
+ ......struct
+ type t = A of { f : string }
+ end..
+Error: Signature mismatch:
+ Modules do not match:
+ sig type t = A of { f : string; } end
+ is not included in
+ sig type t = A of { f : string; } [@@unboxed] end
+ Type declarations do not match:
+ type t = A of { f : string; }
+ is not included in
+ type t = A of { f : string; } [@@unboxed]
+ Their internal representations differ:
+ the second declaration uses unboxed representation.
+# type t11 = L of float [@@unboxed]
+# - : unit = ()
+# type 'a t12 = M of 'a t12 [@@unboxed]
+# val f : int t12 array -> int t12 = <fun>
+# type t13 = A : 'a t12 -> t13 [@@unboxed]
+# type t14
+# type t15 = A of t14 [@@unboxed]
+# type 'a abs
+# Characters 0-45:
+ type t16 = A : _ abs -> t16 [@@ocaml.unboxed];;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Error: This type cannot be unboxed because
+ it might contain both float and non-float values.
+ You should annotate it with [@@ocaml.boxed].
+# type t18 = A : 'a list abs -> t18 [@@unboxed]
+# * Characters 176-256:
+ ......struct
+ type t = A of float [@@ocaml.unboxed]
+ type u = { f1 : t; f2 : t }
+ end..
+Error: Signature mismatch:
+ ...
+ Type declarations do not match:
+ type u = { f1 : t; f2 : t; }
+ is not included in
+ type u = { f1 : t; f2 : t; }
+ Their internal representations differ:
+ the first declaration uses unboxed float representation.
+# * * module T : sig type t [@@immediate] end
+#
diff --git a/tools/ocamlcp.ml b/tools/ocamlcp.ml
index 5879ee602a..22d1e29aae 100644
--- a/tools/ocamlcp.ml
+++ b/tools/ocamlcp.ml
@@ -102,6 +102,8 @@ module Options = Main_args.Make_bytecomp_options (struct
let _no_strict_formats = option "-no-strict-formats"
let _thread () = option "-thread" ()
let _vmthread () = option "-vmthread" ()
+ let _unboxed_types = option "-unboxed-types"
+ let _no_unboxed_types = option "-no-unboxed-types"
let _unsafe = option "-unsafe"
let _unsafe_string = option "-unsafe-string"
let _use_prims s = option_with_arg "-use-prims" s
diff --git a/tools/ocamloptp.ml b/tools/ocamloptp.ml
index b903f390e2..188674af4e 100644
--- a/tools/ocamloptp.ml
+++ b/tools/ocamloptp.ml
@@ -128,6 +128,8 @@ module Options = Main_args.Make_optcomp_options (struct
let _thread = option "-thread"
let _unbox_closures = option "-unbox-closures"
let _unbox_closures_factor = option_with_int "-unbox-closures"
+ let _unboxed_types = option "-unboxed-types"
+ let _no_unboxed_types = option "-no-unboxed-types"
let _unsafe = option "-unsafe"
let _unsafe_string = option "-unsafe-string"
let _v = option "-v"
diff --git a/toplevel/genprintval.ml b/toplevel/genprintval.ml
index 2c9d8a0cb4..28682a9d09 100644
--- a/toplevel/genprintval.ml
+++ b/toplevel/genprintval.ml
@@ -365,9 +365,11 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
tree_of_val depth obj
(try Ctype.apply env decl.type_params body ty_list with
Ctype.Cannot_apply -> abstract_type)
- | {type_kind = Type_variant constr_list} ->
+ | {type_kind = Type_variant constr_list; type_unboxed} ->
+ let unbx = type_unboxed.unboxed in
let tag =
- if O.is_block obj
+ if unbx then Cstr_unboxed
+ else if O.is_block obj
then Cstr_block(O.tag obj)
else Cstr_constant(O.obj obj) in
let {cd_id;cd_args;cd_res} =
@@ -393,12 +395,12 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
in
tree_of_constr_with_args (tree_of_constr env path)
(Ident.name cd_id) false 0 depth obj
- ty_args
+ ty_args unbx
| Cstr_record lbls ->
let r =
tree_of_record_fields depth
env path type_params ty_list
- lbls 0 obj
+ lbls 0 obj unbx
in
Oval_constr(tree_of_constr env path
(Ident.name cd_id),
@@ -413,9 +415,12 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
| Record_extension -> 1
| _ -> 0
in
+ let unbx =
+ match rep with Record_unboxed _ -> true | _ -> false
+ in
tree_of_record_fields depth
env path decl.type_params ty_list
- lbl_list pos obj
+ lbl_list pos obj unbx
end
| {type_kind = Type_open} ->
tree_of_extension path depth obj
@@ -464,7 +469,7 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
end
and tree_of_record_fields depth env path type_params ty_list
- lbl_list pos obj =
+ lbl_list pos obj unboxed =
let rec tree_of_fields pos = function
| [] -> []
| {ld_id; ld_type} :: remainder ->
@@ -481,8 +486,9 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
if pos = 0 then tree_of_label env path name
else Oide_ident name
and v =
- nest tree_of_val (depth - 1) (O.field obj pos)
- ty_arg
+ if unboxed
+ then tree_of_val (depth - 1) obj ty_arg
+ else nest tree_of_val (depth - 1) (O.field obj pos) ty_arg
in
(lid, v) :: tree_of_fields (pos + 1) remainder
in
@@ -497,10 +503,10 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
tree_list start ty_list
and tree_of_constr_with_args
- tree_of_cstr cstr_name inlined start depth obj ty_args =
+ tree_of_cstr cstr_name inlined start depth obj ty_args unboxed =
let lid = tree_of_cstr cstr_name in
let args =
- if inlined then
+ if inlined || unboxed then
match ty_args with
| [ty] -> [ tree_of_val (depth - 1) obj ty ]
| _ -> assert false
@@ -533,7 +539,7 @@ module Make(O : OBJ)(EVP : EVALPATH with type valu = O.t) = struct
tree_of_constr_with_args
(fun x -> Oide_ident x) name (cstr.cstr_inlined <> None)
1 depth bucket
- cstr.cstr_args
+ cstr.cstr_args false
with Not_found | EVP.Error ->
match check_depth depth bucket ty with
Some x -> x
diff --git a/toplevel/opttopmain.ml b/toplevel/opttopmain.ml
index 7832a48656..3f5c5c005a 100644
--- a/toplevel/opttopmain.ml
+++ b/toplevel/opttopmain.ml
@@ -167,6 +167,8 @@ module Options = Main_args.Make_opttop_options (struct
let _S = set keep_asm_file
let _short_paths = clear real_paths
let _stdin () = file_argument ""
+ let _unboxed_types = set unboxed_types
+ let _no_unboxed_types = clear unboxed_types
let _unsafe = set fast
let _verbose = set verbose
let _version () = print_version ()
diff --git a/toplevel/topmain.ml b/toplevel/topmain.ml
index 42f0623cc3..16f0c76b8a 100644
--- a/toplevel/topmain.ml
+++ b/toplevel/topmain.ml
@@ -98,6 +98,8 @@ module Options = Main_args.Make_bytetop_options (struct
let _no_strict_sequence = clear strict_sequence
let _strict_formats = set strict_formats
let _no_strict_formats = clear strict_formats
+ let _unboxed_types = set unboxed_types
+ let _no_unboxed_types = clear unboxed_types
let _unsafe = set fast
let _unsafe_string = set unsafe_string
let _version () = print_version ()
diff --git a/typing/ctype.ml b/typing/ctype.ml
index a9d04555b8..7a576276fe 100644
--- a/typing/ctype.ml
+++ b/typing/ctype.ml
@@ -1100,6 +1100,7 @@ let new_declaration newtype manifest =
type_loc = Location.none;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
let instance_constructor ?in_pattern cstr =
@@ -4355,6 +4356,7 @@ let nondep_type_decl env mid id is_covariant decl =
type_loc = decl.type_loc;
type_attributes = decl.type_attributes;
type_immediate = decl.type_immediate;
+ type_unboxed = decl.type_unboxed;
}
with Not_found ->
clear_hash ();
diff --git a/typing/datarepr.ml b/typing/datarepr.ml
index c9be80ac5d..178af39665 100644
--- a/typing/datarepr.ml
+++ b/typing/datarepr.ml
@@ -49,7 +49,7 @@ let free_vars ?(param=false) ty =
let newgenconstr path tyl = newgenty (Tconstr (path, tyl, ref Mnil))
-let constructor_args priv cd_args cd_res path rep =
+let constructor_existentials cd_args cd_res =
let tyl =
match cd_args with
| Cstr_tuple l -> l
@@ -63,11 +63,20 @@ let constructor_args priv cd_args cd_res path rep =
let res_vars = free_vars type_ret in
TypeSet.elements (TypeSet.diff arg_vars_set res_vars)
in
+ (tyl, existentials)
+
+let constructor_args priv cd_args cd_res path rep =
+ let tyl, existentials = constructor_existentials cd_args cd_res in
match cd_args with
| Cstr_tuple l -> existentials, l, None
| Cstr_record lbls ->
let arg_vars_set = free_vars ~param:true (newgenty (Ttuple tyl)) in
let type_params = TypeSet.elements arg_vars_set in
+ let type_unboxed =
+ match rep with
+ | Record_unboxed _ -> { unboxed = true; default = false }
+ | _ -> { unboxed = false; default = false }
+ in
let tdecl =
{
type_params;
@@ -80,6 +89,7 @@ let constructor_args priv cd_args cd_res path rep =
type_loc = Location.none;
type_attributes = [];
type_immediate = false;
+ type_unboxed;
}
in
existentials,
@@ -104,16 +114,22 @@ let constructor_descrs ty_path decl cstrs =
in
let (tag, descr_rem) =
match cd_args with
- Cstr_tuple [] -> (Cstr_constant idx_const,
+ | _ when decl.type_unboxed.unboxed ->
+ assert (rem = []);
+ (Cstr_unboxed, [])
+ | Cstr_tuple [] -> (Cstr_constant idx_const,
describe_constructors (idx_const+1) idx_nonconst rem)
| _ -> (Cstr_block idx_nonconst,
describe_constructors idx_const (idx_nonconst+1) rem) in
-
let cstr_name = Ident.name cd_id in
let existentials, cstr_args, cstr_inlined =
+ let representation =
+ if decl.type_unboxed.unboxed
+ then Record_unboxed true
+ else Record_inlined idx_nonconst
+ in
constructor_args decl.type_private cd_args cd_res
- (Path.Pdot (ty_path, cstr_name, Path.nopos))
- (Record_inlined idx_nonconst)
+ (Path.Pdot (ty_path, cstr_name, Path.nopos)) representation
in
let cstr =
{ cstr_name;
@@ -201,7 +217,7 @@ let rec find_constr tag num_const num_nonconst = function
then c
else find_constr tag (num_const + 1) num_nonconst rem
| c :: rem ->
- if tag = Cstr_block num_nonconst
+ if tag = Cstr_block num_nonconst || tag = Cstr_unboxed
then c
else find_constr tag num_const (num_nonconst + 1) rem
diff --git a/typing/datarepr.mli b/typing/datarepr.mli
index de8a8c2858..8a85282add 100644
--- a/typing/datarepr.mli
+++ b/typing/datarepr.mli
@@ -34,3 +34,11 @@ exception Constr_not_found
val find_constr_by_tag:
constructor_tag -> constructor_declaration list ->
constructor_declaration
+
+val constructor_existentials :
+ constructor_arguments -> type_expr option -> type_expr list * type_expr list
+(** Takes [cd_args] and [cd_res] from a [constructor_declaration] and
+ returns:
+ - the types of the constructor's arguments
+ - the existential variables introduced by the constructor
+ *)
diff --git a/typing/includecore.ml b/typing/includecore.ml
index c367640b74..e94035c111 100644
--- a/typing/includecore.ml
+++ b/typing/includecore.ml
@@ -126,7 +126,8 @@ type type_mismatch =
| Field_arity of Ident.t
| Field_names of int * Ident.t * Ident.t
| Field_missing of bool * Ident.t
- | Record_representation of bool
+ | Record_representation of bool (* true means second one is unboxed float *)
+ | Unboxed_representation of bool (* true means second one is unboxed *)
| Immediate
let report_type_mismatch0 first second decl ppf err =
@@ -154,6 +155,10 @@ let report_type_mismatch0 first second decl ppf err =
pr "Their internal representations differ:@ %s %s %s"
(if b then second else first) decl
"uses unboxed float representation"
+ | Unboxed_representation b ->
+ pr "Their internal representations differ:@ %s %s %s"
+ (if b then second else first) decl
+ "uses unboxed representation"
| Immediate -> pr "%s is not an immediate type" first
let report_type_mismatch first second decl ppf =
@@ -236,6 +241,15 @@ let type_declarations ?(equality = false) env name decl1 id decl2 =
else [Constraint]
in
if err <> [] then err else
+ let err =
+ match (decl2.type_kind, decl1.type_unboxed.unboxed,
+ decl2.type_unboxed.unboxed) with
+ | Type_abstract, _, _ -> []
+ | _, true, false -> [Unboxed_representation false]
+ | _, false, true -> [Unboxed_representation true]
+ | _ -> []
+ in
+ if err <> [] then err else
let err = match (decl1.type_kind, decl2.type_kind) with
(_, Type_abstract) -> []
| (Type_variant cstrs1, Type_variant cstrs2) ->
diff --git a/typing/includecore.mli b/typing/includecore.mli
index 17278a4aff..8ddd59cddc 100644
--- a/typing/includecore.mli
+++ b/typing/includecore.mli
@@ -33,6 +33,7 @@ type type_mismatch =
| Field_names of int * Ident.t * Ident.t
| Field_missing of bool * Ident.t
| Record_representation of bool
+ | Unboxed_representation of bool
| Immediate
val value_descriptions:
diff --git a/typing/oprint.ml b/typing/oprint.ml
index 6531c1e309..02f236ccb7 100644
--- a/typing/oprint.ml
+++ b/typing/oprint.ml
@@ -506,6 +506,9 @@ and print_out_type_decl kwd ppf td =
let print_immediate ppf =
if td.otype_immediate then fprintf ppf " [%@%@immediate]" else ()
in
+ let print_unboxed ppf =
+ if td.otype_unboxed then fprintf ppf " [%@%@unboxed]" else ()
+ in
let print_out_tkind ppf = function
| Otyp_abstract -> ()
| Otyp_record lbls ->
@@ -523,11 +526,12 @@ and print_out_type_decl kwd ppf td =
print_private td.otype_private
!out_type ty
in
- fprintf ppf "@[<2>@[<hv 2>%t%a@]%t%t@]"
+ fprintf ppf "@[<2>@[<hv 2>%t%a@]%t%t%t@]"
print_name_params
print_out_tkind ty
print_constraints
print_immediate
+ print_unboxed
and print_out_constr ppf (name, tyl,ret_type_opt) =
let name =
diff --git a/typing/outcometree.mli b/typing/outcometree.mli
index 7d4cb5b6e1..b926c920a3 100644
--- a/typing/outcometree.mli
+++ b/typing/outcometree.mli
@@ -106,6 +106,7 @@ and out_type_decl =
otype_type: out_type;
otype_private: Asttypes.private_flag;
otype_immediate: bool;
+ otype_unboxed: bool;
otype_cstrs: (out_type * out_type) list }
and out_extension_constructor =
{ oext_name: string;
diff --git a/typing/parmatch.ml b/typing/parmatch.ml
index 57d470d1a5..b78227d794 100644
--- a/typing/parmatch.ml
+++ b/typing/parmatch.ml
@@ -1848,7 +1848,8 @@ let extendable_path path =
Path.same path Predef.path_option)
let rec collect_paths_from_pat r p = match p.pat_desc with
-| Tpat_construct(_, {cstr_tag=(Cstr_constant _|Cstr_block _)},ps) ->
+| Tpat_construct(_, {cstr_tag=(Cstr_constant _|Cstr_block _|Cstr_unboxed)},ps)
+ ->
let path = get_type_path p.pat_type p.pat_env in
List.fold_left
collect_paths_from_pat
diff --git a/typing/predef.ml b/typing/predef.ml
index db3d714caa..be90b46009 100644
--- a/typing/predef.ml
+++ b/typing/predef.ml
@@ -125,6 +125,7 @@ let decl_abstr =
type_newtype_level = None;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
let decl_abstr_imm = {decl_abstr with type_immediate = true}
diff --git a/typing/printtyp.ml b/typing/printtyp.ml
index b9c3badd38..f99d80abcd 100644
--- a/typing/printtyp.ml
+++ b/typing/printtyp.ml
@@ -863,6 +863,7 @@ let rec tree_of_type_decl id decl =
otype_type = ty;
otype_private = priv;
otype_immediate = immediate;
+ otype_unboxed = decl.type_unboxed.unboxed;
otype_cstrs = constraints }
and tree_of_constructor_arguments = function
@@ -1157,6 +1158,7 @@ let dummy =
type_newtype_level = None; type_loc = Location.none;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
let hide_rec_items = function
diff --git a/typing/subst.ml b/typing/subst.ml
index 6b05651782..85a529f80b 100644
--- a/typing/subst.ml
+++ b/typing/subst.ml
@@ -262,6 +262,7 @@ let type_declaration s decl =
type_loc = loc s decl.type_loc;
type_attributes = attrs s decl.type_attributes;
type_immediate = decl.type_immediate;
+ type_unboxed = decl.type_unboxed;
}
in
cleanup_types ();
diff --git a/typing/typeclass.ml b/typing/typeclass.ml
index f71adb974a..97a400c51c 100644
--- a/typing/typeclass.ml
+++ b/typing/typeclass.ml
@@ -1243,6 +1243,7 @@ let temp_abbrev loc env id arity =
type_loc = loc;
type_attributes = []; (* or keep attrs from the class decl? *)
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
env
in
@@ -1490,6 +1491,7 @@ let class_infos define_class kind
type_loc = cl.pci_loc;
type_attributes = []; (* or keep attrs from cl? *)
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
in
let (cl_params, cl_ty) =
@@ -1508,6 +1510,7 @@ let class_infos define_class kind
type_loc = cl.pci_loc;
type_attributes = []; (* or keep attrs from cl? *)
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
in
((cl, id, clty, ty_id, cltydef, obj_id, obj_abbr, cl_id, cl_abbr, ci_params,
diff --git a/typing/typecore.ml b/typing/typecore.ml
index 4cb5bf28d4..c17fc85238 100644
--- a/typing/typecore.ml
+++ b/typing/typecore.ml
@@ -772,8 +772,8 @@ module Label = NameChoice (struct
let unbound_name_error = Typetexp.unbound_label_error
let in_env lbl =
match lbl.lbl_repres with
- | Record_regular | Record_float -> true
- | Record_inlined _ | Record_extension -> false
+ | Record_regular | Record_float | Record_unboxed false -> true
+ | Record_unboxed true | Record_inlined _ | Record_extension -> false
end)
let disambiguate_label_by_ids keep closed ids labels =
@@ -2896,6 +2896,7 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
type_loc = loc;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
in
Ident.set_current_time ty.level;
diff --git a/typing/typedecl.ml b/typing/typedecl.ml
index 12a54b23f2..11e32edbef 100644
--- a/typing/typedecl.ml
+++ b/typing/typedecl.ml
@@ -55,11 +55,27 @@ type error =
| Cannot_unbox_or_untag_type of native_repr_kind
| Deep_unbox_or_untag_attribute of native_repr_kind
| Bad_immediate_attribute
+ | Bad_unboxed_attribute of string
+ | Wrong_unboxed_type_float
+ | Boxed_and_unboxed
open Typedtree
exception Error of Location.t * error
+(* Note: do not factor the branches in the following pattern-matching:
+ the records must be constants for the compiler to do sharing on them.
+*)
+let get_unboxed_from_attributes sdecl =
+ let unboxed = Builtin_attributes.has_unboxed sdecl.ptype_attributes in
+ let boxed = Builtin_attributes.has_boxed sdecl.ptype_attributes in
+ match boxed, unboxed, !Clflags.unboxed_types with
+ | true, true, _ -> raise (Error(sdecl.ptype_loc, Boxed_and_unboxed))
+ | true, false, _ -> { unboxed = false; default = false }
+ | false, true, _ -> { unboxed = true; default = false }
+ | false, false, false -> { unboxed = false; default = true }
+ | false, false, true -> { unboxed = true; default = true }
+
(* Enter all declared types in the environment as abstract types *)
let enter_type env sdecl id =
@@ -77,6 +93,7 @@ let enter_type env sdecl id =
type_loc = sdecl.ptype_loc;
type_attributes = sdecl.ptype_attributes;
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
in
Env.add_type ~check:true id decl env
@@ -91,12 +108,37 @@ let update_type temp_env env id loc =
with Ctype.Unify trace ->
raise (Error(loc, Type_clash (env, trace)))
-(* Determine if a type is (an abbreviation for) the type "float" *)
(* We use the Ctype.expand_head_opt version of expand_head to get access
to the manifest type of private abbreviations. *)
+let rec get_unboxed_type_representation env ty fuel =
+ if fuel < 0 then None else
+ let ty = Ctype.repr (Ctype.expand_head_opt env ty) in
+ match ty.desc with
+ | Tconstr (p, args, _) ->
+ let tydecl = Env.find_type p env in
+ if tydecl.type_unboxed.unboxed then begin
+ match tydecl.type_kind with
+ | Type_record ([{ld_type = ty2; _}], _)
+ | Type_variant [{cd_args = Cstr_tuple [ty2]; _}]
+ | Type_variant [{cd_args = Cstr_record [{ld_type = ty2; _}]; _}]
+ -> get_unboxed_type_representation env
+ (Ctype.apply env tydecl.type_params ty2 args) (fuel - 1)
+ | Type_abstract -> None
+ (* This case can occur when checking a recursive unboxed type
+ declaration. *)
+ | _ -> assert false (* only the above can be unboxed *)
+ end else
+ Some ty
+ | _ -> Some ty
+
+let get_unboxed_type_representation env ty =
+ get_unboxed_type_representation env ty 100000
+;;
+
+(* Determine if a type's values are represented by floats at run-time. *)
let is_float env ty =
- match Ctype.repr (Ctype.expand_head_opt env ty) with
- {desc = Tconstr(p, _, _)} -> Path.same p Predef.path_float
+ match get_unboxed_type_representation env ty with
+ Some {desc = Tconstr(p, _, _); _} -> Path.same p Predef.path_float
| _ -> false
(* Determine if a type definition defines a fixed type. (PW) *)
@@ -226,6 +268,31 @@ let make_constructor env type_path type_params sargs sret_type =
widen z;
targs, Some tret_type, args, Some ret_type
+(* Check that the argument to a GADT constructor is compatible with unboxing
+ the type, given the existential variables introduced by this constructor. *)
+let rec check_unboxed_gadt_arg loc ex env ty =
+ match get_unboxed_type_representation env ty with
+ | Some {desc = Tvar _; id} ->
+ let f t = (Btype.repr t).id = id in
+ if List.exists f ex then raise(Error(loc, Wrong_unboxed_type_float))
+ | Some {desc = Tarrow _ | Ttuple _ | Tpackage _ | Tobject _ | Tnil
+ | Tvariant _; _} ->
+ ()
+ (* A comment in [Translcore.transl_exp0] claims the above cannot be
+ represented by floats. *)
+ | Some {desc = Tconstr (p, args, _); _} ->
+ let tydecl = Env.find_type p env in
+ assert (not tydecl.type_unboxed.unboxed);
+ if tydecl.type_kind = Type_abstract then
+ List.iter (check_unboxed_gadt_arg loc ex env) args
+ | Some {desc = Tfield _ | Tlink _ | Tsubst _; _} -> assert false
+ | Some {desc = Tunivar _; _} -> ()
+ | Some {desc = Tpoly (t2, _); _} -> check_unboxed_gadt_arg loc ex env t2
+ | None -> ()
+ (* This case is tricky: the argument is another (or the same) type
+ in the same recursive definition. In this case we don't have to
+ check because we will also check that other type for correctness. *)
+
let transl_declaration env sdecl id =
(* Bind type parameters *)
reset_type_variables();
@@ -238,9 +305,54 @@ let transl_declaration env sdecl id =
transl_simple_type env false sty', loc)
sdecl.ptype_cstrs
in
+ let raw_status = get_unboxed_from_attributes sdecl in
+ if raw_status.unboxed && not raw_status.default then begin
+ match sdecl.ptype_kind with
+ | Ptype_abstract ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "it is abstract"))
+ | Ptype_variant [{pcd_args = Pcstr_tuple []; _}] ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "its constructor has no argument"))
+ | Ptype_variant [{pcd_args = Pcstr_tuple [_]; _}] -> ()
+ | Ptype_variant [{pcd_args = Pcstr_tuple _; _}] ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "its constructor has more than one argument"))
+ | Ptype_variant [{pcd_args = Pcstr_record
+ [{pld_mutable=Immutable; _}]; _}] -> ()
+ | Ptype_variant [{pcd_args = Pcstr_record [{pld_mutable=Mutable; _}]; _}] ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute "it is mutable"))
+ | Ptype_variant [{pcd_args = Pcstr_record _; _}] ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "its constructor has more than one argument"))
+ | Ptype_variant _ ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "it has more than one constructor"))
+ | Ptype_record [{pld_mutable=Immutable; _}] -> ()
+ | Ptype_record [{pld_mutable=Mutable; _}] ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "it is mutable"))
+ | Ptype_record _ ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "it has more than one field"))
+ | Ptype_open ->
+ raise(Error(sdecl.ptype_loc, Bad_unboxed_attribute
+ "extensible variant types cannot be unboxed"))
+ end;
+ let unboxed_status =
+ match sdecl.ptype_kind with
+ | Ptype_variant [{pcd_args = Pcstr_tuple [_]; _}]
+ | Ptype_variant [{pcd_args = Pcstr_record
+ [{pld_mutable = Immutable; _}]; _}]
+ | Ptype_record [{pld_mutable = Immutable; _}] ->
+ raw_status
+ | _ -> (* The type is not unboxable, mark it as boxed *)
+ { unboxed = false; default = false }
+ in
+ let unbox = unboxed_status.unboxed in
let (tkind, kind) =
match sdecl.ptype_kind with
- Ptype_abstract -> Ttype_abstract, Type_abstract
+ | Ptype_abstract -> Ttype_abstract, Type_abstract
| Ptype_variant scstrs ->
assert (scstrs <> []);
let all_constrs = ref StringSet.empty in
@@ -251,8 +363,8 @@ let transl_declaration env sdecl id =
all_constrs := StringSet.add name !all_constrs)
scstrs;
if List.length
- (List.filter (fun cd -> cd.pcd_args <> Pcstr_tuple []) scstrs)
- > (Config.max_tag + 1) then
+ (List.filter (fun cd -> cd.pcd_args <> Pcstr_tuple []) scstrs)
+ > (Config.max_tag + 1) then
raise(Error(sdecl.ptype_loc, Too_many_constructors));
let make_cstr scstr =
let name = Ident.create scstr.pcd_name.txt in
@@ -260,6 +372,20 @@ let transl_declaration env sdecl id =
make_constructor env (Path.Pident id) params
scstr.pcd_args scstr.pcd_res
in
+ if unbox then begin
+ (* Cannot unbox a type when the argument can be both float and
+ non-float because it interferes with the dynamic float array
+ optimization. This can only happen when the type is a GADT
+ and the argument is an existential type variable or an
+ unboxed (or abstract) type constructor applied to some
+ existential type variable. Of course we also have to rule
+ out any abstract type constructor applied to anything that
+ might be an existential type variable. *)
+ match Datarepr.constructor_existentials args ret_type with
+ | _, [] -> ()
+ | [argty], ex -> check_unboxed_gadt_arg sdecl.ptype_loc ex env argty
+ | _ -> assert false
+ end;
let tcstr =
{ cd_id = name;
cd_name = scstr.pcd_name;
@@ -282,7 +408,8 @@ let transl_declaration env sdecl id =
| Ptype_record lbls ->
let lbls, lbls' = transl_labels env true lbls in
let rep =
- if List.for_all (fun l -> is_float env l.Types.ld_type) lbls'
+ if unbox then Record_unboxed false
+ else if List.for_all (fun l -> is_float env l.Types.ld_type) lbls'
then Record_float
else Record_regular
in
@@ -307,6 +434,7 @@ let transl_declaration env sdecl id =
type_loc = sdecl.ptype_loc;
type_attributes = sdecl.ptype_attributes;
type_immediate = false;
+ type_unboxed = unboxed_status;
} in
(* Check constraints *)
@@ -902,6 +1030,14 @@ let marked_as_immediate decl =
let compute_immediacy env tdecl =
match (tdecl.type_kind, tdecl.type_manifest) with
+ | (Type_variant [{cd_args = Cstr_tuple [arg]; _}], _)
+ | (Type_variant [{cd_args = Cstr_record [{ld_type = arg; _}]; _}], _)
+ | (Type_record ([{ld_type = arg; _}], _), _)
+ when tdecl.type_unboxed.unboxed ->
+ begin match get_unboxed_type_representation env arg with
+ | Some argrepr -> not (Ctype.maybe_pointer_type env argrepr)
+ | None -> false
+ end
| (Type_variant (_ :: _ as cstrs), _) ->
not (List.exists (fun c -> c.Types.cd_args <> Types.Cstr_tuple []) cstrs)
| (Type_abstract, Some(typ)) ->
@@ -1485,6 +1621,17 @@ let rec parse_native_repr_attributes env core_type ty ~global_repr =
| Ptyp_arrow _, _, _ | _, Tarrow _, _ -> assert false
| _ -> ([], make_native_repr env core_type ty ~global_repr)
+
+let check_unboxable env loc ty =
+ let ty = Ctype.repr (Ctype.expand_head_opt env ty) in
+ match ty.desc with
+ | Tconstr (p, _, _) ->
+ let tydecl = Env.find_type p env in
+ if tydecl.type_unboxed.unboxed then
+ Location.prerr_warning loc
+ (Warnings.Unboxable_type_in_prim_decl (Path.name p))
+ | _ -> ()
+
(* Translate a value declaration *)
let transl_value_decl env loc valdecl =
let cty = Typetexp.transl_type_scheme env valdecl.pval_type in
@@ -1519,6 +1666,7 @@ let transl_value_decl env loc valdecl =
&& prim.prim_arity > 5
&& prim.prim_native_name = ""
then raise(Error(valdecl.pval_type.ptyp_loc, Missing_native_external));
+ Btype.iter_type_expr (check_unboxable env loc) ty;
{ val_type = ty; val_kind = Val_prim prim; Types.val_loc = loc;
val_attributes = valdecl.pval_attributes }
in
@@ -1579,11 +1727,16 @@ let transl_with_constraint env id row_path orig_decl sdecl =
&& sdecl.ptype_private = Private then
Location.prerr_warning sdecl.ptype_loc
(Warnings.Deprecated "spurious use of private");
+ let type_kind, type_unboxed =
+ if arity_ok && man <> None then
+ orig_decl.type_kind, orig_decl.type_unboxed
+ else
+ Type_abstract, {unboxed = false; default = false}
+ in
let decl =
{ type_params = params;
type_arity = List.length params;
- type_kind =
- if arity_ok && man <> None then orig_decl.type_kind else Type_abstract;
+ type_kind;
type_private = priv;
type_manifest = man;
type_variance = [];
@@ -1591,6 +1744,7 @@ let transl_with_constraint env id row_path orig_decl sdecl =
type_loc = sdecl.ptype_loc;
type_attributes = sdecl.ptype_attributes;
type_immediate = false;
+ type_unboxed;
}
in
begin match row_path with None -> ()
@@ -1638,6 +1792,7 @@ let abstract_type_decl arity =
type_loc = Location.none;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
} in
Ctype.end_def();
generalize_decl decl;
@@ -1883,6 +2038,14 @@ let report_error ppf = function
fprintf ppf "@[%s@ %s@]"
"Types marked with the immediate attribute must be"
"non-pointer types like int or bool"
+ | Bad_unboxed_attribute msg ->
+ fprintf ppf "@[This type cannot be unboxed because@ %s.@]" msg
+ | Wrong_unboxed_type_float ->
+ fprintf ppf "@[This type cannot be unboxed because@ \
+ it might contain both float and non-float values.@ \
+ You should annotate it with [%@%@ocaml.boxed].@]"
+ | Boxed_and_unboxed ->
+ fprintf ppf "@[A type cannot be boxed and unboxed at the same time.@]"
let () =
Location.register_error_of_exn
diff --git a/typing/typedecl.mli b/typing/typedecl.mli
index ef46c9d7a5..db4875f96f 100644
--- a/typing/typedecl.mli
+++ b/typing/typedecl.mli
@@ -59,6 +59,10 @@ val compute_variance_decls:
(Types.type_declaration * Types.type_declaration *
Types.class_declaration * Types.class_type_declaration) list
+(* for typeopt.ml *)
+val get_unboxed_type_representation: Env.t -> type_expr -> type_expr option
+
+
type native_repr_kind = Unboxed | Untagged
type error =
@@ -92,6 +96,9 @@ type error =
| Cannot_unbox_or_untag_type of native_repr_kind
| Deep_unbox_or_untag_attribute of native_repr_kind
| Bad_immediate_attribute
+ | Bad_unboxed_attribute of string
+ | Wrong_unboxed_type_float
+ | Boxed_and_unboxed
exception Error of Location.t * error
diff --git a/typing/typemod.ml b/typing/typemod.ml
index c86e7930ac..defe7aad9d 100644
--- a/typing/typemod.ml
+++ b/typing/typemod.ml
@@ -188,6 +188,7 @@ let merge_constraint initial_env loc sg constr =
type_newtype_level = None;
type_attributes = [];
type_immediate = false;
+ type_unboxed = { unboxed = false; default = false };
}
and id_row = Ident.create (s^"#row") in
let initial_env =
diff --git a/typing/types.ml b/typing/types.ml
index c90838104f..ad4e64c00d 100644
--- a/typing/types.ml
+++ b/typing/types.ml
@@ -149,6 +149,7 @@ type type_declaration =
type_loc: Location.t;
type_attributes: Parsetree.attributes;
type_immediate: bool;
+ type_unboxed: unboxed_status;
}
and type_kind =
@@ -160,6 +161,7 @@ and type_kind =
and record_representation =
Record_regular (* All fields are boxed / tagged *)
| Record_float (* All fields are floats *)
+ | Record_unboxed of bool (* Unboxed single-field record, inlined or not *)
| Record_inlined of int (* Inlined record *)
| Record_extension (* Inlined record under extension *)
@@ -185,6 +187,12 @@ and constructor_arguments =
| Cstr_tuple of type_expr list
| Cstr_record of label_declaration list
+and unboxed_status =
+ {
+ unboxed: bool;
+ default: bool; (* False if the unboxed field was set from an attribute. *)
+ }
+
type extension_constructor =
{ ext_type_path: Path.t;
ext_type_params: type_expr list;
@@ -301,6 +309,7 @@ type constructor_description =
and constructor_tag =
Cstr_constant of int (* Constant constructor (an int) *)
| Cstr_block of int (* Regular constructor (a block) *)
+ | Cstr_unboxed (* Constructor of an unboxed type *)
| Cstr_extension of Path.t * bool (* Extension constructor
true if a constant false if a block*)
diff --git a/typing/types.mli b/typing/types.mli
index 45c9ddc6af..a9601d88b0 100644
--- a/typing/types.mli
+++ b/typing/types.mli
@@ -295,6 +295,7 @@ type type_declaration =
type_loc: Location.t;
type_attributes: Parsetree.attributes;
type_immediate: bool; (* true iff type should not be a pointer *)
+ type_unboxed: unboxed_status;
}
and type_kind =
@@ -306,6 +307,7 @@ and type_kind =
and record_representation =
Record_regular (* All fields are boxed / tagged *)
| Record_float (* All fields are floats *)
+ | Record_unboxed of bool (* Unboxed single-field record, inlined or not *)
| Record_inlined of int (* Inlined record *)
| Record_extension (* Inlined record under extension *)
@@ -331,6 +333,12 @@ and constructor_arguments =
| Cstr_tuple of type_expr list
| Cstr_record of label_declaration list
+and unboxed_status =
+ {
+ unboxed: bool;
+ default: bool; (* True for unannotated unboxable types. *)
+ }
+
type extension_constructor =
{
ext_type_path: Path.t;
@@ -449,6 +457,7 @@ type constructor_description =
and constructor_tag =
Cstr_constant of int (* Constant constructor (an int) *)
| Cstr_block of int (* Regular constructor (a block) *)
+ | Cstr_unboxed (* Constructor of an unboxed type *)
| Cstr_extension of Path.t * bool (* Extension constructor
true if a constant false if a block*)
diff --git a/utils/clflags.ml b/utils/clflags.ml
index b43c52e0da..c44d73ad9e 100644
--- a/utils/clflags.ml
+++ b/utils/clflags.ml
@@ -355,3 +355,5 @@ let parse_color_setting = function
| "never" -> Some Misc.Color.Never
| _ -> None
let color = ref Misc.Color.Auto ;; (* -color *)
+
+let unboxed_types = ref false
diff --git a/utils/clflags.mli b/utils/clflags.mli
index 49326fe69c..f7939eb6e9 100644
--- a/utils/clflags.mli
+++ b/utils/clflags.mli
@@ -200,3 +200,5 @@ val set_dumped_pass : string -> bool -> unit
val parse_color_setting : string -> Misc.Color.setting option
val color : Misc.Color.setting ref
+
+val unboxed_types : bool ref
diff --git a/utils/config.mlp b/utils/config.mlp
index 1f918fe221..8459a5354d 100644
--- a/utils/config.mlp
+++ b/utils/config.mlp
@@ -71,7 +71,7 @@ let flambda = %%FLAMBDA%%
let safe_string = %%SAFE_STRING%%
let exec_magic_number = "Caml1999X011"
-and cmi_magic_number = "Caml1999I020"
+and cmi_magic_number = "Caml1999I021"
and cmo_magic_number = "Caml1999O011"
and cma_magic_number = "Caml1999A012"
and cmx_magic_number =
@@ -87,7 +87,7 @@ and cmxa_magic_number =
and ast_impl_magic_number = "Caml1999M019"
and ast_intf_magic_number = "Caml1999N018"
and cmxs_magic_number = "Caml2007D002"
-and cmt_magic_number = "Caml2012T007"
+and cmt_magic_number = "Caml2012T008"
let load_path = ref ([] : string list)
diff --git a/utils/warnings.ml b/utils/warnings.ml
index 488cef8417..70c4759d94 100644
--- a/utils/warnings.ml
+++ b/utils/warnings.ml
@@ -14,10 +14,10 @@
(**************************************************************************)
(* When you change this, you need to update the documentation:
- - man/ocamlc.m in ocaml
- - man/ocamlopt.m in ocaml
- - manual/cmds/comp.etex in the doc sources
- - manual/cmds/native.etex in the doc sources
+ - man/ocamlc.m
+ - man/ocamlopt.m
+ - manual/manual/cmds/comp.etex
+ - manual/manual/cmds/native.etex
*)
type t =
@@ -81,6 +81,7 @@ type t =
| No_cmx_file of string (* 58 *)
| Assignment_to_non_mutable_value (* 59 *)
| Unused_module of string (* 60 *)
+ | Unboxable_type_in_prim_decl of string (* 61 *)
;;
(* If you remove a warning, leave a hole in the numbering. NEVER change
@@ -150,6 +151,7 @@ let number = function
| No_cmx_file _ -> 58
| Assignment_to_non_mutable_value -> 59
| Unused_module _ -> 60
+ | Unboxable_type_in_prim_decl _ -> 61
;;
let last_warning_number = 60
@@ -475,6 +477,12 @@ let message = function
in this source file. Such assignments may generate incorrect code \n\
when using Flambda."
| Unused_module s -> "unused module " ^ s ^ "."
+ | Unboxable_type_in_prim_decl t ->
+ Printf.sprintf
+ "This primitive declaration uses type %s, which is unannotated and\n\
+ unboxable. The representation of such types may change in future\n\
+ versions. You should annotate the declaration of %s with [@@boxed]\n\
+ or [@@unboxed]." t t
;;
let nerrors = ref 0;;
diff --git a/utils/warnings.mli b/utils/warnings.mli
index 7734aa4654..fb03935b8f 100644
--- a/utils/warnings.mli
+++ b/utils/warnings.mli
@@ -76,6 +76,7 @@ type t =
| No_cmx_file of string (* 58 *)
| Assignment_to_non_mutable_value (* 59 *)
| Unused_module of string (* 60 *)
+ | Unboxable_type_in_prim_decl of string (* 61 *)
;;
val parse_options : bool -> string -> unit;;