Skip to content

Commit 4c8c646

Browse files
committed
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.
1 parent 20077be commit 4c8c646

14 files changed

Lines changed: 245 additions & 102 deletions

compiler/frontend/ast_core_type.ml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,12 @@ let list_of_arrow (ty : t) : t * Parsetree.arg list =
136136
match ty.ptyp_desc with
137137
| Ptyp_arrow {arg; ret; arity} when arity = None || acc = [] ->
138138
aux ret (arg :: acc)
139-
| Ptyp_poly (_, ty) ->
140-
Location.raise_errorf ~loc:ty.ptyp_loc "Unhandled poly type"
139+
| Ptyp_poly _ ->
140+
(* unreachable: this would require an inline Ptyp_poly inside an
141+
external's arrow chain. The ReScript parser misreads inline `'a.`
142+
prefix syntax as the deprecated uncurried `(. …)` form and rejects
143+
it, so the typer never sees the required AST shape. *)
144+
assert false
141145
| _ -> (ty, List.rev acc)
142146
in
143147
aux ty []

compiler/frontend/bs_syntaxerr.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type error =
4646
| Bs_this_simple_pattern
4747
| Experimental_feature_not_enabled of Experimental_features.feature
4848
| LetUnwrap_not_supported_in_position of [`Toplevel | `Unsupported_type]
49+
| Misplaced_label_syntax
4950

5051
let pp_error fmt err =
5152
Format.pp_print_string fmt
@@ -86,7 +87,8 @@ let pp_error fmt err =
8687
| `Toplevel -> "`let?` is not allowed for top-level bindings."
8788
| `Unsupported_type ->
8889
"`let?` is only supported in let bindings targeting the `result` or \
89-
`option` type."))
90+
`option` type.")
91+
| Misplaced_label_syntax -> "Label syntax is not supported in this position")
9092

9193
type exn += Error of Location.t * error
9294

@@ -103,5 +105,4 @@ let optional_err loc (lbl : Asttypes.arg_label) =
103105
| _ -> ()
104106

105107
let err_if_label loc (lbl : Asttypes.arg_label) =
106-
if lbl <> Nolabel then
107-
Location.raise_errorf ~loc "Label syntax is not supported in this position"
108+
if lbl <> Nolabel then raise (Error (loc, Misplaced_label_syntax))

compiler/frontend/bs_syntaxerr.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type error =
4646
| Bs_this_simple_pattern
4747
| Experimental_feature_not_enabled of Experimental_features.feature
4848
| LetUnwrap_not_supported_in_position of [`Toplevel | `Unsupported_type]
49+
| Misplaced_label_syntax
4950

5051
val err : Location.t -> error -> 'a
5152

compiler/ml/env.ml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,13 +1616,16 @@ and check_usage loc id warn tbl =
16161616
and check_value_name name loc =
16171617
(* Note: we could also check here general validity of the
16181618
identifier, to protect against bad identifiers forged by -pp or
1619-
-ppx preprocessors. *)
1620-
if name = "->" then
1621-
Location.raise_errorf ~loc "'%s' is not a valid value identifier." name
1619+
-ppx preprocessors.
1620+
1621+
Both guarded paths below are unreachable: the ReScript parser never
1622+
emits value identifiers named "->" or containing "#" — both shapes
1623+
are rejected as syntax errors. *)
1624+
ignore loc;
1625+
if name = "->" then assert false
16221626
else if String.length name > 0 && name.[0] = '#' then
16231627
for i = 1 to String.length name - 1 do
1624-
if name.[i] = '#' then
1625-
Location.raise_errorf ~loc "'%s' is not a valid value identifier." name
1628+
if name.[i] = '#' then assert false
16261629
done
16271630

16281631
and store_value ?check id decl env =

compiler/ml/typecore.ml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,10 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp
13361336
type_pat ~explode:0 p expected_ty k
13371337
(* TODO: record 'extra' to remember about interval *)
13381338
| Ppat_interval _ ->
1339-
Location.raise_errorf ~loc
1340-
"Only character intervals are supported in patterns."
1339+
(* unreachable: the ReScript parser (compiler/syntax/src/res_core.ml) has
1340+
no construction site for Ppat_interval — interval patterns are OCaml
1341+
syntax not part of the ReScript grammar *)
1342+
assert false
13411343
| Ppat_tuple spl ->
13421344
assert (List.length spl >= 2);
13431345
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)
30883090
Types.val_loc = loc;
30893091
} env ~check:(fun s -> Warnings.Unused_for_index s)
30903092
| _ ->
3091-
Location.raise_errorf ~loc:param.ppat_loc
3092-
"Invalid for...of binding: only variables and _ are allowed."
3093+
(* unreachable: the parser's normalize_for_of_pattern
3094+
(compiler/syntax/src/res_core.ml:3841) catches every non-var,
3095+
non-`_` pattern, emits a syntax error, and replaces the pattern
3096+
with Ppat_any before the typer runs *)
3097+
assert false
30933098
in
30943099
let body =
30953100
with_depth loop_depth (fun () ->
@@ -3122,8 +3127,11 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected)
31223127
Types.val_loc = loc;
31233128
} env ~check:(fun s -> Warnings.Unused_for_index s)
31243129
| _ ->
3125-
Location.raise_errorf ~loc:param.ppat_loc
3126-
"Invalid for...of binding: only variables and _ are allowed."
3130+
(* unreachable: the parser's normalize_for_of_pattern
3131+
(compiler/syntax/src/res_core.ml:3841) catches every non-var,
3132+
non-`_` pattern, emits a syntax error, and replaces the pattern
3133+
with Ppat_any before the typer runs *)
3134+
assert false
31273135
in
31283136
let body =
31293137
with_depth loop_depth (fun () ->
@@ -3849,6 +3857,12 @@ and type_application ~context total_app env funct (sargs : sargs) :
38493857
(Error
38503858
(sarg1.pexp_loc, env, Apply_wrong_label (l1, funct.exp_type)))
38513859
else
3860+
(* Originally split between Apply_wrong_label (label not in
3861+
ty_fun) and Incoherent_label_order (label in ty_fun but at
3862+
a different position). The latter is unreachable: modern
3863+
arity-aware unify in type_function eagerly compares against
3864+
ty_expected, raising Expr_type_clash before this branch
3865+
fires. Both label problems now surface as Apply_wrong_label. *)
38523866
raise
38533867
(Error (sarg1.pexp_loc, env, Apply_wrong_label (l1, ty_res)))
38543868
| _ ->

compiler/ml/typedecl.ml

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ let enter_type rec_flag env sdecl id =
108108
in
109109
Env.add_type ~check:true id decl env
110110

111-
let update_type temp_env env id loc =
111+
let update_type temp_env env id _loc =
112112
let path = Path.Pident id in
113113
let decl = Env.find_type path temp_env in
114114
match decl.type_manifest with
@@ -117,8 +117,10 @@ let update_type temp_env env id loc =
117117
let params = List.map (fun _ -> Ctype.newvar ()) decl.type_params in
118118
try Ctype.unify env (Ctype.newconstr path params) ty
119119
with Ctype.Unify _ ->
120-
Location.raise_errorf ~loc
121-
"This type constructor expands to an incompatible type.")
120+
(* unreachable: every recursive abbreviation shape that would reach
121+
this unify failure hits Cycle_in_def in check_recursive_type
122+
(see line ~902 below) before check_coherence runs *)
123+
assert false)
122124

123125
(* We use the Ctype.expand_head_opt version of expand_head to get access
124126
to the manifest type of private abbreviations. *)
@@ -170,7 +172,7 @@ let is_fixed_type sd =
170172
&& sd.ptype_private = Private && has_row_var sty
171173

172174
(* Set the row variable in a fixed type *)
173-
let set_fixed_row env loc p decl =
175+
let set_fixed_row env _loc p decl =
174176
let tm =
175177
match decl.type_manifest with
176178
| None -> assert false
@@ -184,10 +186,16 @@ let set_fixed_row env loc p decl =
184186
if Btype.static_row row then Btype.newgenty Tnil else row.row_more
185187
| Tobject (ty, _) -> snd (Ctype.flatten_fields ty)
186188
| _ ->
187-
Location.raise_errorf ~loc "This fixed type is not an object or variant"
189+
(* unreachable: gated by `is_fixed_type decl`, which only returns true
190+
when the syntactic manifest carries an open polymorphic-variant or
191+
object row. `expand_head` preserves that row, so the manifest's
192+
desc is always Tvariant or Tobject here. *)
193+
assert false
188194
in
189195
if not (Btype.is_Tvar rv) then
190-
Location.raise_errorf ~loc "This fixed type has no row variable";
196+
(* unreachable: same is_fixed_type invariant — the row is always a Tvar
197+
(or extended-Tvar) when is_fixed_type passes *)
198+
assert false;
191199
rv.desc <- Tconstr (p, decl.type_params, ref Mnil)
192200

193201
(* Translate one type declaration *)
@@ -978,10 +986,14 @@ let check_recursion env loc path decl to_check =
978986
match ty.desc with
979987
| Tconstr (path', args', _) ->
980988
(if Path.same path path' then (
981-
if not (Ctype.equal env false args args') then
982-
Location.raise_errorf ~loc
983-
"In the definition of %s, recursive type parameters differ."
984-
(Path.name cpath))
989+
if not (Ctype.equal env false args args') then (
990+
(* unreachable: check_regular runs only on abbreviations,
991+
and every recursive-abbreviation shape hits Cycle_in_def
992+
in the earlier check_recursive_type pass before reaching
993+
here. Variant constructors with non-uniform recursion
994+
(`type rec t<'a> = T(t<int>)`) don't trigger check_regular. *)
995+
ignore cpath;
996+
assert false))
985997
else if
986998
(* Attempt to expand a type abbreviation if:
987999
1- [to_check path'] holds
@@ -1234,7 +1246,7 @@ let for_constr = function
12341246
(fun {Types.ld_mutable; ld_type} -> (ld_mutable = Mutable, ld_type))
12351247
l
12361248

1237-
let compute_variance_gadt env check ((required, loc) as rloc) decl
1249+
let compute_variance_gadt env check ((required, _loc) as rloc) decl
12381250
(tl, ret_type_opt) =
12391251
match ret_type_opt with
12401252
| None ->
@@ -1255,9 +1267,11 @@ let compute_variance_gadt env check ((required, loc) as rloc) decl
12551267
| fv :: fv2 ->
12561268
(* fv1 @ fv2 = free_variables of other parameters *)
12571269
if (c || n) && constrained (fv1 @ fv2) ty then
1258-
Location.raise_errorf ~loc
1259-
"In this GADT definition, the variance of some parameter \
1260-
cannot be checked.";
1270+
(* unreachable: this would fire on a GADT parameter that's
1271+
`_` (anonymous). ReScript's parser rejects `_` in
1272+
`type t<...>` parameter positions, so the typer never
1273+
sees the required AST shape. *)
1274+
assert false;
12611275
(fv :: fv1, fv2))
12621276
([], fvl) tyl required
12631277
in
@@ -1882,8 +1896,12 @@ let transl_value_decl env loc valdecl =
18821896
val_attributes = valdecl.pval_attributes;
18831897
}
18841898
| [] ->
1885-
Location.raise_errorf ~loc:valdecl.pval_loc
1886-
"Value declarations are only allowed in signatures"
1899+
(* unreachable: `pval_prim = []` outside a signature can only arise
1900+
from the parser's `external` recovery, which sets `prim = []`
1901+
*after* emitting a syntax error, so the typer never sees the
1902+
declaration. A bare `val x: int` in a .res is also rejected at
1903+
parse time. *)
1904+
assert false
18871905
| _ ->
18881906
let arity, from_constructor = parse_arity env valdecl.pval_type ty in
18891907
let prim = Primitive.parse_declaration valdecl ~arity ~from_constructor in
@@ -1897,8 +1915,12 @@ let transl_value_decl env loc valdecl =
18971915
&& (prim.prim_name = ""
18981916
|| (prim.prim_name.[0] <> '%' && prim.prim_name.[0] <> '#'))
18991917
then
1900-
Location.raise_errorf ~loc:valdecl.pval_type.ptyp_loc
1901-
"External identifiers must be functions";
1918+
(* unreachable: Primitive.parse_declaration always assigns the
1919+
magic 20-byte prim_native_name encoding to externals; the
1920+
`prim_native_name = ""` precondition can't be satisfied alongside
1921+
`prim_arity = 0` from any externals that survive parsing. Empty
1922+
prim names are rejected earlier with `Not a valid global name`. *)
1923+
assert false;
19021924
{
19031925
val_type = ty;
19041926
val_kind = Val_prim prim;

compiler/ml/typemod.ml

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,23 @@ open Format
2424
type error =
2525
| Cannot_apply of module_type
2626
| Not_included of Includemod.error list
27+
| Cannot_eliminate_dependency of module_type
2728
| Signature_expected
2829
| Structure_expected of module_type
2930
| With_no_component of Longident.t
3031
| With_mismatch of Longident.t * Includemod.error list
32+
| With_makes_applicative_functor_ill_typed of
33+
Longident.t * Path.t * Includemod.error list
3134
| With_changes_module_alias of Longident.t * Ident.t * Path.t
35+
| With_cannot_remove_constrained_type
3236
| Repeated_name of string * string * Warnings.loc
3337
| Non_generalizable of type_expr
3438
| Non_generalizable_module of module_type
3539
| Interface_not_compiled of string
3640
| Not_allowed_in_functor_body
3741
| Not_a_packed_module of type_expr
3842
| Incomplete_packed_module of type_expr
43+
| Scoping_pack of Longident.t * type_expr
3944
| Recursive_module_require_explicit_type
4045
| Apply_generative
4146
| Cannot_scrape_alias of Path.t
@@ -246,13 +251,12 @@ let check_usage_of_path_of_substituted_item paths env signature ~loc ~lid =
246251
let env = !env in
247252
try retype_applicative_functor_type ~loc env funct arg
248253
with Includemod.Error explanation ->
249-
Location.raise_errorf ~loc
250-
"@[<v>@[This `with' constraint on %a makes the applicative \
251-
functor type %s ill-typed in the constrained \
252-
signature:@]@ %a@]"
253-
Printtyp.longident lid.txt
254-
(Path.name referenced_path)
255-
Includemod.report_error explanation));
254+
raise
255+
(Error
256+
( loc,
257+
env,
258+
With_makes_applicative_functor_ill_typed
259+
(lid.txt, referenced_path, explanation) ))));
256260
}
257261
in
258262
iterator.Btype.it_signature iterator signature;
@@ -435,11 +439,8 @@ let merge_constraint initial_env loc sg constr =
435439
in
436440
let params = tdecl.typ_type.type_params in
437441
if params_are_constrained params then
438-
Location.raise_errorf ~loc
439-
"@[<v>Destructive substitutions are not supported for \
440-
constrained types (other than when replacing a type \
441-
constructor with a type constructor with the same \
442-
arguments).@]";
442+
raise
443+
(Error (loc, initial_env, With_cannot_remove_constrained_type));
443444
fun s path -> Subst.add_type_function path ~params ~body s
444445
in
445446
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 =
13291330
(Env.add_module ~arg:true param arg.mod_type env)
13301331
param mty_res
13311332
with Not_found ->
1332-
Location.raise_errorf ~loc:smod.pmod_loc
1333-
"@[This functor has type@ %a@ The parameter cannot be \
1334-
eliminated in the result type.@ Bind the argument to a \
1335-
module identifier.@]"
1336-
Printtyp.modtype mty_functor)
1333+
raise
1334+
(Error
1335+
(smod.pmod_loc, env, Cannot_eliminate_dependency mty_functor))
1336+
)
13371337
in
13381338
rm
13391339
{
@@ -1714,10 +1714,7 @@ let type_package env m p nl =
17141714
(fun n ty ->
17151715
try Ctype.unify env ty (Ctype.newvar ())
17161716
with Ctype.Unify _ ->
1717-
Location.raise_errorf ~loc:m.pmod_loc
1718-
"@[The type %a in this module cannot be exported.@ Its type \
1719-
contains local dependencies:@ %a@]"
1720-
Printtyp.longident n Printtyp.type_expr ty)
1717+
raise (Error (m.pmod_loc, env, Scoping_pack (n, ty))))
17211718
nl tl';
17221719
(wrap_constraint env modl mty Tmodtype_implicit, tl')
17231720

@@ -1833,6 +1830,16 @@ let report_error ppf = function
18331830
"@[<v>@[In this `with' constraint, the new definition of %a@ does not \
18341831
match its original definition@ in the constrained signature:@]@ %a@]"
18351832
longident lid Includemod.report_error explanation
1833+
| With_makes_applicative_functor_ill_typed (lid, path, explanation) ->
1834+
fprintf ppf
1835+
"@[<v>@[This `with' constraint on %a makes the applicative functor @ \
1836+
type %s ill-typed in the constrained signature:@]@ %a@]"
1837+
longident lid (Path.name path) Includemod.report_error explanation
1838+
| With_cannot_remove_constrained_type ->
1839+
fprintf ppf
1840+
"@[<v>Destructive substitutions are not supported for constrained @ \
1841+
types (other than when replacing a type constructor with @ a type \
1842+
constructor with the same arguments).@]"
18361843
| With_changes_module_alias (lid, id, path) ->
18371844
fprintf ppf
18381845
"@[<v>@[This `with' constraint on %a changes %s, which is aliased @ in \
@@ -1866,6 +1873,11 @@ let report_error ppf = function
18661873
| Interface_not_compiled intf_name ->
18671874
fprintf ppf "@[Could not find the .cmi file for interface@ %a.@]"
18681875
Location.print_filename intf_name
1876+
| Cannot_eliminate_dependency mty ->
1877+
fprintf ppf
1878+
"@[This functor has type@ %a@ The parameter cannot be eliminated in the \
1879+
result type.@ Bind the argument to a module identifier.@]"
1880+
modtype mty
18691881
| Not_allowed_in_functor_body ->
18701882
fprintf ppf "@[This expression creates fresh types.@ %s@]"
18711883
"It is not allowed inside applicative functors."
@@ -1875,6 +1887,9 @@ let report_error ppf = function
18751887
| Incomplete_packed_module ty ->
18761888
fprintf ppf "The type of this packed module contains variables:@ %a"
18771889
type_expr ty
1890+
| Scoping_pack (lid, ty) ->
1891+
fprintf ppf "The type %a in this module cannot be exported.@ " longident lid;
1892+
fprintf ppf "Its type contains local dependencies:@ %a" type_expr ty
18781893
| Recursive_module_require_explicit_type ->
18791894
fprintf ppf "Recursive modules require an explicit module type."
18801895
| Apply_generative ->

compiler/ml/typemod.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,23 @@ val save_signature :
6464
type error =
6565
| Cannot_apply of module_type
6666
| Not_included of Includemod.error list
67+
| Cannot_eliminate_dependency of module_type
6768
| Signature_expected
6869
| Structure_expected of module_type
6970
| With_no_component of Longident.t
7071
| With_mismatch of Longident.t * Includemod.error list
72+
| With_makes_applicative_functor_ill_typed of
73+
Longident.t * Path.t * Includemod.error list
7174
| With_changes_module_alias of Longident.t * Ident.t * Path.t
75+
| With_cannot_remove_constrained_type
7276
| Repeated_name of string * string * Warnings.loc
7377
| Non_generalizable of type_expr
7478
| Non_generalizable_module of module_type
7579
| Interface_not_compiled of string
7680
| Not_allowed_in_functor_body
7781
| Not_a_packed_module of type_expr
7882
| Incomplete_packed_module of type_expr
83+
| Scoping_pack of Longident.t * type_expr
7984
| Recursive_module_require_explicit_type
8085
| Apply_generative
8186
| Cannot_scrape_alias of Path.t

0 commit comments

Comments
 (0)