Skip to content

Commit adbb76c

Browse files
aspeddroclaude
andcommitted
Support %assert as a first-class value
When assert is used as a value (e.g. let f = assert), transl_primitive now generates a proper wrapper function instead of falling through to Pccall, which would produce a call to a non-existent runtime function. The generated lambda is: fun assert_cond -> if assert_cond then () else raise Assert_failure(file, line, col), using the location where assert appears in source. This is the best possible location for an alias since the call-site location is not available at primitive translation time. assert_failed_at is extracted as a location-based helper alongside the existing assert_failed (which takes a typed expression). Signed-Off-By: Pedro Castro <aspeddro@gmail.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2c71636 commit adbb76c

1 file changed

Lines changed: 75 additions & 40 deletions

File tree

compiler/ml/translcore.ml

Lines changed: 75 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -453,52 +453,87 @@ let warn_polymorphic_comparison loc prim args =
453453
Location.prerr_warning loc Warnings.Bs_polymorphic_comparison
454454
| _ -> ()
455455

456+
let assert_failed_at loc =
457+
let fname, line, char = Location.get_pos_info loc.Location.loc_start in
458+
let fname = Filename.basename fname in
459+
Lprim
460+
( Praise Raise_regular,
461+
[
462+
Lprim
463+
( Pmakeblock Blk_extension,
464+
[
465+
transl_normal_path Predef.path_assert_failure;
466+
Lconst
467+
(Const_block
468+
( Blk_tuple,
469+
[
470+
Const_base (Const_string (fname, None));
471+
Const_base (Const_int line);
472+
Const_base (Const_int char);
473+
] ));
474+
],
475+
loc );
476+
],
477+
loc )
478+
456479
(* Eta-expand a primitive *)
457480

458481
let transl_primitive loc p env ty =
459482
(* Printf.eprintf "----transl_primitive %s----\n" p.prim_name; *)
460-
let prim =
461-
try specialize_primitive p env ty (* ~has_constant_constructor:false *)
462-
with Not_found -> Pccall p
463-
in
464-
warn_polymorphic_comparison loc prim [];
465-
match prim with
466-
| Ploc kind -> (
467-
let lam = lam_of_loc kind loc in
468-
match p.prim_arity with
469-
| 0 -> lam
470-
| 1 ->
471-
(* TODO: we should issue a warning ? *)
472-
let param = Ident.create "prim" in
473-
Lfunction
474-
{
475-
params = [param];
476-
attr = default_function_attribute;
477-
loc;
478-
body = Lprim (Pmakeblock Blk_tuple, [lam; Lvar param], loc);
479-
}
480-
| _ -> assert false)
481-
| _ ->
482-
let rec make_params n total =
483-
if n <= 0 then []
484-
else
485-
Ident.create ("prim" ^ string_of_int (total - n))
486-
:: make_params (n - 1) total
483+
if p.Primitive.prim_name = "%assert" then
484+
let param = Ident.create "assert_cond" in
485+
Lfunction
486+
{
487+
params = [param];
488+
attr = default_function_attribute;
489+
loc;
490+
body =
491+
(if !Clflags.noassert then lambda_unit
492+
else Lifthenelse (Lvar param, lambda_unit, assert_failed_at loc));
493+
}
494+
else
495+
let prim =
496+
try specialize_primitive p env ty (* ~has_constant_constructor:false *)
497+
with Not_found -> Pccall p
487498
in
488-
let prim_arity = p.prim_arity in
489-
if p.prim_from_constructor || prim_arity = 0 then Lprim (prim, [], loc)
490-
else
491-
let params =
492-
if prim_arity = 1 then [Ident.create "prim"]
493-
else make_params prim_arity prim_arity
499+
warn_polymorphic_comparison loc prim [];
500+
match prim with
501+
| Ploc kind -> (
502+
let lam = lam_of_loc kind loc in
503+
match p.prim_arity with
504+
| 0 -> lam
505+
| 1 ->
506+
(* TODO: we should issue a warning ? *)
507+
let param = Ident.create "prim" in
508+
Lfunction
509+
{
510+
params = [param];
511+
attr = default_function_attribute;
512+
loc;
513+
body = Lprim (Pmakeblock Blk_tuple, [lam; Lvar param], loc);
514+
}
515+
| _ -> assert false)
516+
| _ ->
517+
let rec make_params n total =
518+
if n <= 0 then []
519+
else
520+
Ident.create ("prim" ^ string_of_int (total - n))
521+
:: make_params (n - 1) total
494522
in
495-
Lfunction
496-
{
497-
params;
498-
attr = default_function_attribute;
499-
loc;
500-
body = Lprim (prim, List.map (fun id -> Lvar id) params, loc);
501-
}
523+
let prim_arity = p.prim_arity in
524+
if p.prim_from_constructor || prim_arity = 0 then Lprim (prim, [], loc)
525+
else
526+
let params =
527+
if prim_arity = 1 then [Ident.create "prim"]
528+
else make_params prim_arity prim_arity
529+
in
530+
Lfunction
531+
{
532+
params;
533+
attr = default_function_attribute;
534+
loc;
535+
body = Lprim (prim, List.map (fun id -> Lvar id) params, loc);
536+
}
502537

503538
let transl_primitive_application loc prim env ty args =
504539
let prim_name = prim.prim_name in

0 commit comments

Comments
 (0)