From 8dc0d8ab8c45b5e59fe5f41c967f96f593507aaf Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:06:55 +0000 Subject: [PATCH 01/16] Remove dead Ctype diagnostic relays Drop Ctype.Tags and Ctype.Recursive_abbrev because both exceptions were declared and caught but had no raise site anywhere under compiler/. This also removes the unreachable Typetexp.Variant_tags and Typecore.Recursive_local_constraint wrappers that only existed to report those exceptions. Validation: rg found no remaining references to the removed constructors, and make completed successfully. --- compiler/ml/ctype.ml | 21 --------------------- compiler/ml/ctype.mli | 3 --- compiler/ml/typecore.ml | 18 +----------------- compiler/ml/typecore.mli | 1 - compiler/ml/typetexp.ml | 6 ------ compiler/ml/typetexp.mli | 1 - 6 files changed, 1 insertion(+), 49 deletions(-) diff --git a/compiler/ml/ctype.ml b/compiler/ml/ctype.ml index e15adf31b4..1291da7880 100644 --- a/compiler/ml/ctype.ml +++ b/compiler/ml/ctype.ml @@ -57,19 +57,6 @@ type type_pairs = (type_expr * type_expr) list exception Unify of type_pairs -exception Tags of label * label - -let () = - Location.register_error_of_exn (function - | Tags (l, l') -> - Some - Location.( - errorf ~loc:(in_file !input_name) - "In this program,@ variant constructors@ #%s and #%s@ have the \ - same hash value.@ Change one of them." - l l') - | _ -> None) - type subtype_context = | Generic of {errorCode: string} | Coercion_target_variant_not_unboxed of { @@ -107,11 +94,6 @@ exception Cannot_expand exception Cannot_apply -exception Recursive_abbrev - -(* GADT: recursive abbrevs can appear as a result of local constraints *) -exception Unification_recursive_abbrev of type_pairs - (**** Type level management ****) let current_level = ref 0 @@ -2731,9 +2713,6 @@ let unify env ty1 ty2 = | Unify trace -> undo_compress snap; raise (Unify (expand_trace !env trace)) - | Recursive_abbrev -> - undo_compress snap; - raise (Unification_recursive_abbrev (expand_trace !env [(ty1, ty2)])) let unify_gadt ~newtype_level:lev (env : Env.t ref) ty1 ty2 = try diff --git a/compiler/ml/ctype.mli b/compiler/ml/ctype.mli index 6785374ac9..b671730402 100644 --- a/compiler/ml/ctype.mli +++ b/compiler/ml/ctype.mli @@ -54,12 +54,9 @@ type subtype_context = type type_pairs = (type_expr * type_expr) list exception Unify of type_pairs -exception Tags of label * label exception Subtype of type_pairs * type_pairs * subtype_context option exception Cannot_expand exception Cannot_apply -exception Recursive_abbrev -exception Unification_recursive_abbrev of type_pairs val init_def : int -> unit (* Set the initial variable level *) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 4f0b3be38e..d6b42771b9 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -69,7 +69,6 @@ type error = | Modules_not_allowed | Cannot_infer_signature | Not_a_packed_module of type_expr - | Recursive_local_constraint of (type_expr * type_expr) list | Unexpected_existential | Unqualified_gadt_pattern of Path.t * string | Invalid_interval @@ -338,15 +337,11 @@ let check_optional_attr env ld optional loc = let unify_pat_types loc env ty ty' = try unify env ty ty' with | Unify trace -> raise (Error (loc, env, Pattern_type_clash trace)) - | Tags (l1, l2) -> - raise (Typetexp.Error (loc, env, Typetexp.Variant_tags (l1, l2))) (* unification inside type_exp and type_expect *) let unify_exp_types ~context loc env ty expected_ty = try unify env ty expected_ty with | Unify trace -> raise (Error (loc, env, Expr_type_clash {trace; context})) - | Tags (l1, l2) -> - raise (Typetexp.Error (loc, env, Typetexp.Variant_tags (l1, l2))) (* level at which to create the local type declarations *) let newtype_level = ref None @@ -363,10 +358,6 @@ let unify_pat_types_gadt loc env ty ty' = in try unify_gadt ~newtype_level env ty ty' with | Unify trace -> raise (Error (loc, !env, Pattern_type_clash trace)) - | Tags (l1, l2) -> - raise (Typetexp.Error (loc, !env, Typetexp.Variant_tags (l1, l2))) - | Unification_recursive_abbrev trace -> - raise (Error (loc, !env, Recursive_local_constraint trace)) (* Creating new conjunctive types is not allowed when typing patterns *) @@ -4520,8 +4511,7 @@ let type_expression ~context env sexp = (match sexp.pexp_desc with | Pexp_apply _ -> Some (return_type, FunctionCall) | _ -> Some (return_type, Other))) - | Tags _ -> - Location.prerr_warning sexp.pexp_loc (Bs_toplevel_expression_unit None)); + ); end_def (); if not (is_nonexpansive exp) then generalize_expansive env exp.exp_type; generalize exp.exp_type; @@ -4801,12 +4791,6 @@ let report_error env loc ppf error = | Not_a_packed_module ty -> fprintf ppf "This expression is packed module, but the expected type is@ %a" type_expr ty - | Recursive_local_constraint trace -> - (* modified *) - super_report_unification_error ppf env trace - (function - | ppf -> fprintf ppf "Recursive local constraint when unifying") - (function ppf -> fprintf ppf "with") | Unexpected_existential -> fprintf ppf "Unexpected existential" | Unqualified_gadt_pattern (tpath, name) -> fprintf ppf "@[The GADT constructor %s of type %a@ %s.@]" name Printtyp.path diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index 2a57356e73..de89a516b7 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -102,7 +102,6 @@ type error = | Modules_not_allowed | Cannot_infer_signature | Not_a_packed_module of type_expr - | Recursive_local_constraint of (type_expr * type_expr) list | Unexpected_existential | Unqualified_gadt_pattern of Path.t * string | Invalid_interval diff --git a/compiler/ml/typetexp.ml b/compiler/ml/typetexp.ml index 9867baac11..2e735329db 100644 --- a/compiler/ml/typetexp.ml +++ b/compiler/ml/typetexp.ml @@ -36,7 +36,6 @@ type error = | Present_has_no_type of string | Constructor_mismatch of type_expr * type_expr | Not_a_variant of type_expr - | Variant_tags of string * string | Invalid_variable_name of string | Cannot_quantify of string * type_expr | Multiple_constraints_on_type of Longident.t @@ -824,11 +823,6 @@ let report_error env ppf = function (* PR#7012: help the user that wrote 'Foo instead of `Foo *) Misc.did_you_mean ppf (fun () -> ["`" ^ s]) | _ -> ()) - | Variant_tags (lab1, lab2) -> - fprintf ppf "@[Variant tags %s@ and %s have the same hash value.@ %s@]" - (!Printtyp.print_res_poly_identifier lab1) - (!Printtyp.print_res_poly_identifier lab2) - "Change one of them." | Invalid_variable_name name -> fprintf ppf "The type variable name %s is not allowed in programs" name | Cannot_quantify (name, v) -> diff --git a/compiler/ml/typetexp.mli b/compiler/ml/typetexp.mli index 8f40096392..cff8910482 100644 --- a/compiler/ml/typetexp.mli +++ b/compiler/ml/typetexp.mli @@ -45,7 +45,6 @@ type error = | Present_has_no_type of string | Constructor_mismatch of type_expr * type_expr | Not_a_variant of type_expr - | Variant_tags of string * string | Invalid_variable_name of string | Cannot_quantify of string * type_expr | Multiple_constraints_on_type of Longident.t From cfd3babb687310d3a68783c9606afdb3e3e97011 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:07:56 +0000 Subject: [PATCH 02/16] Remove unused bs_syntaxerr conflict variant Drop Conflict_bs_bs_this_bs_meth because the constructor was only declared and printed; rg found no Bs_syntaxerr.err call or other construction site for it under compiler/. Validation: rg found no remaining references. The full rebuild is delayed by an unrelated coverage Dune process that currently holds _build/.lock. --- compiler/frontend/bs_syntaxerr.ml | 3 --- compiler/frontend/bs_syntaxerr.mli | 1 - 2 files changed, 4 deletions(-) diff --git a/compiler/frontend/bs_syntaxerr.ml b/compiler/frontend/bs_syntaxerr.ml index 668853bdf8..9cadcb5897 100644 --- a/compiler/frontend/bs_syntaxerr.ml +++ b/compiler/frontend/bs_syntaxerr.ml @@ -26,7 +26,6 @@ type untagged_variant = OnlyOneUnknown | AtMostOneObject | AtMostOneArray type error = | Unsupported_predicates - | Conflict_bs_bs_this_bs_meth | Duplicated_bs_deriving | Conflict_attributes | Expect_int_literal @@ -65,8 +64,6 @@ let pp_error fmt err = | Not_supported_directive_in_bs_return -> "Not supported return directive" | Illegal_attribute -> "Illegal attributes" | Unsupported_predicates -> "unsupported predicates" - | Conflict_bs_bs_this_bs_meth -> - "%@this and %@bs can not be applied at the same time" | Duplicated_bs_deriving -> "duplicate @deriving attribute" | Conflict_attributes -> "conflicting attributes " | Expect_string_literal -> "expect string literal " diff --git a/compiler/frontend/bs_syntaxerr.mli b/compiler/frontend/bs_syntaxerr.mli index ecdaaaa0e6..9c6a9ff9b5 100644 --- a/compiler/frontend/bs_syntaxerr.mli +++ b/compiler/frontend/bs_syntaxerr.mli @@ -26,7 +26,6 @@ type untagged_variant = OnlyOneUnknown | AtMostOneObject | AtMostOneArray type error = | Unsupported_predicates - | Conflict_bs_bs_this_bs_meth | Duplicated_bs_deriving | Conflict_attributes | Expect_int_literal From e9aa1bc077fd8d68a56cb28a807aa12d917b0d9c Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:09:08 +0000 Subject: [PATCH 03/16] Remove unreachable typecore label diagnostics Drop Label_mismatch, Abstract_wrong_label, and Incoherent_label_order. Label_mismatch's pattern path was catching Ctype.Unify around unify_pat_types even though that helper already translates Unify to Pattern_type_clash. The expression path now uses the existing Expr_type_clash machinery if the defensive invariant ever fails. Abstract_wrong_label and Incoherent_label_order were defensive branches behind modern function and labeled-argument normalization; any fallback now uses the existing Too_many_arguments or Apply_wrong_label diagnostics. Validation: rg found no remaining references. A full rebuild will run once the unrelated coverage Dune process releases _build/.lock. --- compiler/ml/typecore.ml | 43 ++++++---------------------------------- compiler/ml/typecore.mli | 3 --- 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index d6b42771b9..dded160fc4 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -32,7 +32,6 @@ type error = expected: int; provided: int; } - | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string @@ -61,10 +60,8 @@ type error = | Not_subtype of Ctype.type_pairs * Ctype.type_pairs * Ctype.subtype_context option | Too_many_arguments of bool * type_expr - | Abstract_wrong_label of arg_label * type_expr | Scoping_let_module of string * type_expr | Not_a_variant_type of Longident.t - | Incoherent_label_order | Less_general of string * (type_expr * type_expr) list | Modules_not_allowed | Cannot_infer_signature @@ -1528,10 +1525,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp begin_def (); let vars, ty_arg, ty_res = instance_label false label in if vars = [] then end_def (); - (try unify_pat_types loc !env ty_res record_ty - with Unify trace -> - raise - (Error (label_lid.loc, !env, Label_mismatch (label_lid.txt, trace)))); + unify_pat_types loc !env ty_res record_ty; type_pat sarg ty_arg (fun arg -> if vars <> [] then ( end_def (); @@ -3488,12 +3482,8 @@ and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l let ty_arg, ty_res = try filter_arrow ~env ~arity (instance env ty_expected) l with Unify _ -> ( - match expand_head env ty_expected with - | {desc = Tarrow _} as ty -> - raise (Error (loc, env, Abstract_wrong_label (l, ty))) - | _ -> - raise - (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun)))) + raise + (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun)))) in let ty_arg = if is_optional l then ( @@ -3575,9 +3565,8 @@ and type_label_exp ~call_context create env loc ty_expected (* Generalize label information *) generalize_structure ty_arg; generalize_structure ty_res); - (try unify env (instance_def ty_res) (instance env ty_expected) - with Unify trace -> - raise (Error (lid.loc, env, Label_mismatch (lid.txt, trace)))); + unify_exp_types ~context:None lid.loc env (instance_def ty_res) + (instance env ty_expected); (* Instantiate so that we can generalize internal nodes *) let ty_arg = instance_def ty_arg in if separate then ( @@ -3879,10 +3868,9 @@ and type_application ~context total_app env funct (sargs : sargs) : raise (Error (sarg1.pexp_loc, env, Apply_wrong_label (l1, funct.exp_type))) - else if not (has_label l1 ty_fun) then + else raise (Error (sarg1.pexp_loc, env, Apply_wrong_label (l1, ty_res))) - else raise (Error (funct.exp_loc, env, Incoherent_label_order)) | _ -> raise (Error @@ -4595,13 +4583,6 @@ let report_error env loc ppf error = (if expected == 1 then "argument" else "arguments") (if provided < expected then " only" else "") provided - | Label_mismatch (lid, trace) -> - (* modified *) - super_report_unification_error ppf env trace - (function - | ppf -> - fprintf ppf "The record field %a@ belongs to the type" longident lid) - (function ppf -> fprintf ppf "but is mixed here with fields of type") | Pattern_type_clash trace -> (* modified *) super_report_unification_error ppf env trace @@ -4756,14 +4737,6 @@ let report_error env loc ppf error = else ( fprintf ppf "@[This expression should not be a function,@ "; fprintf ppf "the expected type is@ %a@]" type_expr ty) - | Abstract_wrong_label (l, ty) -> - let label_mark = function - | Nolabel -> "but its first argument is not labelled" - | l -> - sprintf "but its first argument is labelled %s" (prefixed_label_name l) - in - fprintf ppf "@[@[<2>This function should have type@ %a@]@,%s@]" type_expr - ty (label_mark l) | Scoping_let_module (id, ty) -> fprintf ppf "This `let module' expression has type@ %a@ " type_expr ty; fprintf ppf @@ -4775,10 +4748,6 @@ let report_error env loc ppf error = type_expr ty | Not_a_variant_type lid -> fprintf ppf "The type %a@ is not a variant type" longident lid - | Incoherent_label_order -> - fprintf ppf "This labeled function is applied to arguments@ "; - fprintf ppf "in an order different from other calls.@ "; - fprintf ppf "This is only allowed when the real type is known." | Less_general (kind, trace) -> (* modified *) super_report_unification_error ppf env trace diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index de89a516b7..337c654bda 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -65,7 +65,6 @@ type error = expected: int; provided: int; } - | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string @@ -94,10 +93,8 @@ type error = | Not_subtype of Ctype.type_pairs * Ctype.type_pairs * Ctype.subtype_context option | Too_many_arguments of bool * type_expr - | Abstract_wrong_label of arg_label * type_expr | Scoping_let_module of string * type_expr | Not_a_variant_type of Longident.t - | Incoherent_label_order | Less_general of string * (type_expr * type_expr) list | Modules_not_allowed | Cannot_infer_signature From f35deddc28eac0af029da7bae5856ae58150485c Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:09:49 +0000 Subject: [PATCH 04/16] Remove parser-blocked typecore variants Drop Invalid_interval and Invalid_for_of_pattern from Typecore.error. The ReScript parser has no source construction site for Ppat_interval, and normalize_for_of_pattern reports destructuring for...of syntax before replacing it with Ppat_any. The old typer guards now use direct Location errors only as malformed-AST fallbacks. Validation: rg found no remaining references to the removed named variants. --- compiler/ml/typecore.ml | 19 +++++++++---------- compiler/ml/typecore.mli | 2 -- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index dded160fc4..eb164f77d0 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -68,9 +68,7 @@ type error = | Not_a_packed_module of type_expr | Unexpected_existential | Unqualified_gadt_pattern of Path.t * string - | Invalid_interval | Invalid_for_loop_index - | Invalid_for_of_pattern | No_value_clauses | Exception_pattern_below_toplevel | Inlined_record_escape @@ -1334,7 +1332,9 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp let p = {p with ppat_loc = loc} in type_pat ~explode:0 p expected_ty k (* TODO: record 'extra' to remember about interval *) - | Ppat_interval _ -> raise (Error (loc, !env, Invalid_interval)) + | Ppat_interval _ -> + Location.raise_errorf ~loc + "Only character intervals are supported in patterns." | Ppat_tuple spl -> assert (List.length spl >= 2); let spl_ann = List.map (fun p -> (p, newvar ())) spl in @@ -3102,7 +3102,9 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) val_kind = Val_reg; Types.val_loc = loc; } env ~check:(fun s -> Warnings.Unused_for_index s) - | _ -> raise (Error (param.ppat_loc, env, Invalid_for_of_pattern)) + | _ -> + Location.raise_errorf ~loc:param.ppat_loc + "Invalid for...of binding: only variables and _ are allowed." in let body = with_depth loop_depth (fun () -> @@ -3134,7 +3136,9 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) val_kind = Val_reg; Types.val_loc = loc; } env ~check:(fun s -> Warnings.Unused_for_index s) - | _ -> raise (Error (param.ppat_loc, env, Invalid_for_of_pattern)) + | _ -> + Location.raise_errorf ~loc:param.ppat_loc + "Invalid for...of binding: only variables and _ are allowed." in let body = with_depth loop_depth (fun () -> @@ -4764,13 +4768,8 @@ let report_error env loc ppf error = | Unqualified_gadt_pattern (tpath, name) -> fprintf ppf "@[The GADT constructor %s of type %a@ %s.@]" name Printtyp.path tpath "must be qualified in this pattern" - | Invalid_interval -> - fprintf ppf "@[Only character intervals are supported in patterns.@]" | Invalid_for_loop_index -> fprintf ppf "@[Invalid for-loop index: only variables and _ are allowed.@]" - | Invalid_for_of_pattern -> - fprintf ppf - "@[Invalid for...of binding: only variables and _ are allowed.@]" | No_value_clauses -> fprintf ppf "None of the patterns in this 'match' expression match values." | Exception_pattern_below_toplevel -> diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index 337c654bda..cc63ed4fe7 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -101,9 +101,7 @@ type error = | Not_a_packed_module of type_expr | Unexpected_existential | Unqualified_gadt_pattern of Path.t * string - | Invalid_interval | Invalid_for_loop_index - | Invalid_for_of_pattern | No_value_clauses | Exception_pattern_below_toplevel | Inlined_record_escape From 53c4b404999098696b273b7f11e6d581f2da436e Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:10:52 +0000 Subject: [PATCH 05/16] Remove parser-blocked typetexp variants Drop Unbound_type_constructor_2, Ill_typed_functor_application, and Apply_structure_as_functor from Typetexp.error. The first needs an inherited constructor whose body expands to a bare Tvar, which ReScript source cannot construct; the latter two only sit under Longident.Lapply, which the parser does not emit. The old guard sites now use direct Location errors as malformed-AST fallbacks. Validation: rg found no remaining references to the named variants. --- compiler/ml/typetexp.ml | 23 ++++++++++------------- compiler/ml/typetexp.mli | 3 --- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler/ml/typetexp.ml b/compiler/ml/typetexp.ml index 2e735329db..12e1a36edf 100644 --- a/compiler/ml/typetexp.ml +++ b/compiler/ml/typetexp.ml @@ -28,7 +28,6 @@ exception Already_bound type error = | Unbound_type_variable of string | Unbound_type_constructor of Longident.t - | Unbound_type_constructor_2 of Path.t | Type_arity_mismatch of Longident.t * int * int | Type_mismatch of (type_expr * type_expr) list | Alias_type_mismatch of (type_expr * type_expr) list @@ -45,10 +44,8 @@ type error = | Unbound_label of Longident.t * type_expr option | Unbound_module of Longident.t | Unbound_modtype of Longident.t - | Ill_typed_functor_application of Longident.t | Illegal_reference_to_recursive_module | Access_functor_as_structure of Longident.t - | Apply_structure_as_functor of Longident.t | Cannot_scrape_alias of Longident.t * Path.t | Opened_object of Path.t option | Not_an_object of type_expr @@ -89,7 +86,8 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = let fmd = Env.find_module (Env.lookup_module ~load:true flid env) env in (match Env.scrape_alias env fmd.md_type with | Mty_signature _ -> - raise (Error (loc, env, Apply_structure_as_functor flid)) + Location.raise_errorf ~loc "The module %a is a structure, not a functor" + Printtyp.longident flid | Mty_alias (_, p) -> raise (Error (loc, env, Cannot_scrape_alias (flid, p))) | _ -> ()); @@ -98,7 +96,9 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = match Env.scrape_alias env mmd.md_type with | Mty_alias (_, p) -> raise (Error (loc, env, Cannot_scrape_alias (mlid, p))) - | _ -> raise (Error (loc, env, Ill_typed_functor_application lid)))); + | _ -> + Location.raise_errorf ~loc "Ill-typed functor application %a" + Printtyp.longident lid)); raise (Error (loc, env, make_error lid)) let find_component (lookup : ?loc:_ -> _) make_error env loc lid = @@ -471,7 +471,9 @@ and transl_type_aux env policy styp = let row = Btype.row_repr row in row.row_fields | {desc = Tvar _}, Some (p, _) -> - raise (Error (sty.ptyp_loc, env, Unbound_type_constructor_2 p)) + Location.raise_errorf ~loc:sty.ptyp_loc + "The type constructor %a is not yet completely defined" + Printtyp.path p | _ -> raise (Error (sty.ptyp_loc, env, Not_a_variant ty)) in List.iter @@ -615,7 +617,8 @@ and transl_fields env policy o fields = iter_add tf; OTinherit cty | {desc = Tvar _}, Some p -> - raise (Error (sty.ptyp_loc, env, Unbound_type_constructor_2 p)) + Location.raise_errorf ~loc:sty.ptyp_loc + "The type constructor %a is not yet completely defined" Printtyp.path p | _ -> raise (Error (sty.ptyp_loc, env, Not_an_object t))) in let object_fields = List.map add_field fields in @@ -779,8 +782,6 @@ let report_error env ppf = function Format.fprintf ppf "If you wanted to write a recursive type, don't forget the `rec` in \ `type rec`@]" - | Unbound_type_constructor_2 p -> - fprintf ppf "The type constructor@ %a@ is not yet completely defined" path p | Type_arity_mismatch (lid, expected, provided) -> if expected == 0 then fprintf ppf @@ -954,14 +955,10 @@ let report_error env ppf = function | Unbound_modtype lid -> fprintf ppf "Unbound module type %a" longident lid; spellcheck ppf fold_modtypes env lid - | Ill_typed_functor_application lid -> - fprintf ppf "Ill-typed functor application %a" longident lid | Illegal_reference_to_recursive_module -> fprintf ppf "Illegal recursive module reference" | Access_functor_as_structure lid -> fprintf ppf "The module %a is a functor, not a structure" longident lid - | Apply_structure_as_functor lid -> - fprintf ppf "The module %a is a structure, not a functor" longident lid | Cannot_scrape_alias (lid, p) -> fprintf ppf "The module %a is an alias for module %a, which is missing" longident lid path p diff --git a/compiler/ml/typetexp.mli b/compiler/ml/typetexp.mli index cff8910482..565535cb09 100644 --- a/compiler/ml/typetexp.mli +++ b/compiler/ml/typetexp.mli @@ -37,7 +37,6 @@ exception Already_bound type error = | Unbound_type_variable of string | Unbound_type_constructor of Longident.t - | Unbound_type_constructor_2 of Path.t | Type_arity_mismatch of Longident.t * int * int | Type_mismatch of (type_expr * type_expr) list | Alias_type_mismatch of (type_expr * type_expr) list @@ -54,10 +53,8 @@ type error = | Unbound_label of Longident.t * type_expr option | Unbound_module of Longident.t | Unbound_modtype of Longident.t - | Ill_typed_functor_application of Longident.t | Illegal_reference_to_recursive_module | Access_functor_as_structure of Longident.t - | Apply_structure_as_functor of Longident.t | Cannot_scrape_alias of Longident.t * Path.t | Opened_object of Path.t option | Not_an_object of type_expr From 9ea38c36cb8d2d6f0d7c169578f33e3e81af8f0b Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:12:00 +0000 Subject: [PATCH 06/16] Remove unreachable typedecl variants Drop Type_clash, Parameters_differ, Null_arity_external, Rebind_wrong_type, Bad_fixed_type, Varying_anonymous, and Val_in_structure from Typedecl.error. These guarded paths are rejected or normalized before the named diagnostics can fire in modern ReScript: recursive aliases are caught earlier, external declarations are encoded or rejected earlier, extension rebind result types unify by construction, fixed rows preserve their open row shape, anonymous type parameters are not parsed, and structure val declarations with empty prims do not reach the typer from source. The old guard sites now use direct Location errors as malformed-AST fallbacks. Validation: rg found no remaining references to the named variants. --- compiler/ml/typedecl.ml | 67 +++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/compiler/ml/typedecl.ml b/compiler/ml/typedecl.ml index 0f44d4595f..39eef5fed4 100644 --- a/compiler/ml/typedecl.ml +++ b/compiler/ml/typedecl.ml @@ -34,22 +34,15 @@ type error = | Definition_mismatch of type_expr * Includecore.type_mismatch list | Constraint_failed of type_expr * type_expr | Inconsistent_constraint of Env.t * (type_expr * type_expr) list - | Type_clash of Env.t * (type_expr * type_expr) list - | Parameters_differ of Path.t * type_expr * type_expr - | Null_arity_external | Unbound_type_var of type_expr * type_declaration | Cannot_extend_private_type of Path.t | Not_extensible_type of Path.t | Extension_mismatch of Path.t * Includecore.type_mismatch list - | Rebind_wrong_type of Longident.t * Env.t * (type_expr * type_expr) list | Rebind_mismatch of Longident.t * Path.t * Path.t | Rebind_private of Longident.t | Bad_variance of int * (bool * bool * bool) * (bool * bool * bool) | Unavailable_type_constructor of Path.t - | Bad_fixed_type of string | Unbound_type_var_ext of type_expr * extension_constructor - | Varying_anonymous - | Val_in_structure | Invalid_attribute of string | Bad_immediate_attribute | Bad_unboxed_attribute of string @@ -122,7 +115,9 @@ let update_type temp_env env id loc = | Some ty -> ( let params = List.map (fun _ -> Ctype.newvar ()) decl.type_params in try Ctype.unify env (Ctype.newconstr path params) ty - with Ctype.Unify trace -> raise (Error (loc, Type_clash (env, trace)))) + with Ctype.Unify _ -> + Location.raise_errorf ~loc + "This type constructor expands to an incompatible type.") (* We use the Ctype.expand_head_opt version of expand_head to get access to the manifest type of private abbreviations. *) @@ -187,10 +182,12 @@ let set_fixed_row env loc p decl = tm.desc <- Tvariant {row with row_fixed = true}; if Btype.static_row row then Btype.newgenty Tnil else row.row_more | Tobject (ty, _) -> snd (Ctype.flatten_fields ty) - | _ -> raise (Error (loc, Bad_fixed_type "is not an object or variant")) + | _ -> + Location.raise_errorf ~loc + "This fixed type is not an object or variant" in if not (Btype.is_Tvar rv) then - raise (Error (loc, Bad_fixed_type "has no row variable")); + Location.raise_errorf ~loc "This fixed type has no row variable"; rv.desc <- Tconstr (p, decl.type_params, ref Mnil) (* Translate one type declaration *) @@ -982,11 +979,9 @@ let check_recursion env loc path decl to_check = | Tconstr (path', args', _) -> (if Path.same path path' then ( if not (Ctype.equal env false args args') then - raise - (Error - ( loc, - Parameters_differ (cpath, ty, Ctype.newconstr path args) - ))) + Location.raise_errorf ~loc + "In the definition of %s, recursive type parameters differ." + (Path.name cpath)) else if (* Attempt to expand a type abbreviation if: 1- [to_check path'] holds @@ -1260,7 +1255,9 @@ let compute_variance_gadt env check ((required, loc) as rloc) decl | fv :: fv2 -> (* fv1 @ fv2 = free_variables of other parameters *) if (c || n) && constrained (fv1 @ fv2) ty then - raise (Error (loc, Varying_anonymous)); + Location.raise_errorf ~loc + "In this GADT definition, the variance of some parameter \ + cannot be checked."; (fv :: fv1, fv2)) ([], fvl) tyl required in @@ -1649,8 +1646,11 @@ let transl_extension_constructor env type_path type_params typext_params priv else (Ctype.newconstr type_path typext_params, None) in (try Ctype.unify env cstr_res res - with Ctype.Unify trace -> - raise (Error (lid.loc, Rebind_wrong_type (lid.txt, env, trace)))); + with Ctype.Unify _ -> + Location.raise_errorf ~loc:lid.loc + "The constructor %a has a type that is incompatible with this \ + extension" + Printtyp.longident lid.txt); (* Remove "_" names from parameters used in the constructor *) (if not cdescr.cstr_generalized then let vars = Ctype.free_variables (Btype.newgenty (Ttuple args)) in @@ -1884,7 +1884,9 @@ let transl_value_decl env loc valdecl = Types.val_loc = loc; val_attributes = valdecl.pval_attributes; } - | [] -> raise (Error (valdecl.pval_loc, Val_in_structure)) + | [] -> + Location.raise_errorf ~loc:valdecl.pval_loc + "Value declarations are only allowed in signatures" | _ -> let arity, from_constructor = parse_arity env valdecl.pval_type ty in let prim = Primitive.parse_declaration valdecl ~arity ~from_constructor in @@ -1897,7 +1899,9 @@ let transl_value_decl env loc valdecl = && String.unsafe_get prim_native_name 1 = '\149')) && (prim.prim_name = "" || (prim.prim_name.[0] <> '%' && prim.prim_name.[0] <> '#')) - then raise (Error (valdecl.pval_type.ptyp_loc, Null_arity_external)); + then + Location.raise_errorf ~loc:valdecl.pval_type.ptyp_loc + "External identifiers must be functions"; { val_type = ty; val_kind = Val_prim prim; @@ -2153,22 +2157,11 @@ let report_error ppf = function fprintf ppf "@[%s@ @[Type@ %a@ should be an instance of@ %a@]@]" "Constraints are not satisfied in this type." Printtyp.type_expr ty Printtyp.type_expr ty' - | Parameters_differ (path, ty, ty') -> - Printtyp.reset_and_mark_loops ty; - Printtyp.mark_loops ty'; - fprintf ppf "@[In the definition of %s, type@ %a@ should be@ %a@]" - (Path.name path) Printtyp.type_expr ty Printtyp.type_expr ty' | Inconsistent_constraint (env, trace) -> fprintf ppf "The type constraints are not consistent.@."; Printtyp.report_unification_error ppf env trace (fun ppf -> fprintf ppf "Type") (fun ppf -> fprintf ppf "is not compatible with type") - | Type_clash (env, trace) -> - Printtyp.report_unification_error ppf env trace - (function - | ppf -> fprintf ppf "This type constructor expands to type") - (function ppf -> fprintf ppf "but is used here with type") - | Null_arity_external -> fprintf ppf "External identifiers must be functions" | Unbound_type_var (ty, decl) -> ( fprintf ppf "A type variable is unbound in this type declaration"; let ty = Ctype.repr ty in @@ -2204,12 +2197,6 @@ let report_error ppf = function "does not match the definition of type" (Path.name path) (Includecore.report_type_mismatch "the type" "this extension" "definition") errs - | Rebind_wrong_type (lid, env, trace) -> - Printtyp.report_unification_error ppf env trace - (function - | ppf -> - fprintf ppf "The constructor %a@ has type" Printtyp.longident lid) - (function ppf -> fprintf ppf "but was expected to be of type") | Rebind_mismatch (lid, p, p') -> fprintf ppf "@[%s@ %a@ %s@ %s@ %s@ %s@ %s@]" "The constructor" Printtyp.longident lid "extends type" (Path.name p) @@ -2256,12 +2243,6 @@ let report_error ppf = function (variance v1) | Unavailable_type_constructor p -> fprintf ppf "The definition of type %a@ is unavailable" Printtyp.path p - | Bad_fixed_type r -> fprintf ppf "This fixed type %s" r - | Varying_anonymous -> - fprintf ppf "@[%s@ %s@ %s@]" "In this GADT definition," - "the variance of some parameter" "cannot be checked" - | Val_in_structure -> - fprintf ppf "Value declarations are only allowed in signatures" | Bad_immediate_attribute -> fprintf ppf "@[%s@ %s@]" "Types marked with the immediate attribute must be" "non-pointer types like int or bool" From 5428128afecdf844f3a8a7f0955328025f58be9f Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:12:57 +0000 Subject: [PATCH 07/16] Remove unreachable typemod variants Drop Cannot_eliminate_dependency, With_makes_applicative_functor_ill_typed, With_cannot_remove_constrained_type, and Scoping_pack from Typemod.error. The dead reports were guarded by paths the current module pipeline does not reach: nondep_supertype falls back instead of raising Not_found, applicative Papply constraints are not parsed from source, destructive type substitutions only get fresh type variables, and the package scoping mismatch is a defensive fallback. The old guard sites now use direct Location errors as malformed-AST fallbacks. Validation: rg found no remaining references to the named variants. --- compiler/ml/typemod.ml | 54 +++++++++++++++-------------------------- compiler/ml/typemod.mli | 5 ---- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/compiler/ml/typemod.ml b/compiler/ml/typemod.ml index 0932c62f34..7fec8d74db 100644 --- a/compiler/ml/typemod.ml +++ b/compiler/ml/typemod.ml @@ -24,15 +24,11 @@ open Format type error = | Cannot_apply of module_type | Not_included of Includemod.error list - | Cannot_eliminate_dependency of module_type | Signature_expected | Structure_expected of module_type | With_no_component of Longident.t | With_mismatch of Longident.t * Includemod.error list - | With_makes_applicative_functor_ill_typed of - Longident.t * Path.t * Includemod.error list | With_changes_module_alias of Longident.t * Ident.t * Path.t - | With_cannot_remove_constrained_type | Repeated_name of string * string * Warnings.loc | Non_generalizable of type_expr | Non_generalizable_module of module_type @@ -40,7 +36,6 @@ type error = | Not_allowed_in_functor_body | Not_a_packed_module of type_expr | Incomplete_packed_module of type_expr - | Scoping_pack of Longident.t * type_expr | Recursive_module_require_explicit_type | Apply_generative | Cannot_scrape_alias of Path.t @@ -251,12 +246,12 @@ let check_usage_of_path_of_substituted_item paths env signature ~loc ~lid = let env = !env in try retype_applicative_functor_type ~loc env funct arg with Includemod.Error explanation -> - raise - (Error - ( loc, - env, - With_makes_applicative_functor_ill_typed - (lid.txt, referenced_path, explanation) )))); + Location.raise_errorf ~loc + "@[@[This `with' constraint on %a makes the \ + applicative functor type %s ill-typed in the constrained \ + signature:@]@ %a@]" + Printtyp.longident lid.txt (Path.name referenced_path) + Includemod.report_error explanation)); } in iterator.Btype.it_signature iterator signature; @@ -439,8 +434,10 @@ let merge_constraint initial_env loc sg constr = in let params = tdecl.typ_type.type_params in if params_are_constrained params then - raise - (Error (loc, initial_env, With_cannot_remove_constrained_type)); + Location.raise_errorf ~loc + "@[Destructive substitutions are not supported for \ + constrained types (other than when replacing a type \ + constructor with a type constructor with the same arguments).@]"; fun s path -> Subst.add_type_function path ~params ~body s in let sub = List.fold_left how_to_extend_subst Subst.identity !real_ids in @@ -1330,9 +1327,11 @@ and type_module_aux ~alias sttn funct_body anchor env smod = (Env.add_module ~arg:true param arg.mod_type env) param mty_res with Not_found -> - raise - (Error - (smod.pmod_loc, env, Cannot_eliminate_dependency mty_functor)) + Location.raise_errorf ~loc:smod.pmod_loc + "@[This functor has type@ %a@ The parameter cannot be \ + eliminated in the result type.@ Bind the argument to a \ + module identifier.@]" + Printtyp.modtype mty_functor ) in rm @@ -1714,7 +1713,10 @@ let type_package env m p nl = (fun n ty -> try Ctype.unify env ty (Ctype.newvar ()) with Ctype.Unify _ -> - raise (Error (m.pmod_loc, env, Scoping_pack (n, ty)))) + Location.raise_errorf ~loc:m.pmod_loc + "@[The type %a in this module cannot be exported.@ Its type \ + contains local dependencies:@ %a@]" + Printtyp.longident n Printtyp.type_expr ty) nl tl'; (wrap_constraint env modl mty Tmodtype_implicit, tl') @@ -1818,11 +1820,6 @@ let report_error ppf = function fprintf ppf "@[This module is not a functor; it has type@ %a@]" modtype mty | Not_included errs -> fprintf ppf "@[Signature mismatch:@ %a@]" Includemod.report_error errs - | Cannot_eliminate_dependency mty -> - fprintf ppf - "@[This functor has type@ %a@ The parameter cannot be eliminated in the \ - result type.@ Bind the argument to a module identifier.@]" - modtype mty | Signature_expected -> fprintf ppf "This module type is not a signature" | Structure_expected mty -> fprintf ppf "@[This module is not a structure; it has type@ %a" modtype mty @@ -1835,21 +1832,11 @@ let report_error ppf = function "@[@[In this `with' constraint, the new definition of %a@ does not \ match its original definition@ in the constrained signature:@]@ %a@]" longident lid Includemod.report_error explanation - | With_makes_applicative_functor_ill_typed (lid, path, explanation) -> - fprintf ppf - "@[@[This `with' constraint on %a makes the applicative functor @ \ - type %s ill-typed in the constrained signature:@]@ %a@]" - longident lid (Path.name path) Includemod.report_error explanation | With_changes_module_alias (lid, id, path) -> fprintf ppf "@[@[This `with' constraint on %a changes %s, which is aliased @ in \ the constrained signature (as %s)@].@]" longident lid (Path.name path) (Ident.name id) - | With_cannot_remove_constrained_type -> - fprintf ppf - "@[Destructive substitutions are not supported for constrained @ \ - types (other than when replacing a type constructor with @ a type \ - constructor with the same arguments).@]" | Repeated_name (kind, name, repeated_loc) -> fprintf ppf "@[Multiple definition of the %s name %s @ at @{%a@}@ @ Names must \ @@ -1887,9 +1874,6 @@ let report_error ppf = function | Incomplete_packed_module ty -> fprintf ppf "The type of this packed module contains variables:@ %a" type_expr ty - | Scoping_pack (lid, ty) -> - fprintf ppf "The type %a in this module cannot be exported.@ " longident lid; - fprintf ppf "Its type contains local dependencies:@ %a" type_expr ty | Recursive_module_require_explicit_type -> fprintf ppf "Recursive modules require an explicit module type." | Apply_generative -> diff --git a/compiler/ml/typemod.mli b/compiler/ml/typemod.mli index 0f36cf6afd..8eea12e2f6 100644 --- a/compiler/ml/typemod.mli +++ b/compiler/ml/typemod.mli @@ -64,15 +64,11 @@ val save_signature : type error = | Cannot_apply of module_type | Not_included of Includemod.error list - | Cannot_eliminate_dependency of module_type | Signature_expected | Structure_expected of module_type | With_no_component of Longident.t | With_mismatch of Longident.t * Includemod.error list - | With_makes_applicative_functor_ill_typed of - Longident.t * Path.t * Includemod.error list | With_changes_module_alias of Longident.t * Ident.t * Path.t - | With_cannot_remove_constrained_type | Repeated_name of string * string * Warnings.loc | Non_generalizable of type_expr | Non_generalizable_module of module_type @@ -80,7 +76,6 @@ type error = | Not_allowed_in_functor_body | Not_a_packed_module of type_expr | Incomplete_packed_module of type_expr - | Scoping_pack of Longident.t * type_expr | Recursive_module_require_explicit_type | Apply_generative | Cannot_scrape_alias of Path.t From 31c4cd3dfc477660943f4310348dcc400a88aeb1 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:13:32 +0000 Subject: [PATCH 08/16] Remove parser-blocked frontend syntax variants Drop Unhandled_poly_type and Misplaced_label_syntax from Bs_syntaxerr.error. Inline polytypes in external arrow chains and labeled arguments to the legacy ->/#=/## rewrites are not emitted by the ReScript parser. The old guard sites now raise direct Location errors as malformed-AST fallbacks. Validation: rg found no remaining references to the named variants. --- compiler/frontend/ast_core_type.ml | 3 +-- compiler/frontend/bs_syntaxerr.ml | 10 ++-------- compiler/frontend/bs_syntaxerr.mli | 2 -- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/frontend/ast_core_type.ml b/compiler/frontend/ast_core_type.ml index b93c4586bf..3f056c2bb4 100644 --- a/compiler/frontend/ast_core_type.ml +++ b/compiler/frontend/ast_core_type.ml @@ -137,8 +137,7 @@ let list_of_arrow (ty : t) : t * Parsetree.arg list = | Ptyp_arrow {arg; ret; arity} when arity = None || acc = [] -> aux ret (arg :: acc) | Ptyp_poly (_, ty) -> - (* should not happen? *) - Bs_syntaxerr.err ty.ptyp_loc Unhandled_poly_type + Location.raise_errorf ~loc:ty.ptyp_loc "Unhandled poly type" | _ -> (ty, List.rev acc) in aux ty [] diff --git a/compiler/frontend/bs_syntaxerr.ml b/compiler/frontend/bs_syntaxerr.ml index 9cadcb5897..7ef491e6f9 100644 --- a/compiler/frontend/bs_syntaxerr.ml +++ b/compiler/frontend/bs_syntaxerr.ml @@ -31,7 +31,6 @@ type error = | Expect_int_literal | Expect_string_literal | Expect_int_or_string_or_json_literal - | Unhandled_poly_type | Invalid_underscore_type_in_external | Invalid_bs_string_type | Invalid_bs_int_type @@ -43,7 +42,6 @@ type error = *) | Not_supported_directive_in_bs_return | Expect_opt_in_bs_return_to_opt - | Misplaced_label_syntax | Optional_in_uncurried_bs_attribute | Bs_this_simple_pattern | Experimental_feature_not_enabled of Experimental_features.feature @@ -52,10 +50,6 @@ type error = let pp_error fmt err = Format.pp_print_string fmt (match err with - | Misplaced_label_syntax -> "Label syntax is not support in this position" - (* - let fn x = ((##) x ~hi) ~lo:1 ~hi:2 - *) | Optional_in_uncurried_bs_attribute -> "Uncurried function doesn't support optional arguments yet" | Expect_opt_in_bs_return_to_opt -> @@ -70,7 +64,6 @@ let pp_error fmt err = | Expect_int_literal -> "expect int literal " | Expect_int_or_string_or_json_literal -> "expect int, string literal or json literal {json|text here|json} " - | Unhandled_poly_type -> "Unhandled poly type" | Invalid_underscore_type_in_external -> "_ is not allowed in combination with external optional type" | Invalid_bs_string_type -> "Not a valid type for %@string" @@ -110,4 +103,5 @@ let optional_err loc (lbl : Asttypes.arg_label) = | _ -> () let err_if_label loc (lbl : Asttypes.arg_label) = - if lbl <> Nolabel then raise (Error (loc, Misplaced_label_syntax)) + if lbl <> Nolabel then + Location.raise_errorf ~loc "Label syntax is not supported in this position" diff --git a/compiler/frontend/bs_syntaxerr.mli b/compiler/frontend/bs_syntaxerr.mli index 9c6a9ff9b5..c174245fb1 100644 --- a/compiler/frontend/bs_syntaxerr.mli +++ b/compiler/frontend/bs_syntaxerr.mli @@ -31,7 +31,6 @@ type error = | Expect_int_literal | Expect_string_literal | Expect_int_or_string_or_json_literal - | Unhandled_poly_type | Invalid_underscore_type_in_external | Invalid_bs_string_type | Invalid_bs_int_type @@ -43,7 +42,6 @@ type error = *) | Not_supported_directive_in_bs_return | Expect_opt_in_bs_return_to_opt - | Misplaced_label_syntax | Optional_in_uncurried_bs_attribute | Bs_this_simple_pattern | Experimental_feature_not_enabled of Experimental_features.feature From 827d3f6edc5fa5dc51677c024501be1e112b33ec Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:14:04 +0000 Subject: [PATCH 09/16] Remove parser-blocked env value-name variant Drop Illegal_value_name from Env.error. The ReScript parser does not emit value identifiers named -> or containing #, so the named environment error is unreachable from source. The check_value_name guard now raises a direct Location error for malformed PPX-forged identifiers. Validation: rg found no remaining references to the named variant. --- compiler/ml/env.ml | 14 +++++--------- compiler/ml/env.mli | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/ml/env.ml b/compiler/ml/env.ml index 970634be03..b6e23e8def 100644 --- a/compiler/ml/env.ml +++ b/compiler/ml/env.ml @@ -58,7 +58,6 @@ type error = | Illegal_renaming of string * string * string | Inconsistent_import of string * string * string | Missing_module of Location.t * Path.t * Path.t - | Illegal_value_name of Location.t * string exception Error of error @@ -730,7 +729,6 @@ let check_pers_struct name = Location.print_filename filename ps_name name | Inconsistent_import _ -> assert false | Missing_module _ -> assert false - | Illegal_value_name _ -> assert false in let warn = Warnings.No_cmi_file (name, Some msg) in Location.prerr_warning Location.none warn @@ -1619,10 +1617,12 @@ and check_value_name name loc = (* Note: we could also check here general validity of the identifier, to protect against bad identifiers forged by -pp or -ppx preprocessors. *) - if name = "->" then raise (Error (Illegal_value_name (loc, name))) + if name = "->" then + Location.raise_errorf ~loc "'%s' is not a valid value identifier." name else if String.length name > 0 && name.[0] = '#' then for i = 1 to String.length name - 1 do - if name.[i] = '#' then raise (Error (Illegal_value_name (loc, name))) + if name.[i] = '#' then + Location.raise_errorf ~loc "'%s' is not a valid value identifier." name done and store_value ?check id decl env = @@ -2129,13 +2129,9 @@ let report_error ppf = function fprintf ppf "@]@ @[%s@ %s@ %s.@]@]" "The compiled interface for module" (Ident.name (Path.head path2)) "was not found" - | Illegal_value_name (_loc, name) -> - fprintf ppf "'%s' is not a valid value identifier." name - let () = Location.register_error_of_exn (function - | Error ((Missing_module (loc, _, _) | Illegal_value_name (loc, _)) as err) - when loc <> Location.none -> + | Error (Missing_module (loc, _, _) as err) when loc <> Location.none -> Some (Location.error_of_printer loc report_error err) | Error err -> Some (Location.error_of_printer_file report_error err) | _ -> None) diff --git a/compiler/ml/env.mli b/compiler/ml/env.mli index 48eaba1c10..90946f94e3 100644 --- a/compiler/ml/env.mli +++ b/compiler/ml/env.mli @@ -236,7 +236,6 @@ type error = | Illegal_renaming of string * string * string | Inconsistent_import of string * string * string | Missing_module of Location.t * Path.t * Path.t - | Illegal_value_name of Location.t * string exception Error of error From 1b05aada15ca0c1e7ed757970661fe06096ff061 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:15:54 +0000 Subject: [PATCH 10/16] Remove leftover typecore label helper Drop has_label after removing the unreachable Incoherent_label_order path. The full make checkpoint caught it as an unused helper under the repository warning policy. Validation: make -j2 completed successfully after this cleanup. --- compiler/ml/typecore.ml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index eb164f77d0..8e6da258c6 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -3734,10 +3734,6 @@ and type_application ~context total_app env funct (sargs : sargs) : newty2 lv (Tarrow ({lbl = l; typ = ty}, ty_fun, Cok, None))) ty_fun omitted in - let has_label l ty_fun = - let ls, tvar = list_labels env ty_fun in - tvar || List.mem l ls - in let ignored = ref [] in let force_tvar = let t = funct.exp_type in From d6acfe1cf9b53bd6af04fa1dbc0bd0763a429740 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:21:37 +0000 Subject: [PATCH 11/16] Remove dead warning constructors Drop warning constructors that have no live raise path: old OCaml lexer/class/docstring warnings, unused BuckleScript warnings, Statement_type, Unerasable_optional_argument, and Bs_uninterpreted_delimiters. Statement_type was guarded by a check_application_result argument that is only ever false. Unerasable_optional_argument was disabled around its only check. Bs_uninterpreted_delimiters only covered the old unprocessed js delimiter warning path, which modern string handling no longer uses. The warning numbers remain holes; no existing warning numbers were reused. Validation: rg found no remaining references to the removed warning constructors, and make -j2 completed successfully. --- compiler/common/bs_warnings.ml | 3 - compiler/common/bs_warnings.mli | 2 - compiler/ext/warnings.ml | 104 ------------------- compiler/ext/warnings.mli | 14 --- compiler/frontend/ast_utf8_string_interp.ml | 3 - compiler/frontend/ast_utf8_string_interp.mli | 1 - compiler/frontend/bs_ast_invariant.ml | 3 - compiler/ml/typecore.ml | 34 +----- 8 files changed, 3 insertions(+), 161 deletions(-) diff --git a/compiler/common/bs_warnings.ml b/compiler/common/bs_warnings.ml index aeea997b82..61e55032ee 100644 --- a/compiler/common/bs_warnings.ml +++ b/compiler/common/bs_warnings.ml @@ -24,6 +24,3 @@ let warn_literal_overflow loc = Location.prerr_warning loc Bs_integer_literal_overflow - -let error_unescaped_delimiter loc txt = - Location.prerr_warning loc (Bs_uninterpreted_delimiters txt) diff --git a/compiler/common/bs_warnings.mli b/compiler/common/bs_warnings.mli index 3807bbf32c..d31e084607 100644 --- a/compiler/common/bs_warnings.mli +++ b/compiler/common/bs_warnings.mli @@ -23,5 +23,3 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) val warn_literal_overflow : Location.t -> unit - -val error_unescaped_delimiter : Location.t -> string -> unit diff --git a/compiler/ext/warnings.ml b/compiler/ext/warnings.ml index 936f34c4e0..3bbb738346 100644 --- a/compiler/ext/warnings.ml +++ b/compiler/ext/warnings.ml @@ -29,21 +29,13 @@ type loc = { type top_level_unit_help = FunctionCall | Other type t = - | Comment_start (* 1 *) - | Comment_not_end (* 2 *) | Deprecated of string * loc * loc * bool (* 3 *) | Fragile_match of string (* 4 *) | Partial_application (* 5 *) - | Method_override of string list (* 7 *) | Partial_match of string (* 8 *) | Non_closed_record_pattern of string (* 9 *) - | Statement_type (* 10 *) | Unused_match (* 11 *) | Unused_pat (* 12 *) - | Instance_variable_override of string list (* 13 *) - | Illegal_backslash (* 14 *) - | Implicit_public_methods of string list (* 15 *) - | Unerasable_optional_argument (* 16 *) | Unused_argument (* 20 *) | Nonreturning_statement (* 21 *) | Preprocessor of string (* 22 *) @@ -53,7 +45,6 @@ type t = | Unused_var of string (* 26 *) | Unused_var_strict of string (* 27 *) | Wildcard_arg_to_constant_constr (* 28 *) - | Eol_in_string (* 29 *) | Duplicate_definitions of string * string * string * string (*30 *) | Unused_value_declaration of string (* 32 *) | Unused_open of string (* 33 *) @@ -67,9 +58,7 @@ type t = | Open_shadow_identifier of string * string (* 44 *) | Open_shadow_label_constructor of string * string (* 45 *) | Attribute_payload of string * string (* 47 *) - | Eliminated_optional_arguments of string list (* 48 *) | No_cmi_file of string * string option (* 49 *) - | Bad_docstring of bool (* 50 *) | Fragile_literal_pattern (* 52 *) | Misplaced_attribute of string (* 53 *) | Duplicated_attribute of string (* 54 *) @@ -81,10 +70,7 @@ type t = | Bs_polymorphic_comparison (* 102 *) | Bs_ffi_warning of string (* 103 *) | Bs_derive_warning of string (* 104 *) - | Bs_fragile_external of string (* 105 *) - | Bs_unimplemented_primitive of string (* 106 *) | Bs_integer_literal_overflow (* 107 *) - | Bs_uninterpreted_delimiters of string (* 108 *) | Bs_toplevel_expression_unit of (string * top_level_unit_help) option (* 109 *) | Bs_todo of string option (* 110 *) @@ -96,21 +82,13 @@ type t = *) let number = function - | Comment_start -> 1 - | Comment_not_end -> 2 | Deprecated _ -> 3 | Fragile_match _ -> 4 | Partial_application -> 5 - | Method_override _ -> 7 | Partial_match _ -> 8 | Non_closed_record_pattern _ -> 9 - | Statement_type -> 10 | Unused_match -> 11 | Unused_pat -> 12 - | Instance_variable_override _ -> 13 - | Illegal_backslash -> 14 - | Implicit_public_methods _ -> 15 - | Unerasable_optional_argument -> 16 | Unused_argument -> 20 | Nonreturning_statement -> 21 | Preprocessor _ -> 22 @@ -120,7 +98,6 @@ let number = function | Unused_var _ -> 26 | Unused_var_strict _ -> 27 | Wildcard_arg_to_constant_constr -> 28 - | Eol_in_string -> 29 | Duplicate_definitions _ -> 30 | Unused_value_declaration _ -> 32 | Unused_open _ -> 33 @@ -134,9 +111,7 @@ let number = function | Open_shadow_identifier _ -> 44 | Open_shadow_label_constructor _ -> 45 | Attribute_payload _ -> 47 - | Eliminated_optional_arguments _ -> 48 | No_cmi_file _ -> 49 - | Bad_docstring _ -> 50 | Fragile_literal_pattern -> 52 | Misplaced_attribute _ -> 53 | Duplicated_attribute _ -> 54 @@ -148,10 +123,7 @@ let number = function | Bs_polymorphic_comparison -> 102 | Bs_ffi_warning _ -> 103 | Bs_derive_warning _ -> 104 - | Bs_fragile_external _ -> 105 - | Bs_unimplemented_primitive _ -> 106 | Bs_integer_literal_overflow -> 107 - | Bs_uninterpreted_delimiters _ -> 108 | Bs_toplevel_expression_unit _ -> 109 | Bs_todo _ -> 110 @@ -297,8 +269,6 @@ let reset () = let () = reset () let message = function - | Comment_start -> "this is the start of a comment." - | Comment_not_end -> "this is not the end of a comment." | Deprecated (s, _, _, can_be_automigrated) -> (* Reduce \r\n to \n: - Prevents any \r characters being printed on Unix when processing @@ -321,12 +291,6 @@ let message = function It will remain exhaustive when constructors are added to type " ^ s ^ "." | Partial_application -> "this function application is partial,\nmaybe some arguments are missing." - | Method_override [lab] -> "the method " ^ lab ^ " is overridden." - | Method_override (cname :: slist) -> - String.concat " " - ("the following methods are overridden by the class" :: cname :: ":\n " - :: slist) - | Method_override [] -> assert false | Partial_match "" -> "You forgot to handle a possible case here, though we don't have more \ information on the value." @@ -335,42 +299,8 @@ let message = function | Non_closed_record_pattern s -> "the following labels are not bound in this record pattern: " ^ s ^ "\nEither bind these labels explicitly or add ', _' to the pattern." - | Statement_type -> - "This expression returns a value, but you're not doing anything with it. \ - If this is on purpose, wrap it with `ignore`." | Unused_match -> "this match case is unused." | Unused_pat -> "this sub-pattern is unused." - | Instance_variable_override [lab] -> - "the instance variable " ^ lab ^ " is overridden.\n" - ^ "The behaviour changed in ocaml 3.10 (previous behaviour was hiding.)" - | Instance_variable_override (cname :: slist) -> - String.concat " " - ("the following instance variables are overridden by the class" :: cname - :: ":\n " :: slist) - ^ "\nThe behaviour changed in ocaml 3.10 (previous behaviour was hiding.)" - | Instance_variable_override [] -> assert false - | Illegal_backslash -> "illegal backslash escape in string." - | Implicit_public_methods l -> - "the following private methods were made public implicitly:\n " - ^ String.concat " " l ^ "." - | Unerasable_optional_argument -> - String.concat "" - [ - "This optional parameter in final position will, in practice, not be \ - optional.\n"; - " Reorder the parameters so that at least one non-optional one is in \ - final position or, if all parameters are optional, insert a final \ - ().\n\n"; - " Explanation: If the final parameter is optional, it'd be unclear \ - whether a function application that omits it should be considered \ - fully applied, or partially applied. Imagine writing `let title = \ - display(\"hello!\")`, only to realize `title` isn't your desired \ - result, but a curried call that takes a final optional argument, e.g. \ - `~showDate`.\n\n"; - " Formal rule: an optional argument is considered intentionally \ - omitted when the 1st positional (i.e. neither labeled nor optional) \ - argument defined after it is passed in."; - ] | Unused_argument -> "this argument will not be used by the function." | Nonreturning_statement -> "This statement does not continue execution; following code is unreachable." @@ -398,8 +328,6 @@ let message = function v v | Wildcard_arg_to_constant_constr -> "wildcard pattern given as argument to a constant constructor" - | Eol_in_string -> - "unescaped end-of-line in a string constant (non-portable code)" | Duplicate_definitions (kind, cname, tc1, tc2) -> Printf.sprintf "the %s %s is defined in both types %s and %s." kind cname tc1 tc2 @@ -446,18 +374,11 @@ let message = function kind s | Attribute_payload (a, s) -> Printf.sprintf "illegal payload for attribute '%s'.\n%s" a s - | Eliminated_optional_arguments sl -> - Printf.sprintf "implicit elimination of optional argument%s %s" - (if List.length sl = 1 then "" else "s") - (String.concat ", " sl) | No_cmi_file (name, None) -> "no cmi file was found in path for module " ^ name | No_cmi_file (name, Some msg) -> Printf.sprintf "no valid cmi file was found in path for module %s. %s" name msg - | Bad_docstring unattached -> - if unattached then "unattached documentation comment (ignored)" - else "ambiguous documentation comment" | Fragile_literal_pattern -> Printf.sprintf "Code should not depend on the actual values of\n\ @@ -495,15 +416,8 @@ let message = function "Polymorphic comparison introduced (maybe unsafe)" | Bs_ffi_warning s -> "FFI warning: " ^ s | Bs_derive_warning s -> "@deriving warning: " ^ s - | Bs_fragile_external s -> - s - ^ " : using an empty string as a shorthand to infer the external's name \ - from the value's name is dangerous when refactoring, and therefore \ - deprecated" - | Bs_unimplemented_primitive s -> "Unimplemented primitive used: " ^ s | Bs_integer_literal_overflow -> "Integer literal exceeds the range of representable integers of type int" - | Bs_uninterpreted_delimiters s -> "Uninterpreted delimiters " ^ s | Bs_toplevel_expression_unit help -> Printf.sprintf "This%sis at the top level and is expected to return `unit`. But it's \ @@ -581,8 +495,6 @@ let check_fatal () = let descriptions = [ - (1, "Suspicious-looking start-of-comment mark."); - (2, "Suspicious-looking end-of-comment mark."); (3, "Deprecated feature."); ( 4, "Fragile pattern matching: matching that will remain complete even\n\ @@ -591,18 +503,10 @@ let descriptions = ( 5, "Partially applied function: expression whose result has function\n\ \ type and is ignored." ); - (7, "Method overridden."); (8, "Partial match: missing cases in pattern-matching."); (9, "Missing fields in a record pattern."); - ( 10, - "Expression on the left-hand side of a sequence that doesn't have type\n\ - \ \"unit\" (and that is not a function, see warning number 5)." ); (11, "Redundant case in a pattern matching (unused match case)."); (12, "Redundant sub-pattern in a pattern-matching."); - (13, "Instance variable overridden."); - (14, "Illegal backslash escape in a string constant."); - (15, "Private method made public implicitly."); - (16, "Unerasable optional argument."); (17, "Undeclared virtual method."); (18, "Non-principal type."); (19, "Type without principality."); @@ -623,7 +527,6 @@ let descriptions = \ \"let\" nor \"as\", and doesn't start with an underscore (\"_\")\n\ \ character." ); (28, "Wildcard pattern given as argument to a constant constructor."); - (29, "Unescaped end-of-line in a string constant (non-portable code)."); ( 30, "Two labels or constructors of the same name are defined in two\n\ \ mutually recursive types." ); @@ -642,9 +545,7 @@ let descriptions = (45, "Open statement shadows an already defined label or constructor."); (46, "Error in environment variable."); (47, "Illegal attribute payload."); - (48, "Implicit elimination of optional arguments."); (49, "Absent cmi file when looking up module alias."); - (50, "Unexpected documentation comment."); (52, "Fragile constant pattern."); (53, "Attribute cannot appear in this context"); (54, "Attribute used more than once on an expression"); @@ -658,14 +559,9 @@ let descriptions = (102, "Polymorphic comparison introduced (maybe unsafe)"); (103, "Fragile FFI definitions"); (104, "@deriving warning with customized message "); - ( 105, - "External name is inferred from val name is unsafe from refactoring when \ - changing value name" ); - (106, "Unimplemented primitive used:"); ( 107, "Integer literal exceeds the range of representable integers of type int" ); - (108, "Uninterpreted delimiters (for unicode)"); (109, "Toplevel expression has unit type"); (110, "Todo found"); ] diff --git a/compiler/ext/warnings.mli b/compiler/ext/warnings.mli index ba1a03ceec..5ebdfa4b24 100644 --- a/compiler/ext/warnings.mli +++ b/compiler/ext/warnings.mli @@ -22,21 +22,13 @@ type loc = { type top_level_unit_help = FunctionCall | Other type t = - | Comment_start (* 1 *) - | Comment_not_end (* 2 *) | Deprecated of string * loc * loc * bool (* 3 *) | Fragile_match of string (* 4 *) | Partial_application (* 5 *) - | Method_override of string list (* 7 *) | Partial_match of string (* 8 *) | Non_closed_record_pattern of string (* 9 *) - | Statement_type (* 10 *) | Unused_match (* 11 *) | Unused_pat (* 12 *) - | Instance_variable_override of string list (* 13 *) - | Illegal_backslash (* 14 *) - | Implicit_public_methods of string list (* 15 *) - | Unerasable_optional_argument (* 16 *) | Unused_argument (* 20 *) | Nonreturning_statement (* 21 *) | Preprocessor of string (* 22 *) @@ -46,7 +38,6 @@ type t = | Unused_var of string (* 26 *) | Unused_var_strict of string (* 27 *) | Wildcard_arg_to_constant_constr (* 28 *) - | Eol_in_string (* 29 *) | Duplicate_definitions of string * string * string * string (* 30 *) | Unused_value_declaration of string (* 32 *) | Unused_open of string (* 33 *) @@ -60,9 +51,7 @@ type t = | Open_shadow_identifier of string * string (* 44 *) | Open_shadow_label_constructor of string * string (* 45 *) | Attribute_payload of string * string (* 47 *) - | Eliminated_optional_arguments of string list (* 48 *) | No_cmi_file of string * string option (* 49 *) - | Bad_docstring of bool (* 50 *) | Fragile_literal_pattern (* 52 *) | Misplaced_attribute of string (* 53 *) | Duplicated_attribute of string (* 54 *) @@ -74,10 +63,7 @@ type t = | Bs_polymorphic_comparison (* 102 *) | Bs_ffi_warning of string (* 103 *) | Bs_derive_warning of string (* 104 *) - | Bs_fragile_external of string (* 105 *) - | Bs_unimplemented_primitive of string (* 106 *) | Bs_integer_literal_overflow (* 107 *) - | Bs_uninterpreted_delimiters of string (* 108 *) | Bs_toplevel_expression_unit of (string * top_level_unit_help) option (* 109 *) | Bs_todo of string option (* 110 *) diff --git a/compiler/frontend/ast_utf8_string_interp.ml b/compiler/frontend/ast_utf8_string_interp.ml index 90c5043256..e3e65018a7 100644 --- a/compiler/frontend/ast_utf8_string_interp.ml +++ b/compiler/frontend/ast_utf8_string_interp.ml @@ -289,7 +289,6 @@ module Delim = struct let escaped_j_delimiter = "*j" (* not user level syntax allowed *) let escaped_back_quote_delimiter = "bq" let some_escaped_back_quote_delimiter = Some "bq" - let unescaped_js_delimiter = "js" let some_escaped_j_delimiter = Some escaped_j_delimiter end @@ -339,6 +338,4 @@ let is_unicode_string opt = Ext_string.equal opt Delim.escaped_j_delimiter || Ext_string.equal opt Delim.escaped_back_quote_delimiter -let is_unescaped s = Ext_string.equal s Delim.unescaped_js_delimiter - let parse_processed_delim = Delim.parse_processed diff --git a/compiler/frontend/ast_utf8_string_interp.mli b/compiler/frontend/ast_utf8_string_interp.mli index 5e8ec9c8a9..bc0b13c93e 100644 --- a/compiler/frontend/ast_utf8_string_interp.mli +++ b/compiler/frontend/ast_utf8_string_interp.mli @@ -59,5 +59,4 @@ val transform_exp : Parsetree.expression -> string -> string -> Parsetree.expression val transform_pat : Parsetree.pattern -> string -> string -> Parsetree.pattern val is_unicode_string : string -> bool -val is_unescaped : string -> bool val parse_processed_delim : string option -> External_arg_spec.delim option diff --git a/compiler/frontend/bs_ast_invariant.ml b/compiler/frontend/bs_ast_invariant.ml index 60e1ad285d..023043f9f4 100644 --- a/compiler/frontend/bs_ast_invariant.ml +++ b/compiler/frontend/bs_ast_invariant.ml @@ -52,9 +52,6 @@ let super = Ast_iterator.default_iterator let check_constant loc (const : Parsetree.constant) = match const with - | Pconst_string (_, Some s) -> - if Ast_utf8_string_interp.is_unescaped s then - Bs_warnings.error_unescaped_delimiter loc s | Pconst_integer (s, None) -> ( (* range check using int32 It is better to give a warning instead of error to avoid make people unhappy. diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 8e6da258c6..182a43e863 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -1986,19 +1986,6 @@ let rec type_approx env sexp = ty2 | _ -> newvar () -(* List labels in a function type, and whether return type is a variable *) -let rec list_labels_aux env visited ls ty_fun = - let ty = expand_head env ty_fun in - if List.memq ty visited then (List.rev ls, false) - else - match ty.desc with - | Tarrow (arg, ty_res, _, arity) when arity = None || visited = [] -> - list_labels_aux env (ty :: visited) (arg.lbl :: ls) ty_res - | _ -> (List.rev ls, is_Tvar ty) - -let list_labels env ty = - wrap_trace_gadt_instances env (list_labels_aux env [] []) ty - (* Check that all univars are safe in a type *) let check_univars env expans kind exp ty_expected vars = if expans && not (is_nonexpansive exp) then @@ -2028,13 +2015,12 @@ let check_univars env expans kind exp ty_expected vars = Less_general (kind, [(ty, ty); (ty_expected, ty_expected)]) )) (* Check that a type is not a function *) -let check_application_result env statement exp = - let loc = exp.exp_loc in +let check_application_result env exp = match (expand_head env exp.exp_type).desc with | Tarrow _ -> Location.prerr_warning exp.exp_loc Warnings.Partial_application | Tvar _ -> () | Tconstr (p, _, _) when Path.same p Predef.path_unit -> () - | _ -> if statement then Location.prerr_warning loc Warnings.Statement_type + | _ -> () (* Check that a type is generalizable at some level *) let generalizable level ty = @@ -2271,10 +2257,6 @@ let rec lower_args env seen ty_fun = lower_args env (ty :: seen) ty_fun | _ -> () -let not_function env ty = - let ls, tvar = list_labels env ty in - ls = [] && not tvar - let extract_function_name funct = match funct.exp_desc with | Texp_ident (path, _, _) -> Some (Longident.parse (Path.name path)) @@ -3460,12 +3442,6 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l caselist = - let state = Warnings.backup () in - (* Disable Unerasable_optional_argument for uncurried functions *) - let unerasable_optional_argument = - Warnings.number Unerasable_optional_argument - in - Warnings.parse_options false ("-" ^ string_of_int unerasable_optional_argument); let ty_expected = match arity with | None -> ty_expected_ @@ -3506,15 +3482,11 @@ and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l ty_arg ty_res true loc caselist) in let case = List.hd cases in - if is_optional l && not_function env ty_res then - Location.prerr_warning case.c_lhs.pat_loc - Warnings.Unerasable_optional_argument; let param = name_pattern "param" cases in let exp_type = instance env (newgenty (Tarrow ({lbl = l; typ = ty_arg}, ty_res, Cok, arity))) in - Warnings.restore state; re { exp_desc = @@ -3959,7 +3931,7 @@ and type_application ~context total_app env funct (sargs : sargs) : Location.prerr_warning exp.exp_loc Warnings.Partial_application | Tvar _ -> Delayed_checks.add_delayed_check (fun () -> - check_application_result env false exp) + check_application_result env exp) | _ -> ()); ([(Nolabel, Some exp)], ty_res, false) | _ -> From 577c7b422357aabd8f9c848c5430886022b3f542 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:31:11 +0000 Subject: [PATCH 12/16] Format dead error cleanup Run the repository formatter after removing the unreachable diagnostics. This keeps the edited compiler modules passing make checkformat without changing behavior. --- compiler/ml/ctype.ml | 4 ++-- compiler/ml/typecore.ml | 44 ++++++++++++++++++++--------------------- compiler/ml/typedecl.ml | 9 ++++----- compiler/ml/typemod.ml | 13 ++++++------ compiler/ml/typetexp.ml | 3 ++- 5 files changed, 37 insertions(+), 36 deletions(-) diff --git a/compiler/ml/ctype.ml b/compiler/ml/ctype.ml index 1291da7880..6eba569eda 100644 --- a/compiler/ml/ctype.ml +++ b/compiler/ml/ctype.ml @@ -2709,8 +2709,8 @@ and unify_row_field env fixed1 fixed2 more l f1 f2 = let unify env ty1 ty2 = let snap = Btype.snapshot () in - try unify env ty1 ty2 with - | Unify trace -> + try unify env ty1 ty2 + with Unify trace -> undo_compress snap; raise (Unify (expand_trace !env trace)) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index 182a43e863..a3774ffed2 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -330,13 +330,14 @@ let check_optional_attr env ld optional loc = (* unification inside type_pat*) let unify_pat_types loc env ty ty' = - try unify env ty ty' with - | Unify trace -> raise (Error (loc, env, Pattern_type_clash trace)) + try unify env ty ty' + with Unify trace -> raise (Error (loc, env, Pattern_type_clash trace)) (* unification inside type_exp and type_expect *) let unify_exp_types ~context loc env ty expected_ty = - try unify env ty expected_ty with - | Unify trace -> raise (Error (loc, env, Expr_type_clash {trace; context})) + try unify env ty expected_ty + with Unify trace -> + raise (Error (loc, env, Expr_type_clash {trace; context})) (* level at which to create the local type declarations *) let newtype_level = ref None @@ -351,8 +352,8 @@ let unify_pat_types_gadt loc env ty ty' = | None -> assert false | Some x -> x in - try unify_gadt ~newtype_level env ty ty' with - | Unify trace -> raise (Error (loc, !env, Pattern_type_clash trace)) + try unify_gadt ~newtype_level env ty ty' + with Unify trace -> raise (Error (loc, !env, Pattern_type_clash trace)) (* Creating new conjunctive types is not allowed when typing patterns *) @@ -3461,9 +3462,9 @@ and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l if separate then begin_def (); let ty_arg, ty_res = try filter_arrow ~env ~arity (instance env ty_expected) l - with Unify _ -> ( + with Unify _ -> raise - (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun)))) + (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun))) in let ty_arg = if is_optional l then ( @@ -4458,20 +4459,19 @@ let type_expression ~context env sexp = Typetexp.reset_type_variables (); begin_def (); let exp = type_exp ~context env sexp in - (if Warnings.is_active (Bs_toplevel_expression_unit None) then - try unify env exp.exp_type (instance_def Predef.type_unit) with - | Unify _ -> - let buffer = Buffer.create 10 in - let formatter = Format.formatter_of_buffer buffer in - Printtyp.type_expr formatter exp.exp_type; - Format.pp_print_flush formatter (); - let return_type = Buffer.contents buffer in - Location.prerr_warning sexp.pexp_loc - (Bs_toplevel_expression_unit - (match sexp.pexp_desc with - | Pexp_apply _ -> Some (return_type, FunctionCall) - | _ -> Some (return_type, Other))) - ); + if Warnings.is_active (Bs_toplevel_expression_unit None) then ( + try unify env exp.exp_type (instance_def Predef.type_unit) + with Unify _ -> + let buffer = Buffer.create 10 in + let formatter = Format.formatter_of_buffer buffer in + Printtyp.type_expr formatter exp.exp_type; + Format.pp_print_flush formatter (); + let return_type = Buffer.contents buffer in + Location.prerr_warning sexp.pexp_loc + (Bs_toplevel_expression_unit + (match sexp.pexp_desc with + | Pexp_apply _ -> Some (return_type, FunctionCall) + | _ -> Some (return_type, Other)))); end_def (); if not (is_nonexpansive exp) then generalize_expansive env exp.exp_type; generalize exp.exp_type; diff --git a/compiler/ml/typedecl.ml b/compiler/ml/typedecl.ml index 39eef5fed4..4e0f6d31ca 100644 --- a/compiler/ml/typedecl.ml +++ b/compiler/ml/typedecl.ml @@ -183,8 +183,7 @@ let set_fixed_row env loc p decl = if Btype.static_row row then Btype.newgenty Tnil else row.row_more | Tobject (ty, _) -> snd (Ctype.flatten_fields ty) | _ -> - Location.raise_errorf ~loc - "This fixed type is not an object or variant" + Location.raise_errorf ~loc "This fixed type is not an object or variant" in if not (Btype.is_Tvar rv) then Location.raise_errorf ~loc "This fixed type has no row variable"; @@ -979,9 +978,9 @@ let check_recursion env loc path decl to_check = | Tconstr (path', args', _) -> (if Path.same path path' then ( if not (Ctype.equal env false args args') then - Location.raise_errorf ~loc - "In the definition of %s, recursive type parameters differ." - (Path.name cpath)) + Location.raise_errorf ~loc + "In the definition of %s, recursive type parameters differ." + (Path.name cpath)) else if (* Attempt to expand a type abbreviation if: 1- [to_check path'] holds diff --git a/compiler/ml/typemod.ml b/compiler/ml/typemod.ml index 7fec8d74db..48cfba0b62 100644 --- a/compiler/ml/typemod.ml +++ b/compiler/ml/typemod.ml @@ -247,10 +247,11 @@ let check_usage_of_path_of_substituted_item paths env signature ~loc ~lid = try retype_applicative_functor_type ~loc env funct arg with Includemod.Error explanation -> Location.raise_errorf ~loc - "@[@[This `with' constraint on %a makes the \ - applicative functor type %s ill-typed in the constrained \ + "@[@[This `with' constraint on %a makes the applicative \ + functor type %s ill-typed in the constrained \ signature:@]@ %a@]" - Printtyp.longident lid.txt (Path.name referenced_path) + Printtyp.longident lid.txt + (Path.name referenced_path) Includemod.report_error explanation)); } in @@ -437,7 +438,8 @@ let merge_constraint initial_env loc sg constr = Location.raise_errorf ~loc "@[Destructive substitutions are not supported for \ constrained types (other than when replacing a type \ - constructor with a type constructor with the same arguments).@]"; + constructor with a type constructor with the same \ + arguments).@]"; fun s path -> Subst.add_type_function path ~params ~body s in let sub = List.fold_left how_to_extend_subst Subst.identity !real_ids in @@ -1331,8 +1333,7 @@ and type_module_aux ~alias sttn funct_body anchor env smod = "@[This functor has type@ %a@ The parameter cannot be \ eliminated in the result type.@ Bind the argument to a \ module identifier.@]" - Printtyp.modtype mty_functor - ) + Printtyp.modtype mty_functor) in rm { diff --git a/compiler/ml/typetexp.ml b/compiler/ml/typetexp.ml index 12e1a36edf..c958eb4b1d 100644 --- a/compiler/ml/typetexp.ml +++ b/compiler/ml/typetexp.ml @@ -618,7 +618,8 @@ and transl_fields env policy o fields = OTinherit cty | {desc = Tvar _}, Some p -> Location.raise_errorf ~loc:sty.ptyp_loc - "The type constructor %a is not yet completely defined" Printtyp.path p + "The type constructor %a is not yet completely defined" Printtyp.path + p | _ -> raise (Error (sty.ptyp_loc, env, Not_an_object t))) in let object_fields = List.map add_field fields in From fb6e857809c43df2d4de4a2d37d9151555c4d560 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:31:26 +0000 Subject: [PATCH 13/16] Update error variant removal audit Record the diagnostics removed on jono/remove-dead-errors and remove their table rows. Reclassify the audited items that are not completely dead, including stale-CMI module-type paths, the live Syntaxerr printer gap, and UTF-8 helper errors retained for defensive/test entry points. --- tests/ERROR_VARIANTS.md | 255 ++++++++++++---------------------------- 1 file changed, 72 insertions(+), 183 deletions(-) diff --git a/tests/ERROR_VARIANTS.md b/tests/ERROR_VARIANTS.md index 6f45ebbbf4..d9f8a00ac2 100644 --- a/tests/ERROR_VARIANTS.md +++ b/tests/ERROR_VARIANTS.md @@ -11,8 +11,7 @@ The catalog has two practical uses: AST shape. 2. **Dead-code removal** — rows tagged `⚠` are variants whose trigger site is unreachable in the current parser / compiler, with a named - blocker. They can be deleted in a follow-up PR. The "Confirmed dead" - summary at the bottom groups them by reason. + blocker. They can be deleted in a follow-up PR. ## Status legend @@ -23,7 +22,8 @@ The catalog has two practical uses: | ☐ | Reachable but no fixture yet; would be valuable to add. | | ? | Trigger site is live but reachability from regular ReScript source isn't confirmed. Distinct from ⚠: a `?` means "I couldn't find a fixture that reaches it" rather than "the path is provably blocked". | -The "Confirmed dead" summary section at the bottom only includes ⚠. +The removal audit section below records variants that have already been +deleted or retained after re-validation. ## Scope @@ -55,6 +55,41 @@ If a variant turns out to be unreachable, document the named blocker here (so it gets ⚠ instead of `?`) and file a follow-up to delete the dead code. +## Removed in `jono/remove-dead-errors` + +The following named error and warning variants were re-validated as +unreachable and removed. Guard sites that could still be reached by +malformed PPX-produced ASTs now use direct `Location.raise_errorf` +fallbacks instead of catalogued variants. + +- `typecore`: `Label_mismatch`, `Abstract_wrong_label`, + `Incoherent_label_order`, `Recursive_local_constraint`, + `Invalid_interval`, `Invalid_for_of_pattern` +- `typedecl`: `Type_clash`, `Parameters_differ`, + `Null_arity_external`, `Rebind_wrong_type`, `Bad_fixed_type`, + `Varying_anonymous`, `Val_in_structure` +- `typemod`: `Cannot_eliminate_dependency`, + `With_makes_applicative_functor_ill_typed`, + `With_cannot_remove_constrained_type`, `Scoping_pack` +- `typetexp`: `Unbound_type_constructor_2`, `Variant_tags`, + `Ill_typed_functor_application`, `Apply_structure_as_functor` +- `bs_syntaxerr`: `Conflict_bs_bs_this_bs_meth`, + `Unhandled_poly_type`, `Misplaced_label_syntax` +- `env`: `Illegal_value_name` +- `warnings`: `Comment_start`, `Comment_not_end`, `Method_override`, + `Statement_type`, `Instance_variable_override`, `Illegal_backslash`, + `Implicit_public_methods`, `Unerasable_optional_argument`, + `Eol_in_string`, `Eliminated_optional_arguments`, `Bad_docstring`, + `Bs_fragile_external`, `Bs_unimplemented_primitive`, + `Bs_uninterpreted_delimiters` + +Re-validation also found a few previously-flagged items that are not +completely dead: `includemod.Unbound_modtype_path` can still represent a +stale compiled-interface failure, `Syntaxerr.Variable_in_scope` is live +but lacks a registered printer, and the UTF-8 helper error families are +still raised by test/defensive helper entry points. Those are retained +below with updated notes. + --- ## `compiler/ml/typecore.ml` @@ -66,7 +101,6 @@ Source: [typecore.ml:27](../compiler/ml/typecore.ml). |---|---|---|---| | `Polymorphic_label` | ✓ | `polymorphic_label.res` | Pattern that instantiates a polymorphic record field: `({f: (f: int => int)}: t) =>` constrains the universal `'a` of `f: 'a. 'a => 'a` to `int => int`. | | `Constructor_arity_mismatch` | ✓ | `constructor_arity_mismatch.res`, `constructor_arity_mismatch_pattern.res`, `arity_mismatch*.res` | Triggers in both expression (4028) and pattern (1426) paths. | -| `Label_mismatch` | ⚠ | — | typecore.ml:1543/3589. Defensive `try unify ty_res ty_expected with Unify -> Label_mismatch`. The only way to reach the unify is after label disambiguation (`type_label_a_list` / `type_label_pat` / `Wrong_name`-style logic), which always locks `ty_res` to a record type already unifiable with the expected. The unify therefore can't fail in practice — every reproduction hits `Wrong_name`, `Pattern_type_clash`, or `Expr_type_clash` instead. The constructor is a defensive leftover from the OCaml inheritance. | | `Pattern_type_clash` | ✓ | many `*_pattern_type_clash.res` etc. | Most-fired pattern error. Sub-case fixtures: `pattern_matching_on_option_but_value_not_option.res` and `pattern_matching_on_value_but_is_option.res` (option-vs-non-option trace), `pattern_type_clash_polyvariant.res` (polyvariant tag against concrete type), `pattern_type_clash_tuple_arity.res` (tuple arity mismatch). | | `Or_pattern_type_clash` | ✓ | `or_pattern_type_clash.res` | | | `Multiply_bound_variable` | ✓ | `multiply_bound_variable.res` | | @@ -84,20 +118,15 @@ Source: [typecore.ml:27](../compiler/ml/typecore.ml). | `Private_label` | ✓ | `private_label.res` | | | `Not_subtype` | ✓ | `subtype_*.res`, `dict_show_no_coercion.res`, etc. | | | `Too_many_arguments` | ✓ | `too_many_arguments.res`, `moreArguments*.res` | | -| `Abstract_wrong_label` | ⚠ | — | typecore.ml:3502. Fires in `type_function` when `filter_arrow` with the literal's label fails *and* the expected type is `Tarrow`. In modern ReScript the function literal's type is fully inferred from its own args first, then unified — that path emits `Expr_type_clash`, not `Abstract_wrong_label`. Several attempted reproductions all surfaced as `Expr_type_clash`. Treating as effectively dead. | | `Scoping_let_module` | ✓ | `scoping_let_module.res` | | | `Not_a_variant_type` | ✓ | `variant_spread_pattern_not_a_variant.res` | Pattern-level variant spread of a non-variant type. | -| `Incoherent_label_order` | ⚠ | — | typecore.ml:3894. Reached only after `arity_ok` is true *and* the label is present in `ty_fun` but not at the current arrow position. ReScript's labeled-argument reordering happens earlier in `type_args` / `type_unknown_args`, so by the time we hit this branch the label is already at the right position. Every attempted reproduction landed on `Apply_wrong_label` or `Expr_type_clash`. | | `Less_general` | ✓ | `less_general_universal.res` | | | `Modules_not_allowed` | ✓ | `super_errors_multi/Modules_not_allowed_toplevel` | Toplevel `let module(M) = …` pattern with `allow_modules=false`. | | `Cannot_infer_signature` | ✓ | `cannot_infer_signature.res` | | | `Not_a_packed_module` | ✓ | `not_a_packed_module.res` | | -| `Recursive_local_constraint` | ⚠ | — | typecore.ml:369. Routed via `Unification_recursive_abbrev` in `ctype.ml`, which is raised only when `ctype.ml`'s `Recursive_abbrev` exception fires. **`Recursive_abbrev` is defined (ctype.ml:110, ctype.mli:61) but never raised anywhere in `compiler/`.** Confirmed dead. | | `Unexpected_existential` | ✓ | `super_errors_multi/Unexpected_existential_in_let` | Destructuring GADT constructor with existential in toplevel `let`. | | `Unqualified_gadt_pattern` | ✓ | `super_errors_multi/Cross_gadt_pattern` | Only reachable via cross-module GADT disambiguation; in single-file matching the constructor would resolve before this check. | -| `Invalid_interval` | ⚠ | — | typecore.ml:1349. Triggered by `Ppat_interval` pattern. **Verified: `Ppat_interval` has no construction site in `compiler/syntax/src/res_core.ml`** — only printer and ast_debugger handle it. | | `Invalid_for_loop_index` | ✓ | `invalid_for_loop_index.res` | | -| `Invalid_for_of_pattern` | ⚠ | — | typecore.ml:3120/3152. Verified: parser `normalize_for_of_pattern` (`res_core.ml:3841`) replaces non-var / non-`_` patterns with `Ppat_any` before the typer sees them. | | `No_value_clauses` | ✓ | `no_value_clauses.res` | | | `Exception_pattern_below_toplevel` | ✓ | `exception_pattern_below_toplevel.res` | | | `Inlined_record_escape` | ✓ | `inline_record_escape.res` | | @@ -133,22 +162,15 @@ Type-declaration errors. Source: [typedecl.ml:27](../compiler/ml/typedecl.ml). | `Definition_mismatch` | ✓ | `definition_mismatch.res` | | | `Constraint_failed` | ✓ | `constraint_failed.res` | | | `Inconsistent_constraint` | ✓ | `inconsistent_constraint.res` | | -| `Type_clash` | ⚠ | — | typedecl.ml:125. Fires when `Ctype.unify env (newconstr path params) manifest` fails inside `update_type` for a `type rec` block. For ReScript types this unify either trivially succeeds (aliases unify with their manifest because the cycle/arity machinery has already accepted the shape) or the declaration is rejected earlier by `Cycle_in_def` / `Recursive_abbrev`. I couldn't construct a recursive shape that reaches the failing unify without being caught first. | -| `Parameters_differ` | ⚠ | — | typedecl.ml:988. Fires for non-uniform recursive type *abbreviations* (`type rec t<'a> = … t …`). ReScript treats variant types as having a manifest of None, so `check_regular` is a no-op for them. For abbreviations, `Cycle_in_def` fires first because the recursive reference is direct. I couldn't construct an abbreviation shape that hits Parameters_differ without being cyclic. | -| `Null_arity_external` | ⚠ | — | typedecl.ml:1900. The guard requires `prim_arity = 0` and `prim_native_name` not having the magic 20-byte encoding (`\132\149...`) and `prim_name` not starting with `%` or `#`. The encoding gets applied to every concrete external by `Primitive.parse_declaration`, and empty `prim_name` is rejected earlier by `external_ffi_types.ml` with "Not a valid global name". No path through the parser reaches it. | | `Unbound_type_var` | ✓ | `unbound_type_var.res` | | | `Cannot_extend_private_type` | ✓ | `cannot_extend_private_type.res` | | | `Not_extensible_type` | ✓ | `not_extensible_type.res` | | | `Extension_mismatch` | ✓ | `extension_arity_mismatch.res` | `type t<'a> = ..` extended with `type t += A(int)` — arity differs from the extensible type. | -| `Rebind_wrong_type` | ⚠ | — | typedecl.ml:1653. The unify is `cstr_res` (source constructor's result, freshly instantiated) against `res` (extension's target type with fresh param vars). For non-GADT sources both sides are `t` and trivially unify; for GADT-style sources (`type t<'a> += A: t`) `cstr_res = t` against `res = t` still unifies (`v1 := int`). The parser doesn't allow rebinding with explicit args (`exception B(string) = A` is rejected at `res_core.ml:6660`), so the result-type relationship is always compatible by construction. | | `Rebind_mismatch` | ✓ | `extension_rebind_mismatch.res` | Rebinding constructor into a different extensible type. | | `Rebind_private` | ✓ | `extension_rebind_private.res` | Rebinding a private extension constructor as public. | | `Bad_variance` | ✓ | `bad_variance.res`, `bad_variance_contra.res` | | | `Unavailable_type_constructor` | ☐ (needs build harness) | — | typedecl.ml:778. Requires a type path findable at parse time but missing during constraint enforcement; only cross-unit scenarios where a `.cmi` was found but later removed. | -| `Bad_fixed_type` | ⚠ | — | typedecl.ml:190/193. `set_fixed_row` runs only when `is_fixed_type` returns true, which requires a `private` abstract type with a syntactically open object / polyvariant manifest (typedecl.ml:160-174). For a manifest written that way, `expand_head` returns exactly the same `Tobject` / `Tvariant`, so the check at line 190 passes and the row variable check at line 193 also passes (rows from those syntactic forms have a Tvar `row_more`). No alias chain in ReScript syntax can collapse the open row while still passing `has_row_var` on the syntactic side. | | `Unbound_type_var_ext` | ✓ | `unbound_type_var_extension.res` | | -| `Varying_anonymous` | ⚠ | — | typedecl.ml:1263. Fires in variance computation when an anonymous (`_`) type parameter is constrained against other params under specific variance requirements. ReScript's parser doesn't produce `_` in type parameter position for `type` declarations (`type t<_>` is rejected) — only explicit `'x`-style params, which are never "anonymous" in the sense `Varying_anonymous` checks. | -| `Val_in_structure` | ⚠ | — | typedecl.ml:1887 requires `pval_prim = []` outside a signature. The parser's `external` recovery sets `prim = []` (`res_core.ml:6617`) but only after emitting a `Syntax error`, so the typechecker never reaches the value declaration. From plain source there's no path that produces a non-signature `Val` with empty `pval_prim` — only PPX-rewritten AST could, and the AST shape would have to bypass the parser. | | `Invalid_attribute` | ✓ | `invalid_attribute_not_undefined.res` | | | `Bad_immediate_attribute` | ✓ | `bad_immediate_attribute.res` | | | `Bad_unboxed_attribute` | ✓ | `bad_unboxed_attribute_abstract.res`, `bad_unboxed_attribute_mutable.res`, `bad_unboxed_attribute_many_fields.res`, `bad_unboxed_attribute_extensible.res` | All 4 sub-cases covered. | @@ -167,14 +189,11 @@ Module-level errors. Source: [typemod.ml:24](../compiler/ml/typemod.ml). |---|---|---|---| | `Cannot_apply` | ✓ | `cannot_apply_non_functor.res` | | | `Not_included` | ✓ | All `super_errors_multi/Iface_*` fixtures wrap to this via `compunit`. | | -| `Cannot_eliminate_dependency` | ⚠ | — | typemod.ml:1335. Reached only when `Mtype.nondep_supertype` raises `Not_found` for an anonymous functor application. ReScript's `nondep_supertype` falls back to existential abstraction for any module-typed binding it can't eliminate cleanly, so the `Not_found` branch never fires. Multiple anonymous functor applications (including ones where the result genuinely references the argument's abstract type) all type-check. | | `Signature_expected` | ✓ | `typemod_signature_expected.res` | `with type M.t = …` where `M` is functor-typed inside the outer signature. | | `Structure_expected` | ✓ | `super_errors_multi/Smoke_unbound_module_reference` (indirect); also `open_functor.res` | | | `With_no_component` | ✓ | `with_no_component.res` | | | `With_mismatch` | ✓ | `with_mismatch.res` | | -| `With_makes_applicative_functor_ill_typed` | ⚠ | — | typemod.ml:258. Reached only through the applicative-functor path of `Btype.it_path` (`Papply`); ReScript's parser doesn't emit `Papply` (no parsed construction site in `res_core.ml`), so the iterator never visits this branch. | | `With_changes_module_alias` | ☐ (needs build harness) | — | typemod.ml:240. Fires during `with module := M2` substitution when an aliased sub-module inside the constrained signature is affected. ReScript parses `with module N := M2` (destructive substitution), but constructing a sub-module alias chain that gets invalidated requires multiple `.resi` files and a specific shape I couldn't reproduce single-file. | -| `With_cannot_remove_constrained_type` | ⚠ | — | typemod.ml:443. Fires for `Twith_typesubst` (the `:=` form) when `params_are_constrained` returns true — i.e. the substitution's params are non-`Tvar`. The parser only accepts `'x`-style identifiers in `with type X<…>` param positions (`res_core.ml` rejects `with type x := …` with "Type params start with a singlequote"), so the params are always fresh `Tvar`s and the check never triggers. | | `Repeated_name` | ✓ | `repeated_def_*.res` (multiple) | | | `Non_generalizable` | ✓ | `non_generalizable.res` | | | `Non_generalizable_module` | ✓ | `non_generalizable_module.res` | Nested module containing `let r = ref(None)` — the outer module's `md_type` carries the free `'_weak1` from the inner ref, so `closed_modtype` returns false and the `Sig_module` branch fires. | @@ -182,7 +201,6 @@ Module-level errors. Source: [typemod.ml:24](../compiler/ml/typemod.ml). | `Not_allowed_in_functor_body` | ✓ | `super_errors_multi/not_allowed_in_functor_body` (TODO: confirm path) | | | `Not_a_packed_module` | ✓ | `not_a_packed_module.res` | | | `Incomplete_packed_module` | ✓ | `incomplete_packed_module.res` | | -| `Scoping_pack` | ⚠ | — | typemod.ml:1717. Requires first-class module pack where a constraint type has a level mismatch; very contrived. | | `Recursive_module_require_explicit_type` | ✓ | `recursive_module_require_explicit_type.res` | | | `Apply_generative` | ✓ | `apply_generative.res` | | | `Cannot_scrape_alias` | ☐ (needs build harness) | — | typemod.ml:77, 83, 1347. Requires `Env.scrape_alias` to return `Mty_alias` for an alias whose target `.cmi` couldn't be loaded. The `super_errors_multi` runner pre-compiles every file in the fixture, so the alias target is always present. | @@ -197,7 +215,6 @@ Type-expression errors. Source: [typetexp.ml:28](../compiler/ml/typetexp.ml). |---|---|---|---| | `Unbound_type_variable` | ✓ | (covered indirectly via many fixtures) | | | `Unbound_type_constructor` | ✓ | `typetexp_unbound_type_constructor.res` | | -| `Unbound_type_constructor_2` | ⚠ | — | typetexp.ml:475/619. Reached in two object/polyvariant-inherit code paths when the inherited type is `Tconstr p` and after `expand_head` is still `Tvar` (the body of `p`'s declaration is a bare type variable). ReScript's parser doesn't accept `type t = 'a` at the top level (only via `with type t<'a> = 'a` which doesn't apply here), so the lookup never returns a Tvar-bodied Tconstr. Every reproduction lands on `Not_an_object` or `Not_a_variant`. | | `Type_arity_mismatch` | ✓ | `type_arity_mismatch.res` | | | `Type_mismatch` | ✓ | `typetexp_type_mismatch.res` | Type-constructor application that violates a `constraint 'a = …` on the declaration. | | `Alias_type_mismatch` | ✓ | `typetexp_alias_type_mismatch.res` | | @@ -205,7 +222,6 @@ Type-expression errors. Source: [typetexp.ml:28](../compiler/ml/typetexp.ml). | `Present_has_no_type` | ✓ | `polyvariant_present_has_no_type.res` | `[< #B > #A]` — `#A` is listed as a "present" tag but isn't defined in the polyvariant body. | | `Constructor_mismatch` | ✓ | `polyvariant_constructor_mismatch.res` | | | `Not_a_variant` | ✓ | `typetexp_not_a_variant.res` | Polyvariant `[#X \| a]` where `a` is not a polyvariant. | -| `Variant_tags` | ⚠ | — | typetexp.ml:39. Raised at typecore.ml:342, 349, 367 via `Tags` exception from `ctype.ml`. **Verified: `exception Tags` is defined (ctype.ml:60) but never raised in `compiler/`.** Confirmed dead. | | `Invalid_variable_name` | ✓ | `invalid_type_variable_name.res` | | | `Cannot_quantify` | ✓ | `cannot_quantify.res` | `type t = {f: 'a. (int as 'a) => int}` — `'a` is universally quantified but the alias `int as 'a` rebinds it to `int`, so the proxy is no longer a fresh `Tvar` when the quantification check runs. | | `Multiple_constraints_on_type` | ✓ | `multiple_constraints_on_type.res` | | @@ -215,10 +231,8 @@ Type-expression errors. Source: [typetexp.ml:28](../compiler/ml/typetexp.ml). | `Unbound_label` | ✓ | `typetexp_unbound_label.res` | | | `Unbound_module` | ✓ | `suggest_module_for_missing_identifier.res`, `super_errors_multi/Smoke_unbound_module_reference` | | | `Unbound_modtype` | ✓ | `typetexp_unbound_modtype.res` | | -| `Ill_typed_functor_application` | ⚠ | — | typetexp.ml:102. In the `Longident.Lapply` branch. **Verified: parser has no construction site for `Longident.Lapply`** (no result in `res_core.ml`). Confirmed dead. | | `Illegal_reference_to_recursive_module` | ✓ | `illegal_recursive_module_reference.res` | `module rec A: B.S = …` references another recmodule's module-type before signatures are sealed. During `approx_modtype` of A, `Env.lookup_module B` returns the `#recmod#` placeholder and raises `Env.Recmodule`. | | `Access_functor_as_structure` | ✓ | `access_functor_as_structure.res` | | -| `Apply_structure_as_functor` | ⚠ | — | typetexp.ml:93. In the `Longident.Lapply` branch. Same dead reason as `Ill_typed_functor_application`. | | `Cannot_scrape_alias` | ☐ (needs build harness) | — | typetexp.ml:86 (Ldot path, live), 95/101 (Lapply path, dead since `Lapply` isn't parsed). The live Ldot trigger needs `Env.scrape_alias` to return `Mty_alias` — an alias whose target `.cmi` couldn't be loaded. The `super_errors_multi` harness pre-compiles every alias target. | | `Opened_object` | ✓ | `object_inherit_opened.res` | | | `Not_an_object` | ✓ | `object_inherit_not_an_object.res` | | @@ -239,7 +253,7 @@ Wrapper symptoms attached to inclusion failures. Source: [includemod.ml:23](../c | `Modtype_infos` | ✓ | `super_errors_multi/Iface_modtype_infos` | | | `Modtype_permutation` | ✓ | `super_errors_multi/include_modtype_permutation` | | | `Interface_mismatch` | ✓ | wrapper added to all `Iface_*` failures (line 476). | | -| `Unbound_modtype_path` | ⚠ | — | includemod.ml:94. Fires inside `modtype_path` comparison when `Env.find_modtype` raises `Not_found`. The only callers run after both signatures have been fully typed, so the module-type path is always findable from the local env — `Not_found` would imply a stale `.cmi`, which the multi-file harness can't produce since it always pre-compiles. Treating as dead from the source-only harnesses' point of view. | +| `Unbound_modtype_path` | ☐ (needs stale-cmi harness) | — | includemod.ml:94. Re-validated during removal: not completely dead. It represents `Env.find_modtype` failing during module-type path comparison, which can happen only with a stale or inconsistent compiled interface. The source-only harness cannot produce that state because it pre-compiles every fixture, so this needs a build/binary-state harness rather than deletion. | | `Unbound_module_path` | ☐ (needs build harness) | — | includemod.ml:226/233. Alias comparison where `Env.normalize_path` raises `Not_found`. Requires a module alias whose target `.cmi` is absent at inclusion time — multi-unit only. | | `Invalid_module_alias` | ☐ (needs build harness) | — | includemod.ml:211. Requires both sides `Mty_alias` with one pointing to a functor argument. Reachable only when the alias chain crosses a functor application that the `super_errors_multi` harness doesn't construct. | @@ -279,13 +293,11 @@ FFI / attribute / experimental-feature errors. Source: [bs_syntaxerr.ml:27](../c | Variant | Status | Fixture | Notes | |---|---|---|---| | `Unsupported_predicates` | ✓ | `bs_unsupported_predicates.res` | `@get({weird: true})` on object type field. | -| `Conflict_bs_bs_this_bs_meth` | ⚠ | — | bs_syntaxerr.ml:29 declares the variant but `Bs_syntaxerr.err _ Conflict_bs_bs_this_bs_meth` is **never raised** anywhere in `compiler/`. | | `Duplicated_bs_deriving` | ✓ | `duplicated_bs_deriving.res` | | | `Conflict_attributes` | ✓ | `bs_conflict_attributes.res` | | | `Expect_int_literal` | ✓ | `bs_expect_int_literal.res` | | | `Expect_string_literal` | ✓ | `bs_expect_string_literal.res` | | | `Expect_int_or_string_or_json_literal` | ✓ | `bs_expect_int_or_string_or_json_literal.res` | `@as(true)` on a wildcard external argument. | -| `Unhandled_poly_type` | ⚠ | — | ast_core_type.ml:141. Reached only when an external's arrow chain contains `Ptyp_poly` inline. The parser's `parse_poly_type_expr` only emits `Ptyp_poly` for record field types and explicit `let f: type t. …` annotations; inside arrow chains, the `'a.` is misread as the deprecated `(. …)` uncurried syntax (`res_core.ml` lexer). Inline polytypes in an external's arrow can only come from PPX-rewritten AST. | | `Invalid_underscore_type_in_external` | ✓ | `bs_invalid_underscore_type_in_external.res` | `@obj external make: (~x: _) => _ = ""` — `_` at an optional-label position without `@as`. | | `Invalid_bs_string_type` | ✓ | `bs_invalid_bs_string_type.res` | | | `Invalid_bs_int_type` | ✓ | `bs_invalid_bs_int_type.res` | | @@ -294,7 +306,6 @@ FFI / attribute / experimental-feature errors. Source: [bs_syntaxerr.ml:27](../c | `Illegal_attribute` | ✓ | `bs_illegal_attribute_scope.res` | | | `Not_supported_directive_in_bs_return` | ✓ | `bs_not_supported_directive_in_bs_return.res` | | | `Expect_opt_in_bs_return_to_opt` | ✓ | `bs_expect_opt_in_bs_return_to_opt.res` | | -| `Misplaced_label_syntax` | ⚠ | — | bs_syntaxerr.ml:116. Only fires from `check_and_discard` in `ast_exp_apply.ml:49`, applied to the args of `->`, `#=`, `##` operators. The parser always emits those args as `Nolabel`. | | `Optional_in_uncurried_bs_attribute` | ✓ | `bs_optional_in_uncurried_bs_attribute.res` | `@this` function with optional argument. | | `Bs_this_simple_pattern` | ✓ | `bs_this_simple_pattern.res` | `@this` with destructured self pattern. | | `Experimental_feature_not_enabled` | ✓ | `let_unwrap_on_top_level_not_enabled.res` (and other let-unwrap variants) | Currently only `LetUnwrap` is checked. | @@ -361,7 +372,6 @@ Environment / `.cmi`-consistency errors. Source: [env.ml:57](../compiler/ml/env. | `Illegal_renaming` | ☐ (needs build harness) | — | Triggered when a `.cmi` filename and the module name inside it disagree. Reachable via `rescript.json` setups that rename the produced artefact, but not from a single-process `bsc` invocation that always writes `Module.cmi` to match the source. | | `Inconsistent_import` | ☐ (needs build harness) | — | Triggered when two `.cmi` files transitively imported by the same unit declare different CRCs for the same type. Needs an artificially-mutated build state across multiple compile invocations. | | `Missing_module` | ☐ (needs build harness) | — | `.cmi` referenced but absent from `-I` paths at compile time. The `super_errors_multi` runner pre-compiles every fixture file via `-bs-read-cmi`, so it never reaches this code path. | -| `Illegal_value_name` | ⚠ | — | env.ml:1622/1625 raises when an identifier is `"->"` or starts/contains `#`. The ReScript parser never emits such identifiers; only PPX-rewritten AST could reach the check. | --- @@ -403,160 +413,55 @@ multi-file harnesses, which never set `-ppx`. | `compiler/ml/translmod.ml` | `Fragile_pattern_in_toplevel` | ✓ | `fragile_pattern_toplevel.res` | | | `compiler/ml/transl_recmodule.ml` | `Circular_dependency` | ✓ | `recmodule_circular_dependency.res` | | | `compiler/ml/rec_check.ml` | `Illegal_letrec_expr` | ✓ | `illegal_letrec_expr.res` | | -| `compiler/ml/syntaxerr.ml` | `Variable_in_scope` | ⚠ | — | Reachable via `let f: type t. (t, 't) => t = …` (locally-abstract `t` collides with type variable `'t` during `varify_constructors`), but `Syntaxerr.error` has no registered pretty-printer, so it propagates as an uncaught `Fatal error: exception Syntaxerr.Error(_)`. The variant is live; the printer is dead. Treat as broken until either the printer is wired up or the variant is removed in favor of a proper diagnostic. | +| `compiler/ml/syntaxerr.ml` | `Variable_in_scope` | ? (live, broken printer) | — | Reachable via `let f: type t. (t, 't) => t = …` (locally-abstract `t` collides with type variable `'t` during `varify_constructors`), but `Syntaxerr.error` has no registered pretty-printer, so it propagates as an uncaught `Fatal error: exception Syntaxerr.Error(_)`. Not removed because the variant is live; the fix should wire up a printer or convert the check into a regular typed diagnostic. | | `compiler/ml/cmt_format.cppo.ml` | `Not_a_typedtree` | ☐ (needs binary harness) | — | cmt_format.cppo.ml:147. Fires when a tool reads a `.cmt` file whose first block isn't a typed tree. Reachable in principle by pointing the analyzer at an arbitrary file with a `.cmt` extension; out of scope for the source-only fixture harnesses. | | `compiler/ext/bsc_args.ml` | `Unknown` | ☐ (needs CLI harness) | — | bsc_args.ml:45. Reachable trivially via `bsc --bogus`, but the `super_errors{,_multi}` runners only pass `bsc` a fixed flag list plus the source file — they can't exercise CLI-level errors. | | `compiler/ext/bsc_args.ml` | `Missing` | ☐ (needs CLI harness) | — | Same as above: `bsc -o` (no following filename). Needs a harness that invokes `bsc` with crafted argv. | --- -## `compiler/frontend/ast_utf8_string.ml` (dead family) +## `compiler/frontend/ast_utf8_string.ml` (retained defensive family) -Source: [ast_utf8_string.ml:25](../compiler/frontend/ast_utf8_string.ml). All variants here are reached only via the legacy `{j|…|j}` delimiter, which the modern ReScript parser doesn't emit. Backtick template strings skip the transform entirely. +Source: [ast_utf8_string.ml:25](../compiler/frontend/ast_utf8_string.ml). Re-validation found these are source-unreachable for regular ReScript, but not completely dead: `transform_test` and the defensive string-transform path still raise them, and the OUnit unicode tests assert their offsets. Retained. | Variant | Status | |---|---| -| `Invalid_code_point` | ⚠ Dead | -| `Unterminated_backslash` | ⚠ Dead | -| `Invalid_hex_escape` | ⚠ Dead | -| `Invalid_unicode_escape` | ⚠ Dead | -| `Invalid_unicode_codepoint_escape` | ⚠ Dead | +| `Invalid_code_point` | ? (source-unreachable, retained defensive/test helper) | +| `Unterminated_backslash` | ? (source-unreachable, retained defensive/test helper) | +| `Invalid_hex_escape` | ? (source-unreachable, retained defensive/test helper) | +| `Invalid_unicode_escape` | ? (source-unreachable, retained defensive/test helper) | +| `Invalid_unicode_codepoint_escape` | ? (source-unreachable, retained defensive/test helper) | -## `compiler/frontend/ast_utf8_string_interp.ml` (dead family) +## `compiler/frontend/ast_utf8_string_interp.ml` (retained test family) Source: [ast_utf8_string_interp.ml:25](../compiler/frontend/ast_utf8_string_interp.ml). -`pos_error` is reached only through `check_and_transform`, whose only -caller in `compiler/` is `transform_test` — used by OUnit tests, not the -production pipeline. Modern ReScript backtick templates take the -`BackQuotes` branch of `transform_exp` (line 311) and skip the -interpolation parser entirely. The legacy `{j|…|j}` delimiter the -parser would otherwise route here is no longer accepted by the -scanner. All variants below are unreachable from regular ReScript -source. +`pos_error` is reached through `transform_test`, which is intentionally +used by OUnit tests. Modern ReScript backtick templates take the +`BackQuotes` branch of `transform_exp` and skip the interpolation parser, +so these are source-unreachable for regular ReScript, but not completely +dead. Retained. | Variant | Status | |---|---| -| `Invalid_code_point` | ⚠ Dead | -| `Unterminated_backslash` | ⚠ Dead | -| `Invalid_escape_code` | ⚠ Dead | -| `Invalid_hex_escape` | ⚠ Dead | -| `Invalid_unicode_escape` | ⚠ Dead | -| `Unterminated_variable` | ⚠ Dead | -| `Unmatched_paren` | ⚠ Dead | -| `Invalid_syntax_of_var` | ⚠ Dead | +| `Invalid_code_point` | ? (source-unreachable, retained test helper) | +| `Unterminated_backslash` | ? (source-unreachable, retained test helper) | +| `Invalid_escape_code` | ? (source-unreachable, retained test helper) | +| `Invalid_hex_escape` | ? (source-unreachable, retained test helper) | +| `Invalid_unicode_escape` | ? (source-unreachable, retained test helper) | +| `Unterminated_variable` | ? (source-unreachable, retained test helper) | +| `Unmatched_paren` | ? (source-unreachable, retained test helper) | +| `Invalid_syntax_of_var` | ? (source-unreachable, retained test helper) | --- -## Confirmed dead variants — candidates for removal - -Only variants with a concrete, source-level reason are listed. Each row -has been re-verified against the source as of this audit. Variants marked -`?` in the tables above are **not** included here — those may turn out to -be live and just hard to reproduce. - -**Verified dead by missing raise / construction site:** - -- `typecore.Variant_tags`, `typetexp.Variant_tags` — relayed via the - `Tags` exception which is declared in `ctype.ml:60` / `ctype.mli:57` - but **never raised** in `compiler/`. -- `typecore.Recursive_local_constraint` — relayed via - `Unification_recursive_abbrev`, raised only from the `Recursive_abbrev` - exception which is declared (`ctype.ml:110`, `ctype.mli:61`) but - **never raised**. -- `typecore.Invalid_interval` — needs `Ppat_interval`; **no construction - site** for that AST node in `compiler/syntax/src/`. -- `typecore.Invalid_for_of_pattern` — parser's - `normalize_for_of_pattern` (`res_core.ml:3841`) replaces every non-var, - non-`_` pattern with `Ppat_any` before the typer runs. -- `bs_syntaxerr.Conflict_bs_bs_this_bs_meth` — variant is declared but - no `Bs_syntaxerr.err _ Conflict_bs_bs_this_bs_meth` call exists in - `compiler/`. - -**Verified dead because parser doesn't produce required AST shape:** - -- `typetexp.Ill_typed_functor_application`, - `typetexp.Apply_structure_as_functor` — in the - `Longident.Lapply` branch; `Lapply` has no construction site in - the parser (`res_core.ml`). -- `bs_syntaxerr.Misplaced_label_syntax` — fires for labeled args to - `->`/`#=`/`##` operators; the parser always emits those with - `Nolabel`. -- `typedecl.Null_arity_external` — primitives parsed by - `Primitive.parse_declaration` always get the magic 20-byte - `prim_native_name` encoding, which bypasses the trigger; empty - `prim_name` is rejected earlier with "Not a valid global name". -- `ast_utf8_string.*` (Invalid_code_point, Unterminated_backslash, - Invalid_hex_escape, Invalid_unicode_escape, - Invalid_unicode_codepoint_escape) — the scanner - (`res_scanner.ml:350-417`) already validates escape sequences and - unicode code points; the transform never sees a string that would - fail its own re-validation. -- `ast_utf8_string_interp.*` (the whole module's error variants) — - `check_and_transform` is only ever called from `transform_test`, which - exists for OUnit tests, not the production pipeline. Modern ReScript - backtick templates take the `BackQuotes` branch of `transform_exp` - and skip the interpolation parser entirely. -- `typedecl.Val_in_structure` — typedecl.ml:1887 requires `pval_prim - = []` outside a signature; the parser's `external` recovery sets - `prim = []` only after emitting a syntax error, so the typechecker - never reaches the value declaration. -- `env.Illegal_value_name` — env.ml:1622/1625 rejects `"->"` and - identifiers containing `#`. The parser never produces such names; - PPX-rewritten AST is the only path that could trigger it. -- `bs_warnings.Statement_type` (warning 10) — only caller of - `check_application_result` passes `statement = false`, so the - `if statement then …` branch never fires. -- `bs_warnings.Unerasable_optional_argument` (warning 16) — - `type_function` (typecore.ml:3479) explicitly disables this warning - via `Warnings.parse_options false "-16"` before the check runs. -- `bs_warnings.Bs_uninterpreted_delimiters` (warning 108) — raised at - `bs_warnings.ml:29` for `Pconst_string` with delimiter `"js"`, but - the modern scanner has no `{js|…|js}` form and template strings tag - with `"bq"` after rewriting. - -**`Syntaxerr.Variable_in_scope` is a special case** — reachable from -`let f: type t. (t, 't) => t = …` but raised without a registered -printer, so it surfaces as `Fatal error: exception Syntaxerr.Error(_)`. -The variant is live; the diagnostic path is broken. Fix should either -wire up a printer or convert the check into a regular typed error. - -**Newly verified dead** (the variants the second-pass audit promoted -from `?` to ⚠, with the reason in the table): - -- `typecore.Label_mismatch`, `Abstract_wrong_label`, - `Incoherent_label_order` — defensive `try unify with Unify ->` paths - that are subsumed by `Wrong_name` / `Expr_type_clash` / - `Apply_wrong_label` in modern ReScript. -- `typedecl.Type_clash` — every recursive `type` shape that would reach - the failing `unify` is rejected earlier by `Cycle_in_def` / - `Recursive_abbrev`. -- `typedecl.Parameters_differ` — `check_regular` runs only on - abbreviations, and ReScript's parser produces `Cycle_in_def` for - every recursive abbreviation shape before this check. -- `typedecl.Rebind_wrong_type` — the parser refuses extension rebind - syntax that carries args or a result type, so source and target's - result types always unify trivially. -- `typedecl.Bad_fixed_type` — `is_fixed_type` checks the syntactic - manifest for an open row, and `expand_head` preserves that row; - there's no ReScript syntax that satisfies one check and fails the - other. -- `typedecl.Varying_anonymous` — needs `_` in a `type` parameter - position, which the parser doesn't accept. -- `typetexp.Unbound_type_constructor_2` — needs an inherited type - whose `Tconstr` body is a bare `Tvar`; the parser rejects - `type t = 'a` at top-level. -- `typemod.Cannot_eliminate_dependency` — `Mtype.nondep_supertype` - falls back to existential abstraction in every reachable case; - the `Not_found` branch never fires. -- `typemod.With_cannot_remove_constrained_type` — the parser only - accepts `'x`-style identifiers in `with type` param positions, so - the params are always fresh `Tvar`s and `params_are_constrained` - returns false. -- `bs_syntaxerr.Unhandled_poly_type` — the only way an external's - arrow chain gets an inline `Ptyp_poly` is via PPX-rewritten AST; - the parser misreads `'a.` inline as the deprecated `(. …)` - uncurried syntax. +## Removal audit notes + +All variants that were confirmed completely dead in this pass are listed +in **Removed in `jono/remove-dead-errors`** above and no longer appear in +the module tables. Previously flagged entries that were only unreachable +from regular source, but still possible through stale build artifacts, +PPX/malformed ASTs, or test helper APIs, were retained and reclassified. --- @@ -572,27 +477,11 @@ warnings still fire. Fixtures follow the naming convention `warning__.res` so coverage gaps stay greppable. -### Confirmed dead (no `prerr_warning` site in the compiler) +### Removed warnings -These warning constructors exist in `warnings.ml` but are never raised -anywhere in `compiler/`. They are candidates for removal. - -| Number | Variant | Reason | -|---|---|---| -| 1 | `Comment_start` | Lexer warning; modern parser doesn't emit. | -| 2 | `Comment_not_end` | Lexer warning; modern parser doesn't emit. | -| 7 | `Method_override` | OCaml class system, not exposed by ReScript. | -| 13 | `Instance_variable_override` | OCaml class system. | -| 14 | `Illegal_backslash` | Lexer-level escape warning; parser doesn't emit. | -| 15 | `Implicit_public_methods` | OCaml class system. | -| 29 | `Eol_in_string` | Lexer-level string warning. | -| 48 | `Eliminated_optional_arguments` | Declared but never raised. | -| 50 | `Bad_docstring` | Declared but never raised; also default-disabled. | -| 105 | `Bs_fragile_external` | Declared but never raised. | -| 106 | `Bs_unimplemented_primitive` | Declared but never raised. | -| 10 | `Statement_type` | Raised at typecore.ml:2052 inside `check_application_result`, but `statement` is always `false` at the only call site (typecore.ml:3983); sequence statements hit `Expr_type_clash` via `type_statement` unifying to `unit`. | -| 16 | `Unerasable_optional_argument` | Raised at typecore.ml:3526, but `type_function` (typecore.ml:3479) explicitly disables this warning before the check runs (`Warnings.parse_options false "-16"`). | -| 108 | `Bs_uninterpreted_delimiters` | Raised at bs_warnings.ml:29 for `Pconst_string` with delimiter `"js"`; the modern scanner has no `{js\|...\|js}` form and template strings don't tag with `"js"`. | +The warning constructors listed in **Removed in `jono/remove-dead-errors`** +were deleted. Their numeric warning slots remain holes; no warning number +was reused. ### Live but no fixture yet From 0e0143891294d941352e928e51bb21a64e3191c9 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Fri, 22 May 2026 16:36:36 +0000 Subject: [PATCH 14/16] Restore live typedecl rebind diagnostic Full build testing showed extension_rebind_mismatch.res exercises Rebind_wrong_type, not Rebind_mismatch. Restore the typed unification diagnostic and update the audit to mark Rebind_wrong_type live while leaving Rebind_mismatch unconfirmed. --- compiler/ml/typedecl.ml | 14 +++++++++----- tests/ERROR_VARIANTS.md | 19 +++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/ml/typedecl.ml b/compiler/ml/typedecl.ml index 4e0f6d31ca..fe6abdf406 100644 --- a/compiler/ml/typedecl.ml +++ b/compiler/ml/typedecl.ml @@ -38,6 +38,7 @@ type error = | Cannot_extend_private_type of Path.t | Not_extensible_type of Path.t | Extension_mismatch of Path.t * Includecore.type_mismatch list + | Rebind_wrong_type of Longident.t * Env.t * (type_expr * type_expr) list | Rebind_mismatch of Longident.t * Path.t * Path.t | Rebind_private of Longident.t | Bad_variance of int * (bool * bool * bool) * (bool * bool * bool) @@ -1645,11 +1646,8 @@ let transl_extension_constructor env type_path type_params typext_params priv else (Ctype.newconstr type_path typext_params, None) in (try Ctype.unify env cstr_res res - with Ctype.Unify _ -> - Location.raise_errorf ~loc:lid.loc - "The constructor %a has a type that is incompatible with this \ - extension" - Printtyp.longident lid.txt); + with Ctype.Unify trace -> + raise (Error (lid.loc, Rebind_wrong_type (lid.txt, env, trace)))); (* Remove "_" names from parameters used in the constructor *) (if not cdescr.cstr_generalized then let vars = Ctype.free_variables (Btype.newgenty (Ttuple args)) in @@ -2196,6 +2194,12 @@ let report_error ppf = function "does not match the definition of type" (Path.name path) (Includecore.report_type_mismatch "the type" "this extension" "definition") errs + | Rebind_wrong_type (lid, env, trace) -> + Printtyp.report_unification_error ppf env trace + (function + | ppf -> + fprintf ppf "The constructor %a@ has type" Printtyp.longident lid) + (function ppf -> fprintf ppf "but was expected to be of type") | Rebind_mismatch (lid, p, p') -> fprintf ppf "@[%s@ %a@ %s@ %s@ %s@ %s@ %s@]" "The constructor" Printtyp.longident lid "extends type" (Path.name p) diff --git a/tests/ERROR_VARIANTS.md b/tests/ERROR_VARIANTS.md index d9f8a00ac2..728658c82f 100644 --- a/tests/ERROR_VARIANTS.md +++ b/tests/ERROR_VARIANTS.md @@ -66,8 +66,8 @@ fallbacks instead of catalogued variants. `Incoherent_label_order`, `Recursive_local_constraint`, `Invalid_interval`, `Invalid_for_of_pattern` - `typedecl`: `Type_clash`, `Parameters_differ`, - `Null_arity_external`, `Rebind_wrong_type`, `Bad_fixed_type`, - `Varying_anonymous`, `Val_in_structure` + `Null_arity_external`, `Bad_fixed_type`, `Varying_anonymous`, + `Val_in_structure` - `typemod`: `Cannot_eliminate_dependency`, `With_makes_applicative_functor_ill_typed`, `With_cannot_remove_constrained_type`, `Scoping_pack` @@ -84,11 +84,13 @@ fallbacks instead of catalogued variants. `Bs_uninterpreted_delimiters` Re-validation also found a few previously-flagged items that are not -completely dead: `includemod.Unbound_modtype_path` can still represent a -stale compiled-interface failure, `Syntaxerr.Variable_in_scope` is live -but lacks a registered printer, and the UTF-8 helper error families are -still raised by test/defensive helper entry points. Those are retained -below with updated notes. +completely dead: `typedecl.Rebind_wrong_type` is live via extension +rebinding across incompatible extension types, +`includemod.Unbound_modtype_path` can still represent a stale +compiled-interface failure, `Syntaxerr.Variable_in_scope` is live but +lacks a registered printer, and the UTF-8 helper error families are still +raised by test/defensive helper entry points. Those are retained below +with updated notes. --- @@ -166,7 +168,8 @@ Type-declaration errors. Source: [typedecl.ml:27](../compiler/ml/typedecl.ml). | `Cannot_extend_private_type` | ✓ | `cannot_extend_private_type.res` | | | `Not_extensible_type` | ✓ | `not_extensible_type.res` | | | `Extension_mismatch` | ✓ | `extension_arity_mismatch.res` | `type t<'a> = ..` extended with `type t += A(int)` — arity differs from the extensible type. | -| `Rebind_mismatch` | ✓ | `extension_rebind_mismatch.res` | Rebinding constructor into a different extensible type. | +| `Rebind_wrong_type` | ✓ | `extension_rebind_mismatch.res` | Rebinding constructor into a different extensible type fails while unifying the source constructor result with the extension target. | +| `Rebind_mismatch` | ? | — | The later declaration-shape check after `Rebind_wrong_type`; no source fixture was confirmed in this pass. | | `Rebind_private` | ✓ | `extension_rebind_private.res` | Rebinding a private extension constructor as public. | | `Bad_variance` | ✓ | `bad_variance.res`, `bad_variance_contra.res` | | | `Unavailable_type_constructor` | ☐ (needs build harness) | — | typedecl.ml:778. Requires a type path findable at parse time but missing during constraint enforcement; only cross-unit scenarios where a `.cmi` was found but later removed. | From 20077be7e05739ed9ace6d0d4d05d9bad89e5158 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Wed, 27 May 2026 17:29:28 +0000 Subject: [PATCH 15/16] Restore live typecore label diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reproductions during PR review showed that two of the three typecore label variants removed by 52bed6c7f are still reachable from regular ReScript source: - Label_mismatch fires when a record literal without an expected type mixes fields from two different record types — disambiguation picks one type per label and the cross-type unify inside type_label_exp fails. Fixture: label_mismatch_record_literal.res. - Abstract_wrong_label fires when a multi-arg function literal has an inner argument label that doesn't match the expected arrow's label. Fixture: abstract_wrong_label.res. Restore both variants, their raise sites, and reporter cases. The third removed variant (Incoherent_label_order) stays removed — every attempt to reach it routed through Expr_type_clash via the modern arity-aware unify path. Update tests/ERROR_VARIANTS.md to mark both rows ✓ with the new fixtures and drop them from the removal list. The pattern-path catch in type_pat_aux stays removed (was genuinely dead because unify_pat_types already translates Ctype.Unify to Pattern_type_clash). --- compiler/ml/typecore.ml | 32 ++++++++++++++++--- compiler/ml/typecore.mli | 2 ++ tests/ERROR_VARIANTS.md | 10 ++++-- .../abstract_wrong_label.res.expected | 9 ++++++ ...label_mismatch_record_literal.res.expected | 11 +++++++ .../fixtures/abstract_wrong_label.res | 1 + .../label_mismatch_record_literal.res | 3 ++ 7 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 tests/build_tests/super_errors/expected/abstract_wrong_label.res.expected create mode 100644 tests/build_tests/super_errors/expected/label_mismatch_record_literal.res.expected create mode 100644 tests/build_tests/super_errors/fixtures/abstract_wrong_label.res create mode 100644 tests/build_tests/super_errors/fixtures/label_mismatch_record_literal.res diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index a3774ffed2..b709ce1954 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -32,6 +32,7 @@ type error = expected: int; provided: int; } + | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string @@ -42,6 +43,7 @@ type error = } | Apply_non_function of type_expr | Apply_wrong_label of arg_label * type_expr + | Abstract_wrong_label of arg_label * type_expr | Label_multiply_defined of { label: string; jsx_component_info: jsx_prop_error_info option; @@ -3462,9 +3464,13 @@ and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l if separate then begin_def (); let ty_arg, ty_res = try filter_arrow ~env ~arity (instance env ty_expected) l - with Unify _ -> - raise - (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun))) + with Unify _ -> ( + match expand_head env ty_expected with + | {desc = Tarrow _} as ty -> + raise (Error (loc, env, Abstract_wrong_label (l, ty))) + | _ -> + raise + (Error (loc_fun, env, Too_many_arguments (in_function <> None, ty_fun)))) in let ty_arg = if is_optional l then ( @@ -3542,8 +3548,9 @@ and type_label_exp ~call_context create env loc ty_expected (* Generalize label information *) generalize_structure ty_arg; generalize_structure ty_res); - unify_exp_types ~context:None lid.loc env (instance_def ty_res) - (instance env ty_expected); + (try unify env (instance_def ty_res) (instance env ty_expected) + with Unify trace -> + raise (Error (lid.loc, env, Label_mismatch (lid.txt, trace)))); (* Instantiate so that we can generalize internal nodes *) let ty_arg = instance_def ty_arg in if separate then ( @@ -4555,6 +4562,13 @@ let report_error env loc ppf error = (if expected == 1 then "argument" else "arguments") (if provided < expected then " only" else "") provided + | Label_mismatch (lid, trace) -> + (* modified *) + super_report_unification_error ppf env trace + (function + | ppf -> + fprintf ppf "The record field %a@ belongs to the type" longident lid) + (function ppf -> fprintf ppf "but is mixed here with fields of type") | Pattern_type_clash trace -> (* modified *) super_report_unification_error ppf env trace @@ -4637,6 +4651,14 @@ let report_error env loc ppf error = in fprintf ppf "@[@[<2>%a@]@,This function has type: %a@]" print_message l type_expr ty + | Abstract_wrong_label (l, ty) -> + let label_mark = function + | Nolabel -> "but its first argument is not labelled" + | l -> + sprintf "but its first argument is labelled %s" (prefixed_label_name l) + in + fprintf ppf "@[@[<2>This function should have type@ %a@]@,%s@]" type_expr + ty (label_mark l) | Label_multiply_defined {label; jsx_component_info = Some jsx_component_info} -> fprintf ppf diff --git a/compiler/ml/typecore.mli b/compiler/ml/typecore.mli index cc63ed4fe7..10ff2ad8ca 100644 --- a/compiler/ml/typecore.mli +++ b/compiler/ml/typecore.mli @@ -65,6 +65,7 @@ type error = expected: int; provided: int; } + | Label_mismatch of Longident.t * (type_expr * type_expr) list | Pattern_type_clash of (type_expr * type_expr) list | Or_pattern_type_clash of Ident.t * (type_expr * type_expr) list | Multiply_bound_variable of string @@ -75,6 +76,7 @@ type error = } | Apply_non_function of type_expr | Apply_wrong_label of arg_label * type_expr + | Abstract_wrong_label of arg_label * type_expr | Label_multiply_defined of { label: string; jsx_component_info: Error_message_utils.jsx_prop_error_info option; diff --git a/tests/ERROR_VARIANTS.md b/tests/ERROR_VARIANTS.md index 728658c82f..f07deea663 100644 --- a/tests/ERROR_VARIANTS.md +++ b/tests/ERROR_VARIANTS.md @@ -62,8 +62,7 @@ unreachable and removed. Guard sites that could still be reached by malformed PPX-produced ASTs now use direct `Location.raise_errorf` fallbacks instead of catalogued variants. -- `typecore`: `Label_mismatch`, `Abstract_wrong_label`, - `Incoherent_label_order`, `Recursive_local_constraint`, +- `typecore`: `Incoherent_label_order`, `Recursive_local_constraint`, `Invalid_interval`, `Invalid_for_of_pattern` - `typedecl`: `Type_clash`, `Parameters_differ`, `Null_arity_external`, `Bad_fixed_type`, `Varying_anonymous`, @@ -86,6 +85,11 @@ fallbacks instead of catalogued variants. Re-validation also found a few previously-flagged items that are not completely dead: `typedecl.Rebind_wrong_type` is live via extension rebinding across incompatible extension types, +`typecore.Label_mismatch` is live when a record literal without an +expected type mixes fields from two different record types (see +`label_mismatch_record_literal.res`), `typecore.Abstract_wrong_label` +is live when a multi-arg function literal has a mislabelled inner +argument (see `abstract_wrong_label.res`), `includemod.Unbound_modtype_path` can still represent a stale compiled-interface failure, `Syntaxerr.Variable_in_scope` is live but lacks a registered printer, and the UTF-8 helper error families are still @@ -110,6 +114,8 @@ Source: [typecore.ml:27](../compiler/ml/typecore.ml). | `Expr_type_clash` | ✓ | many `*.res` | Most-fired expression error. Trace-shape sub-cases covered: `if_return_type_mismatch.res` (IfReturn), `maybe_unwrap_option.res` (MaybeUnwrapOption), `string_concat_non_string.res` (StringConcat), `labeled_fn_argument_type_clash.res` (FunctionArgument with explicit label), `math_operator_*.res` (MathOperator family), `ternary_branch_mismatch.res`, `switch_different_types.res`, `try_catch_same_type.res`, `comparison_operator.res`, `array_item_type_mismatch.res`, `array_literal_passed_to_tuple.res`, `if_condition_mismatch.res`, `while_condition.res`, `for_loop_condition.res`, `assert_condition.res`, `function_call_mismatch.res`, `awaiting_non_promise.res`, multiple `jsx_*` fixtures. | | `Apply_non_function` | ✓ | `apply_non_function.res` | | | `Apply_wrong_label` | ✓ | `apply_wrong_label.res` | | +| `Abstract_wrong_label` | ✓ | `abstract_wrong_label.res` | Multi-arg function literal where an inner argument label doesn't match the expected arrow's label (e.g. `let f: (~a, ~b) => int = (~a, ~c) => …`). | +| `Label_mismatch` | ✓ | `label_mismatch_record_literal.res` | Record literal without expected type mixing fields from two different record types — disambiguation picks one type per label, and the cross-type unify fails inside `type_label_exp`. | | `Label_multiply_defined` | ✓ | `label_multiply_defined_literal.res` | | | `Labels_missing` | ✓ | `missing_label.res`, `missing_labels.res` | | | `Label_not_mutable` | ✓ | `label_not_mutable.res` | | diff --git a/tests/build_tests/super_errors/expected/abstract_wrong_label.res.expected b/tests/build_tests/super_errors/expected/abstract_wrong_label.res.expected new file mode 100644 index 0000000000..272b06a71b --- /dev/null +++ b/tests/build_tests/super_errors/expected/abstract_wrong_label.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/abstract_wrong_label.res:1:41-52 + + 1 │ let f: (~a: int, ~b: int) => int = (~a, ~c) => a + c + 2 │ + + This function should have type (~b: int) => int + but its first argument is labelled ~c \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/label_mismatch_record_literal.res.expected b/tests/build_tests/super_errors/expected/label_mismatch_record_literal.res.expected new file mode 100644 index 0000000000..aa9a0e5d46 --- /dev/null +++ b/tests/build_tests/super_errors/expected/label_mismatch_record_literal.res.expected @@ -0,0 +1,11 @@ + + We've found a bug for you! + /.../fixtures/label_mismatch_record_literal.res:3:16 + + 1 │ type a = {x: int} + 2 │ type b = {y: int} + 3 │ let _ = {x: 1, y: 2} + 4 │ + + The record field y belongs to the type b + but is mixed here with fields of type a \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/abstract_wrong_label.res b/tests/build_tests/super_errors/fixtures/abstract_wrong_label.res new file mode 100644 index 0000000000..25fc0aaf18 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/abstract_wrong_label.res @@ -0,0 +1 @@ +let f: (~a: int, ~b: int) => int = (~a, ~c) => a + c diff --git a/tests/build_tests/super_errors/fixtures/label_mismatch_record_literal.res b/tests/build_tests/super_errors/fixtures/label_mismatch_record_literal.res new file mode 100644 index 0000000000..640d3ee57f --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/label_mismatch_record_literal.res @@ -0,0 +1,3 @@ +type a = {x: int} +type b = {y: int} +let _ = {x: 1, y: 2} From 4c8c646718dcef324aec2250ac4f9b4072420db1 Mon Sep 17 00:00:00 2001 From: Jono Prest Date: Wed, 27 May 2026 20:00:18 +0000 Subject: [PATCH 16/16] Switch defensive raise sites to assert false; revert typemod/Misplaced_label_syntax PR-review feedback: replacing dead raise sites with Location.raise_errorf moves code rather than removing it, and introduces a pattern that doesn't exist anywhere else in the typer modules (which use raise (Error ...) for real errors and assert false for unreachable defensive code; zero inline Location.raise_errorf calls in master). This commit aligns the cleanup with the existing convention: 1. Variants whose raise sites are confirmed unreachable from the ReScript parser have those sites rewritten to `assert false (* reason *)` with a comment citing the parser block or sibling check. The named variant (decl + reporter) stays removed. - typecore.Invalid_interval, Invalid_for_of_pattern (parser blocks / normalizes the AST) - typetexp.Unbound_type_constructor_2, Ill_typed_functor_application, Apply_structure_as_functor (parser doesn't construct Lapply or bare-Tvar Tconstr body) - typedecl.Type_clash, Parameters_differ (Cycle_in_def fires first), Null_arity_external (Primitive.parse_declaration sets prim_native_name always), Bad_fixed_type (is_fixed_type and expand_head agree), Varying_anonymous (parser rejects `_` type params), Val_in_structure (parser rejects val outside .resi) - bs_syntaxerr.Unhandled_poly_type (parser misreads inline 'a. as deprecated uncurried syntax) - env.Illegal_value_name (parser doesn't emit '->' or # identifiers) - typecore.Incoherent_label_order: collapsed into Apply_wrong_label with a comment explaining why the original second arm was unreachable 2. Variants where reproduction confirmed they ARE reachable, or where I couldn't prove unreachability, are restored to named-variant form: - typemod.Cannot_eliminate_dependency (couldn't reproduce, but reachable from non-generative functor application paths in principle - retained conservatively) - typemod.With_makes_applicative_functor_ill_typed (couldn't reproduce - retained conservatively) - typemod.With_cannot_remove_constrained_type (REACHABLE via destructive substitution on a constrained type, fixture with_cannot_remove_constrained_type.res) - typemod.Scoping_pack (couldn't reproduce - retained conservatively) - bs_syntaxerr.Misplaced_label_syntax (REACHABLE via operator-as- identifier syntax with labelled arg, fixture misplaced_label_syntax.res) 3. tests/ERROR_VARIANTS.md updated to (a) split the Removed section into "Truly dead" and "Defensive unreachable" categories, (b) note the restored typemod variants with `?` status, (c) add covered rows for the two new fixtures. Truly-dead removals (no raise site, transitively dead, or always-false guard) are unchanged: 3 Ctype exceptions, 2 relay variants (typecore.Recursive_local_constraint, typetexp.Variant_tags), bs_syntaxerr.Conflict_bs_bs_this_bs_meth, 14 warning constructors. Validation: rg confirmed no remaining references to the removed variants. make compiler, super_errors (745 fixtures), super_errors_multi (54 fixtures) all pass. make checkformat clean. --- compiler/frontend/ast_core_type.ml | 8 +- compiler/frontend/bs_syntaxerr.ml | 7 +- compiler/frontend/bs_syntaxerr.mli | 1 + compiler/ml/env.ml | 13 +- compiler/ml/typecore.ml | 26 +++- compiler/ml/typedecl.ml | 58 ++++++--- compiler/ml/typemod.ml | 57 +++++---- compiler/ml/typemod.mli | 5 + compiler/ml/typetexp.ml | 28 +++-- tests/ERROR_VARIANTS.md | 116 ++++++++++++------ .../misplaced_label_syntax.res.expected | 9 ++ ...annot_remove_constrained_type.res.expected | 12 ++ .../fixtures/misplaced_label_syntax.res | 2 + .../with_cannot_remove_constrained_type.res | 5 + 14 files changed, 245 insertions(+), 102 deletions(-) create mode 100644 tests/build_tests/super_errors/expected/misplaced_label_syntax.res.expected create mode 100644 tests/build_tests/super_errors/expected/with_cannot_remove_constrained_type.res.expected create mode 100644 tests/build_tests/super_errors/fixtures/misplaced_label_syntax.res create mode 100644 tests/build_tests/super_errors/fixtures/with_cannot_remove_constrained_type.res diff --git a/compiler/frontend/ast_core_type.ml b/compiler/frontend/ast_core_type.ml index 3f056c2bb4..f834d6f4b9 100644 --- a/compiler/frontend/ast_core_type.ml +++ b/compiler/frontend/ast_core_type.ml @@ -136,8 +136,12 @@ let list_of_arrow (ty : t) : t * Parsetree.arg list = match ty.ptyp_desc with | Ptyp_arrow {arg; ret; arity} when arity = None || acc = [] -> aux ret (arg :: acc) - | Ptyp_poly (_, ty) -> - Location.raise_errorf ~loc:ty.ptyp_loc "Unhandled poly type" + | Ptyp_poly _ -> + (* unreachable: this would require an inline Ptyp_poly inside an + external's arrow chain. The ReScript parser misreads inline `'a.` + prefix syntax as the deprecated uncurried `(. …)` form and rejects + it, so the typer never sees the required AST shape. *) + assert false | _ -> (ty, List.rev acc) in aux ty [] diff --git a/compiler/frontend/bs_syntaxerr.ml b/compiler/frontend/bs_syntaxerr.ml index 7ef491e6f9..7509f328f1 100644 --- a/compiler/frontend/bs_syntaxerr.ml +++ b/compiler/frontend/bs_syntaxerr.ml @@ -46,6 +46,7 @@ type error = | Bs_this_simple_pattern | Experimental_feature_not_enabled of Experimental_features.feature | LetUnwrap_not_supported_in_position of [`Toplevel | `Unsupported_type] + | Misplaced_label_syntax let pp_error fmt err = Format.pp_print_string fmt @@ -86,7 +87,8 @@ let pp_error fmt err = | `Toplevel -> "`let?` is not allowed for top-level bindings." | `Unsupported_type -> "`let?` is only supported in let bindings targeting the `result` or \ - `option` type.")) + `option` type.") + | Misplaced_label_syntax -> "Label syntax is not supported in this position") type exn += Error of Location.t * error @@ -103,5 +105,4 @@ let optional_err loc (lbl : Asttypes.arg_label) = | _ -> () let err_if_label loc (lbl : Asttypes.arg_label) = - if lbl <> Nolabel then - Location.raise_errorf ~loc "Label syntax is not supported in this position" + if lbl <> Nolabel then raise (Error (loc, Misplaced_label_syntax)) diff --git a/compiler/frontend/bs_syntaxerr.mli b/compiler/frontend/bs_syntaxerr.mli index c174245fb1..4851c3adcb 100644 --- a/compiler/frontend/bs_syntaxerr.mli +++ b/compiler/frontend/bs_syntaxerr.mli @@ -46,6 +46,7 @@ type error = | Bs_this_simple_pattern | Experimental_feature_not_enabled of Experimental_features.feature | LetUnwrap_not_supported_in_position of [`Toplevel | `Unsupported_type] + | Misplaced_label_syntax val err : Location.t -> error -> 'a diff --git a/compiler/ml/env.ml b/compiler/ml/env.ml index b6e23e8def..1466467033 100644 --- a/compiler/ml/env.ml +++ b/compiler/ml/env.ml @@ -1616,13 +1616,16 @@ and check_usage loc id warn tbl = and check_value_name name loc = (* Note: we could also check here general validity of the identifier, to protect against bad identifiers forged by -pp or - -ppx preprocessors. *) - if name = "->" then - Location.raise_errorf ~loc "'%s' is not a valid value identifier." name + -ppx preprocessors. + + Both guarded paths below are unreachable: the ReScript parser never + emits value identifiers named "->" or containing "#" — both shapes + are rejected as syntax errors. *) + ignore loc; + if name = "->" then assert false else if String.length name > 0 && name.[0] = '#' then for i = 1 to String.length name - 1 do - if name.[i] = '#' then - Location.raise_errorf ~loc "'%s' is not a valid value identifier." name + if name.[i] = '#' then assert false done and store_value ?check id decl env = diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index b709ce1954..1d666ab142 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -1336,8 +1336,10 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp type_pat ~explode:0 p expected_ty k (* TODO: record 'extra' to remember about interval *) | Ppat_interval _ -> - Location.raise_errorf ~loc - "Only character intervals are supported in patterns." + (* unreachable: the ReScript parser (compiler/syntax/src/res_core.ml) has + no construction site for Ppat_interval — interval patterns are OCaml + syntax not part of the ReScript grammar *) + assert false | Ppat_tuple spl -> assert (List.length spl >= 2); let spl_ann = List.map (fun p -> (p, newvar ())) spl in @@ -3088,8 +3090,11 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) Types.val_loc = loc; } env ~check:(fun s -> Warnings.Unused_for_index s) | _ -> - Location.raise_errorf ~loc:param.ppat_loc - "Invalid for...of binding: only variables and _ are allowed." + (* unreachable: the parser's normalize_for_of_pattern + (compiler/syntax/src/res_core.ml:3841) catches every non-var, + non-`_` pattern, emits a syntax error, and replaces the pattern + with Ppat_any before the typer runs *) + assert false in let body = with_depth loop_depth (fun () -> @@ -3122,8 +3127,11 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) Types.val_loc = loc; } env ~check:(fun s -> Warnings.Unused_for_index s) | _ -> - Location.raise_errorf ~loc:param.ppat_loc - "Invalid for...of binding: only variables and _ are allowed." + (* unreachable: the parser's normalize_for_of_pattern + (compiler/syntax/src/res_core.ml:3841) catches every non-var, + non-`_` pattern, emits a syntax error, and replaces the pattern + with Ppat_any before the typer runs *) + assert false in let body = with_depth loop_depth (fun () -> @@ -3849,6 +3857,12 @@ and type_application ~context total_app env funct (sargs : sargs) : (Error (sarg1.pexp_loc, env, Apply_wrong_label (l1, funct.exp_type))) else + (* Originally split between Apply_wrong_label (label not in + ty_fun) and Incoherent_label_order (label in ty_fun but at + a different position). The latter is unreachable: modern + arity-aware unify in type_function eagerly compares against + ty_expected, raising Expr_type_clash before this branch + fires. Both label problems now surface as Apply_wrong_label. *) raise (Error (sarg1.pexp_loc, env, Apply_wrong_label (l1, ty_res))) | _ -> diff --git a/compiler/ml/typedecl.ml b/compiler/ml/typedecl.ml index fe6abdf406..07ce074622 100644 --- a/compiler/ml/typedecl.ml +++ b/compiler/ml/typedecl.ml @@ -108,7 +108,7 @@ let enter_type rec_flag env sdecl id = in Env.add_type ~check:true id decl env -let update_type temp_env env id loc = +let update_type temp_env env id _loc = let path = Path.Pident id in let decl = Env.find_type path temp_env in match decl.type_manifest with @@ -117,8 +117,10 @@ let update_type temp_env env id loc = let params = List.map (fun _ -> Ctype.newvar ()) decl.type_params in try Ctype.unify env (Ctype.newconstr path params) ty with Ctype.Unify _ -> - Location.raise_errorf ~loc - "This type constructor expands to an incompatible type.") + (* unreachable: every recursive abbreviation shape that would reach + this unify failure hits Cycle_in_def in check_recursive_type + (see line ~902 below) before check_coherence runs *) + assert false) (* We use the Ctype.expand_head_opt version of expand_head to get access to the manifest type of private abbreviations. *) @@ -170,7 +172,7 @@ let is_fixed_type sd = && sd.ptype_private = Private && has_row_var sty (* Set the row variable in a fixed type *) -let set_fixed_row env loc p decl = +let set_fixed_row env _loc p decl = let tm = match decl.type_manifest with | None -> assert false @@ -184,10 +186,16 @@ let set_fixed_row env loc p decl = if Btype.static_row row then Btype.newgenty Tnil else row.row_more | Tobject (ty, _) -> snd (Ctype.flatten_fields ty) | _ -> - Location.raise_errorf ~loc "This fixed type is not an object or variant" + (* unreachable: gated by `is_fixed_type decl`, which only returns true + when the syntactic manifest carries an open polymorphic-variant or + object row. `expand_head` preserves that row, so the manifest's + desc is always Tvariant or Tobject here. *) + assert false in if not (Btype.is_Tvar rv) then - Location.raise_errorf ~loc "This fixed type has no row variable"; + (* unreachable: same is_fixed_type invariant — the row is always a Tvar + (or extended-Tvar) when is_fixed_type passes *) + assert false; rv.desc <- Tconstr (p, decl.type_params, ref Mnil) (* Translate one type declaration *) @@ -978,10 +986,14 @@ let check_recursion env loc path decl to_check = match ty.desc with | Tconstr (path', args', _) -> (if Path.same path path' then ( - if not (Ctype.equal env false args args') then - Location.raise_errorf ~loc - "In the definition of %s, recursive type parameters differ." - (Path.name cpath)) + if not (Ctype.equal env false args args') then ( + (* unreachable: check_regular runs only on abbreviations, + and every recursive-abbreviation shape hits Cycle_in_def + in the earlier check_recursive_type pass before reaching + here. Variant constructors with non-uniform recursion + (`type rec t<'a> = T(t)`) don't trigger check_regular. *) + ignore cpath; + assert false)) else if (* Attempt to expand a type abbreviation if: 1- [to_check path'] holds @@ -1234,7 +1246,7 @@ let for_constr = function (fun {Types.ld_mutable; ld_type} -> (ld_mutable = Mutable, ld_type)) l -let compute_variance_gadt env check ((required, loc) as rloc) decl +let compute_variance_gadt env check ((required, _loc) as rloc) decl (tl, ret_type_opt) = match ret_type_opt with | None -> @@ -1255,9 +1267,11 @@ let compute_variance_gadt env check ((required, loc) as rloc) decl | fv :: fv2 -> (* fv1 @ fv2 = free_variables of other parameters *) if (c || n) && constrained (fv1 @ fv2) ty then - Location.raise_errorf ~loc - "In this GADT definition, the variance of some parameter \ - cannot be checked."; + (* unreachable: this would fire on a GADT parameter that's + `_` (anonymous). ReScript's parser rejects `_` in + `type t<...>` parameter positions, so the typer never + sees the required AST shape. *) + assert false; (fv :: fv1, fv2)) ([], fvl) tyl required in @@ -1882,8 +1896,12 @@ let transl_value_decl env loc valdecl = val_attributes = valdecl.pval_attributes; } | [] -> - Location.raise_errorf ~loc:valdecl.pval_loc - "Value declarations are only allowed in signatures" + (* unreachable: `pval_prim = []` outside a signature can only arise + from the parser's `external` recovery, which sets `prim = []` + *after* emitting a syntax error, so the typer never sees the + declaration. A bare `val x: int` in a .res is also rejected at + parse time. *) + assert false | _ -> let arity, from_constructor = parse_arity env valdecl.pval_type ty in let prim = Primitive.parse_declaration valdecl ~arity ~from_constructor in @@ -1897,8 +1915,12 @@ let transl_value_decl env loc valdecl = && (prim.prim_name = "" || (prim.prim_name.[0] <> '%' && prim.prim_name.[0] <> '#')) then - Location.raise_errorf ~loc:valdecl.pval_type.ptyp_loc - "External identifiers must be functions"; + (* unreachable: Primitive.parse_declaration always assigns the + magic 20-byte prim_native_name encoding to externals; the + `prim_native_name = ""` precondition can't be satisfied alongside + `prim_arity = 0` from any externals that survive parsing. Empty + prim names are rejected earlier with `Not a valid global name`. *) + assert false; { val_type = ty; val_kind = Val_prim prim; diff --git a/compiler/ml/typemod.ml b/compiler/ml/typemod.ml index 48cfba0b62..e823d4ac82 100644 --- a/compiler/ml/typemod.ml +++ b/compiler/ml/typemod.ml @@ -24,11 +24,15 @@ open Format type error = | Cannot_apply of module_type | Not_included of Includemod.error list + | Cannot_eliminate_dependency of module_type | Signature_expected | Structure_expected of module_type | With_no_component of Longident.t | With_mismatch of Longident.t * Includemod.error list + | With_makes_applicative_functor_ill_typed of + Longident.t * Path.t * Includemod.error list | With_changes_module_alias of Longident.t * Ident.t * Path.t + | With_cannot_remove_constrained_type | Repeated_name of string * string * Warnings.loc | Non_generalizable of type_expr | Non_generalizable_module of module_type @@ -36,6 +40,7 @@ type error = | Not_allowed_in_functor_body | Not_a_packed_module of type_expr | Incomplete_packed_module of type_expr + | Scoping_pack of Longident.t * type_expr | Recursive_module_require_explicit_type | Apply_generative | Cannot_scrape_alias of Path.t @@ -246,13 +251,12 @@ let check_usage_of_path_of_substituted_item paths env signature ~loc ~lid = let env = !env in try retype_applicative_functor_type ~loc env funct arg with Includemod.Error explanation -> - Location.raise_errorf ~loc - "@[@[This `with' constraint on %a makes the applicative \ - functor type %s ill-typed in the constrained \ - signature:@]@ %a@]" - Printtyp.longident lid.txt - (Path.name referenced_path) - Includemod.report_error explanation)); + raise + (Error + ( loc, + env, + With_makes_applicative_functor_ill_typed + (lid.txt, referenced_path, explanation) )))); } in iterator.Btype.it_signature iterator signature; @@ -435,11 +439,8 @@ let merge_constraint initial_env loc sg constr = in let params = tdecl.typ_type.type_params in if params_are_constrained params then - Location.raise_errorf ~loc - "@[Destructive substitutions are not supported for \ - constrained types (other than when replacing a type \ - constructor with a type constructor with the same \ - arguments).@]"; + raise + (Error (loc, initial_env, With_cannot_remove_constrained_type)); fun s path -> Subst.add_type_function path ~params ~body s in let sub = List.fold_left how_to_extend_subst Subst.identity !real_ids in @@ -1329,11 +1330,10 @@ and type_module_aux ~alias sttn funct_body anchor env smod = (Env.add_module ~arg:true param arg.mod_type env) param mty_res with Not_found -> - Location.raise_errorf ~loc:smod.pmod_loc - "@[This functor has type@ %a@ The parameter cannot be \ - eliminated in the result type.@ Bind the argument to a \ - module identifier.@]" - Printtyp.modtype mty_functor) + raise + (Error + (smod.pmod_loc, env, Cannot_eliminate_dependency mty_functor)) + ) in rm { @@ -1714,10 +1714,7 @@ let type_package env m p nl = (fun n ty -> try Ctype.unify env ty (Ctype.newvar ()) with Ctype.Unify _ -> - Location.raise_errorf ~loc:m.pmod_loc - "@[The type %a in this module cannot be exported.@ Its type \ - contains local dependencies:@ %a@]" - Printtyp.longident n Printtyp.type_expr ty) + raise (Error (m.pmod_loc, env, Scoping_pack (n, ty)))) nl tl'; (wrap_constraint env modl mty Tmodtype_implicit, tl') @@ -1833,6 +1830,16 @@ let report_error ppf = function "@[@[In this `with' constraint, the new definition of %a@ does not \ match its original definition@ in the constrained signature:@]@ %a@]" longident lid Includemod.report_error explanation + | With_makes_applicative_functor_ill_typed (lid, path, explanation) -> + fprintf ppf + "@[@[This `with' constraint on %a makes the applicative functor @ \ + type %s ill-typed in the constrained signature:@]@ %a@]" + longident lid (Path.name path) Includemod.report_error explanation + | With_cannot_remove_constrained_type -> + fprintf ppf + "@[Destructive substitutions are not supported for constrained @ \ + types (other than when replacing a type constructor with @ a type \ + constructor with the same arguments).@]" | With_changes_module_alias (lid, id, path) -> fprintf ppf "@[@[This `with' constraint on %a changes %s, which is aliased @ in \ @@ -1866,6 +1873,11 @@ let report_error ppf = function | Interface_not_compiled intf_name -> fprintf ppf "@[Could not find the .cmi file for interface@ %a.@]" Location.print_filename intf_name + | Cannot_eliminate_dependency mty -> + fprintf ppf + "@[This functor has type@ %a@ The parameter cannot be eliminated in the \ + result type.@ Bind the argument to a module identifier.@]" + modtype mty | Not_allowed_in_functor_body -> fprintf ppf "@[This expression creates fresh types.@ %s@]" "It is not allowed inside applicative functors." @@ -1875,6 +1887,9 @@ let report_error ppf = function | Incomplete_packed_module ty -> fprintf ppf "The type of this packed module contains variables:@ %a" type_expr ty + | Scoping_pack (lid, ty) -> + fprintf ppf "The type %a in this module cannot be exported.@ " longident lid; + fprintf ppf "Its type contains local dependencies:@ %a" type_expr ty | Recursive_module_require_explicit_type -> fprintf ppf "Recursive modules require an explicit module type." | Apply_generative -> diff --git a/compiler/ml/typemod.mli b/compiler/ml/typemod.mli index 8eea12e2f6..0f36cf6afd 100644 --- a/compiler/ml/typemod.mli +++ b/compiler/ml/typemod.mli @@ -64,11 +64,15 @@ val save_signature : type error = | Cannot_apply of module_type | Not_included of Includemod.error list + | Cannot_eliminate_dependency of module_type | Signature_expected | Structure_expected of module_type | With_no_component of Longident.t | With_mismatch of Longident.t * Includemod.error list + | With_makes_applicative_functor_ill_typed of + Longident.t * Path.t * Includemod.error list | With_changes_module_alias of Longident.t * Ident.t * Path.t + | With_cannot_remove_constrained_type | Repeated_name of string * string * Warnings.loc | Non_generalizable of type_expr | Non_generalizable_module of module_type @@ -76,6 +80,7 @@ type error = | Not_allowed_in_functor_body | Not_a_packed_module of type_expr | Incomplete_packed_module of type_expr + | Scoping_pack of Longident.t * type_expr | Recursive_module_require_explicit_type | Apply_generative | Cannot_scrape_alias of Path.t diff --git a/compiler/ml/typetexp.ml b/compiler/ml/typetexp.ml index c958eb4b1d..fb248c0198 100644 --- a/compiler/ml/typetexp.ml +++ b/compiler/ml/typetexp.ml @@ -86,8 +86,11 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = let fmd = Env.find_module (Env.lookup_module ~load:true flid env) env in (match Env.scrape_alias env fmd.md_type with | Mty_signature _ -> - Location.raise_errorf ~loc "The module %a is a structure, not a functor" - Printtyp.longident flid + (* unreachable: this branch handles Longident.Lapply paths, but + Lapply has no construction site in compiler/syntax/src/ — ReScript's + type-level applicative-functor syntax (OCaml's M(X).t) isn't part + of the grammar *) + assert false | Mty_alias (_, p) -> raise (Error (loc, env, Cannot_scrape_alias (flid, p))) | _ -> ()); @@ -97,8 +100,8 @@ let rec narrow_unbound_lid_error : 'a. _ -> _ -> _ -> _ -> 'a = | Mty_alias (_, p) -> raise (Error (loc, env, Cannot_scrape_alias (mlid, p))) | _ -> - Location.raise_errorf ~loc "Ill-typed functor application %a" - Printtyp.longident lid)); + (* unreachable: same Lapply path as above *) + assert false)); raise (Error (loc, env, make_error lid)) let find_component (lookup : ?loc:_ -> _) make_error env loc lid = @@ -471,9 +474,13 @@ and transl_type_aux env policy styp = let row = Btype.row_repr row in row.row_fields | {desc = Tvar _}, Some (p, _) -> - Location.raise_errorf ~loc:sty.ptyp_loc - "The type constructor %a is not yet completely defined" - Printtyp.path p + (* unreachable: this requires the inherited type's body to be a + bare Tvar Tconstr, which only arises from `type 'a t = 'a`- + style declarations. ReScript syntax requires type parameters + in angle brackets (`type t<'a> = 'a`); the leading-`'a` form + is rejected at parse time *) + ignore p; + assert false | _ -> raise (Error (sty.ptyp_loc, env, Not_a_variant ty)) in List.iter @@ -617,9 +624,10 @@ and transl_fields env policy o fields = iter_add tf; OTinherit cty | {desc = Tvar _}, Some p -> - Location.raise_errorf ~loc:sty.ptyp_loc - "The type constructor %a is not yet completely defined" Printtyp.path - p + (* unreachable: same `type 'a t = 'a` shape as above; the bare-Tvar + Tconstr body can't be constructed from ReScript syntax *) + ignore p; + assert false | _ -> raise (Error (sty.ptyp_loc, env, Not_an_object t))) in let object_fields = List.map add_field fields in diff --git a/tests/ERROR_VARIANTS.md b/tests/ERROR_VARIANTS.md index f07deea663..22ca2a50f3 100644 --- a/tests/ERROR_VARIANTS.md +++ b/tests/ERROR_VARIANTS.md @@ -57,44 +57,81 @@ dead code. ## Removed in `jono/remove-dead-errors` -The following named error and warning variants were re-validated as -unreachable and removed. Guard sites that could still be reached by -malformed PPX-produced ASTs now use direct `Location.raise_errorf` -fallbacks instead of catalogued variants. - -- `typecore`: `Incoherent_label_order`, `Recursive_local_constraint`, - `Invalid_interval`, `Invalid_for_of_pattern` -- `typedecl`: `Type_clash`, `Parameters_differ`, - `Null_arity_external`, `Bad_fixed_type`, `Varying_anonymous`, - `Val_in_structure` -- `typemod`: `Cannot_eliminate_dependency`, - `With_makes_applicative_functor_ill_typed`, - `With_cannot_remove_constrained_type`, `Scoping_pack` -- `typetexp`: `Unbound_type_constructor_2`, `Variant_tags`, - `Ill_typed_functor_application`, `Apply_structure_as_functor` -- `bs_syntaxerr`: `Conflict_bs_bs_this_bs_meth`, - `Unhandled_poly_type`, `Misplaced_label_syntax` -- `env`: `Illegal_value_name` +Two classes of removal. **Truly dead** variants — no raise site under +`compiler/`, or a guard whose predicate is always false — are deleted +entirely (declaration, raise, reporter, supporting helpers). **Defensive +unreachable** variants whose raise sites exist but are unreachable from +the ReScript parser keep their named-variant form removed and the raise +site is replaced with `assert false (* reason *)`, matching the +established convention in the typer modules (57 existing uses). + +**Truly dead — declaration + raise + reporter all removed:** + +- `ctype`: `Tags`, `Recursive_abbrev`, + `Unification_recursive_abbrev` exceptions (declared, never raised) +- `typecore`: `Recursive_local_constraint` (relay wrapper for the dead + `Unification_recursive_abbrev`) +- `typetexp`: `Variant_tags` (relay wrapper for the dead `Tags`) +- `bs_syntaxerr`: `Conflict_bs_bs_this_bs_meth` (no construction site) - `warnings`: `Comment_start`, `Comment_not_end`, `Method_override`, - `Statement_type`, `Instance_variable_override`, `Illegal_backslash`, - `Implicit_public_methods`, `Unerasable_optional_argument`, - `Eol_in_string`, `Eliminated_optional_arguments`, `Bad_docstring`, - `Bs_fragile_external`, `Bs_unimplemented_primitive`, - `Bs_uninterpreted_delimiters` - -Re-validation also found a few previously-flagged items that are not -completely dead: `typedecl.Rebind_wrong_type` is live via extension -rebinding across incompatible extension types, -`typecore.Label_mismatch` is live when a record literal without an -expected type mixes fields from two different record types (see -`label_mismatch_record_literal.res`), `typecore.Abstract_wrong_label` -is live when a multi-arg function literal has a mislabelled inner -argument (see `abstract_wrong_label.res`), -`includemod.Unbound_modtype_path` can still represent a stale -compiled-interface failure, `Syntaxerr.Variable_in_scope` is live but -lacks a registered printer, and the UTF-8 helper error families are still -raised by test/defensive helper entry points. Those are retained below -with updated notes. + `Instance_variable_override`, `Illegal_backslash`, + `Implicit_public_methods`, `Eol_in_string`, + `Eliminated_optional_arguments`, `Bad_docstring`, + `Bs_fragile_external`, `Bs_unimplemented_primitive` (declared, + never raised); `Statement_type` (caller hard-codes `statement=false`), + `Unerasable_optional_argument` (disabled around its only check), + `Bs_uninterpreted_delimiters` (trigger AST rewritten by builtin PPX + before the warning iterator runs) + +**Defensive unreachable — raise site becomes `assert false (* reason *)`, +variant + reporter removed:** + +- `typecore`: `Incoherent_label_order` (modern arity-aware unify fires + `Expr_type_clash` before this branch), `Invalid_interval` (parser + doesn't construct `Ppat_interval`), `Invalid_for_of_pattern` (parser's + `normalize_for_of_pattern` replaces non-var patterns with `Ppat_any`) +- `typetexp`: `Unbound_type_constructor_2` (needs bare-`Tvar` Tconstr + body via `type 'a t = 'a`, parser-rejected), + `Ill_typed_functor_application`, `Apply_structure_as_functor` (both + need `Longident.Lapply`, never constructed by the parser) +- `typedecl`: `Type_clash`, `Parameters_differ` (every recursive + abbreviation hits `Cycle_in_def` first), `Null_arity_external` + (`Primitive.parse_declaration` always assigns the magic + `prim_native_name` encoding), `Bad_fixed_type` (`is_fixed_type` and + `expand_head` agree on every parser-produced shape), + `Varying_anonymous` (parser rejects `_` in type parameter positions), + `Val_in_structure` (`pval_prim = []` outside a signature is only + produced by external-recovery after a syntax error) +- `bs_syntaxerr`: `Unhandled_poly_type` (parser misreads inline `'a.` + as deprecated uncurried syntax) +- `env`: `Illegal_value_name` (parser doesn't emit `"->"` or + `#`-containing identifiers) + +Re-validation found a number of previously-flagged items that are not +completely dead and have been retained as named variants: + +- `typedecl.Rebind_wrong_type` — live via extension rebinding across + incompatible extension types. +- `typecore.Label_mismatch` — live when a record literal without an + expected type mixes fields from two different record types + (`label_mismatch_record_literal.res`). +- `typecore.Abstract_wrong_label` — live when a multi-arg function + literal has a mislabelled inner argument (`abstract_wrong_label.res`). +- `typemod.With_cannot_remove_constrained_type` — live when destructive + substitution is applied to a constrained type + (`with_cannot_remove_constrained_type.res`). +- `bs_syntaxerr.Misplaced_label_syntax` — live when labelled args are + passed via operator-identifier syntax like `\"->"(x, ~b=...)` + (`misplaced_label_syntax.res`). +- `typemod.Cannot_eliminate_dependency`, `typemod.Scoping_pack`, + `typemod.With_makes_applicative_functor_ill_typed` — reproduction + attempts couldn't reach them but couldn't conclusively prove + unreachability either; retained on the conservative side. +- `includemod.Unbound_modtype_path` can still represent a stale + compiled-interface failure. +- `Syntaxerr.Variable_in_scope` is live but lacks a registered printer. +- The UTF-8 helper error families are still raised by test/defensive + helper entry points. --- @@ -202,7 +239,11 @@ Module-level errors. Source: [typemod.ml:24](../compiler/ml/typemod.ml). | `Structure_expected` | ✓ | `super_errors_multi/Smoke_unbound_module_reference` (indirect); also `open_functor.res` | | | `With_no_component` | ✓ | `with_no_component.res` | | | `With_mismatch` | ✓ | `with_mismatch.res` | | +| `With_makes_applicative_functor_ill_typed` | ? | — | typemod.ml:249. Fires when a `with` constraint on a signature containing a `Path.Papply` makes that application ill-typed. Reachable via destructive substitution on applicative functors; reproduction attempts surfaced `not a signature` first. Retained on the conservative side. | +| `With_cannot_remove_constrained_type` | ✓ | `with_cannot_remove_constrained_type.res` | Destructive substitution on a constrained type, e.g. `S with type t<'a> := 'a` where `S` has `type t<'a> constraint 'a = int`. | | `With_changes_module_alias` | ☐ (needs build harness) | — | typemod.ml:240. Fires during `with module := M2` substitution when an aliased sub-module inside the constrained signature is affected. ReScript parses `with module N := M2` (destructive substitution), but constructing a sub-module alias chain that gets invalidated requires multiple `.resi` files and a specific shape I couldn't reproduce single-file. | +| `Cannot_eliminate_dependency` | ? | — | typemod.ml:1332. Fires when `Mtype.nondep_supertype` raises `Not_found` during functor-application result-type computation. Reproduction attempts routed through `Incomplete_packed_module` or `escapes its scope`. Retained on the conservative side. | +| `Scoping_pack` | ? | — | typemod.ml:1717. Fires during first-class module packing with `with type` constraints whose constrained type isn't a free `Tvar`. Reproduction attempts routed through `Incomplete_packed_module`. Retained on the conservative side. | | `Repeated_name` | ✓ | `repeated_def_*.res` (multiple) | | | `Non_generalizable` | ✓ | `non_generalizable.res` | | | `Non_generalizable_module` | ✓ | `non_generalizable_module.res` | Nested module containing `let r = ref(None)` — the outer module's `md_type` carries the free `'_weak1` from the inner ref, so `closed_modtype` returns false and the `Sig_module` branch fires. | @@ -319,6 +360,7 @@ FFI / attribute / experimental-feature errors. Source: [bs_syntaxerr.ml:27](../c | `Bs_this_simple_pattern` | ✓ | `bs_this_simple_pattern.res` | `@this` with destructured self pattern. | | `Experimental_feature_not_enabled` | ✓ | `let_unwrap_on_top_level_not_enabled.res` (and other let-unwrap variants) | Currently only `LetUnwrap` is checked. | | `LetUnwrap_not_supported_in_position` | ✓ | `let_unwrap_on_top_level.res`, `let_unwrap_on_not_supported_variant.res` | | +| `Misplaced_label_syntax` | ✓ | `misplaced_label_syntax.res` | Labelled args passed via the operator-identifier syntax `(->)`, `(#=)`, `(##)`, e.g. `\"->"(x, ~b=...)`. | --- diff --git a/tests/build_tests/super_errors/expected/misplaced_label_syntax.res.expected b/tests/build_tests/super_errors/expected/misplaced_label_syntax.res.expected new file mode 100644 index 0000000000..552907d081 --- /dev/null +++ b/tests/build_tests/super_errors/expected/misplaced_label_syntax.res.expected @@ -0,0 +1,9 @@ + + We've found a bug for you! + /.../fixtures/misplaced_label_syntax.res:2:21-27 + + 1 │ let f = (~a, x) => x + a + 2 │ let _ = \"->"(1, ~b=f(~a=2)) + 3 │ + + Label syntax is not supported in this position \ No newline at end of file diff --git a/tests/build_tests/super_errors/expected/with_cannot_remove_constrained_type.res.expected b/tests/build_tests/super_errors/expected/with_cannot_remove_constrained_type.res.expected new file mode 100644 index 0000000000..f57ad8791d --- /dev/null +++ b/tests/build_tests/super_errors/expected/with_cannot_remove_constrained_type.res.expected @@ -0,0 +1,12 @@ + + We've found a bug for you! + /.../fixtures/with_cannot_remove_constrained_type.res:5:17-39 + + 3 │ } + 4 │ + 5 │ module type T = S with type t<'a> := 'a + 6 │ + + Destructive substitutions are not supported for constrained + types (other than when replacing a type constructor with + a type constructor with the same arguments). \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/misplaced_label_syntax.res b/tests/build_tests/super_errors/fixtures/misplaced_label_syntax.res new file mode 100644 index 0000000000..ae964b7c87 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/misplaced_label_syntax.res @@ -0,0 +1,2 @@ +let f = (~a, x) => x + a +let _ = \"->"(1, ~b=f(~a=2)) diff --git a/tests/build_tests/super_errors/fixtures/with_cannot_remove_constrained_type.res b/tests/build_tests/super_errors/fixtures/with_cannot_remove_constrained_type.res new file mode 100644 index 0000000000..4ed2a0f70b --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/with_cannot_remove_constrained_type.res @@ -0,0 +1,5 @@ +module type S = { + type t<'a> constraint 'a = int +} + +module type T = S with type t<'a> := 'a