Skip to content

Commit a747aed

Browse files
SamChou19815meta-codesync[bot]
authored andcommitted
[flow] Introduce opaque underlying type variant to prepare for custom errors
Summary: This diff changes the simple `Type.t option` that's the backing storage of the underlying type of opaque type to a 3-member variant: ``` type underlying_t = | FullyOpaque | NormalUnderlying of { t: TypeTerm.t } | FullyTransparentForCustomError of { custom_error_loc: ALoc.t; t: TypeTerm.t; } ``` , where `FullyOpaque` and `NormalUnderlying` mapped to the previous `None` and `Some` case, and the new `FullyTransparentForCustomError` is introduced for custom errors. `FullyTransparentForCustomError` behaves almost exactly the same as `NormalUnderlying`, except that, as the name suggests, it will always be transparent (while NormalUnderlying is only transparent while the same-file reason check passes). I believe the design balances between not changing type checking behavior while also gives us a reliable marker for types with custom errors. The opaque type design is battle tested, so I believe we should use it instead of patching more reasons. For now, nothing uses the new `FullyTransparentForCustomError` yet. Changelog: [internal] Reviewed By: panagosg7 Differential Revision: D86207093 fbshipit-source-id: b7231197277cedbfc0f502200de9a41a416d4ae9
1 parent 77bfd68 commit a747aed

19 files changed

Lines changed: 322 additions & 54 deletions

src/typing/annotation_inference.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,9 +704,16 @@ module rec ConsGen : S = struct
704704
(****************)
705705
| (OpaqueT (_, { upper_t = Some upper_t; _ }), Annot_ToStringT { reason; _ }) ->
706706
elab_t cx upper_t (Annot_ToStringT { orig_t = Some t; reason })
707-
| (OpaqueT (r, { underlying_t = Some t; _ }), _)
707+
| (OpaqueT (r, { underlying_t = Opaque.NormalUnderlying { t }; _ }), _)
708708
when ALoc.source (loc_of_reason r) = ALoc.source (def_loc_of_reason r) ->
709709
elab_t cx ~seen t op
710+
| ( OpaqueT
711+
( _,
712+
{ underlying_t = Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ }; _ }
713+
),
714+
_
715+
) ->
716+
elab_t cx ~seen t op
710717
(********)
711718
(* Keys *)
712719
(********)

src/typing/concrete_type_eq.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ let rec swap_reason t2 t1 =
2323
) ->
2424
let underlying_t =
2525
match (repr1, repr2) with
26-
| (Some t1, Some t2) -> Some (swap_reason t2 t1)
26+
| ( Opaque.FullyTransparentForCustomError { t = t1; custom_error_loc = _ },
27+
Opaque.FullyTransparentForCustomError { t = t2; custom_error_loc }
28+
) ->
29+
Opaque.FullyTransparentForCustomError { custom_error_loc; t = swap_reason t2 t1 }
30+
| (Opaque.NormalUnderlying { t = t1 }, Opaque.NormalUnderlying { t = t2 }) ->
31+
Opaque.NormalUnderlying { t = swap_reason t2 t1 }
2732
| _ -> repr2
2833
in
2934
let lower_t =

src/typing/convertTypes.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,10 @@ and type_to_json : Context.t -> int -> t -> json =
200200
("opaque_id", JSON_String (Opaque.string_of_id opaquetype.opaque_id));
201201
( "underlying_t",
202202
match opaquetype.underlying_t with
203-
| None -> JSON_Null
204-
| Some t -> type_to_json cx (depth - 1) t
203+
| Opaque.FullyOpaque -> JSON_Null
204+
| Opaque.FullyTransparentForCustomError { t; _ }
205+
| Opaque.NormalUnderlying { t; _ } ->
206+
type_to_json cx (depth - 1) t
205207
);
206208
( "super_t",
207209
match opaquetype.upper_t with

src/typing/debug_js.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,11 @@ let rec dump_t_ (depth, tvars) cx t =
269269
)
270270
)
271271
)
272-
(Base.Option.value_map underlying_t ~default:"" ~f:(fun t -> spf " (%s)" (kid t)))
272+
(match underlying_t with
273+
| Opaque.NormalUnderlying { t } -> spf " (%s)" (kid t)
274+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc } ->
275+
spf " (%s, custom_error_loc=%s)" (kid t) (ALoc.debug_to_string custom_error_loc)
276+
| Opaque.FullyOpaque -> "")
273277
)
274278
t
275279
| OptionalT { reason = _; type_ = arg; use_desc = _ } -> p ~extra:(kid arg) t

src/typing/flow_js.ml

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,14 +1411,25 @@ struct
14111411
( _,
14121412
{
14131413
opaque_id = Opaque.UserDefinedOpaqueTypeId (opaque_id, _);
1414-
underlying_t = Some t;
1414+
underlying_t = Opaque.NormalUnderlying { t };
14151415
_;
14161416
}
14171417
),
14181418
ToStringT { reason; t_out; _ }
14191419
)
14201420
when ALoc.source (opaque_id :> ALoc.t) = Some (Context.file cx) ->
14211421
rec_flow cx trace (t, ToStringT { orig_t = Some l; reason; t_out })
1422+
| ( OpaqueT
1423+
( _,
1424+
{
1425+
opaque_id = Opaque.UserDefinedOpaqueTypeId _;
1426+
underlying_t = Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ };
1427+
_;
1428+
}
1429+
),
1430+
ToStringT { reason; t_out; _ }
1431+
) ->
1432+
rec_flow cx trace (t, ToStringT { orig_t = Some l; reason; t_out })
14221433
(* Use the upper bound of OpaqueT if it's available, for operations that must be
14231434
* performed on some concretized types. *)
14241435
| (OpaqueT (_, { upper_t = Some t; _ }), ObjKitT _)
@@ -1434,14 +1445,25 @@ struct
14341445
( _,
14351446
{
14361447
opaque_id = Opaque.UserDefinedOpaqueTypeId (opaque_id, _);
1437-
underlying_t = Some t;
1448+
underlying_t = Opaque.NormalUnderlying { t; _ };
14381449
_;
14391450
}
14401451
),
14411452
_
14421453
)
14431454
when ALoc.source (opaque_id :> ALoc.t) = Some (Context.file cx) ->
14441455
rec_flow cx trace (t, u)
1456+
| ( OpaqueT
1457+
( _,
1458+
{
1459+
opaque_id = Opaque.UserDefinedOpaqueTypeId _;
1460+
underlying_t = Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ };
1461+
_;
1462+
}
1463+
),
1464+
_
1465+
) ->
1466+
rec_flow cx trace (t, u)
14451467
(*****************************************************)
14461468
(* keys (NOTE: currently we only support string keys *)
14471469
(*****************************************************)
@@ -5528,10 +5550,17 @@ struct
55285550
)
55295551
)
55305552
| OpaqueT (r, ({ underlying_t; lower_t; upper_t; opaque_type_args; _ } as opaquetype)) ->
5553+
let underlying_t =
5554+
match underlying_t with
5555+
| Opaque.FullyOpaque -> Opaque.FullyOpaque
5556+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc } ->
5557+
Opaque.FullyTransparentForCustomError { t = only_any t; custom_error_loc }
5558+
| Opaque.NormalUnderlying { t } -> Opaque.NormalUnderlying { t = only_any t }
5559+
in
55315560
let opaquetype =
55325561
{
55335562
opaquetype with
5534-
underlying_t = Base.Option.(underlying_t >>| only_any);
5563+
underlying_t;
55355564
lower_t = Base.Option.(lower_t >>| only_any);
55365565
upper_t = Base.Option.(upper_t >>| only_any);
55375566
opaque_type_args =
@@ -6412,7 +6441,13 @@ struct
64126441
* lower_t to be inspectable *)
64136442
eagerly_eval_destructor_if_resolved cx ~trace use_op reason t d tvar
64146443
in
6415-
let underlying_t = Base.Option.map ~f:eval_t underlying_t in
6444+
let underlying_t =
6445+
match underlying_t with
6446+
| Opaque.FullyOpaque -> Opaque.FullyOpaque
6447+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc } ->
6448+
Opaque.FullyTransparentForCustomError { t = eval_t t; custom_error_loc }
6449+
| Opaque.NormalUnderlying { t } -> Opaque.NormalUnderlying { t = eval_t t }
6450+
in
64166451
let lower_t = Base.Option.map ~f:eval_t lower_t in
64176452
let upper_t = Base.Option.map ~f:eval_t upper_t in
64186453
let opaque_t = OpaqueT (r, { opaquetype with underlying_t; lower_t; upper_t }) in
@@ -6438,7 +6473,7 @@ struct
64386473
( _,
64396474
{
64406475
opaque_id = Opaque.UserDefinedOpaqueTypeId (opaque_id, _);
6441-
underlying_t = Some t;
6476+
underlying_t = Opaque.NormalUnderlying { t };
64426477
_;
64436478
}
64446479
);
@@ -6458,13 +6493,57 @@ struct
64586493
(GenericT { bound = t; reason = r; id; name; no_infer })
64596494
d
64606495
tout
6496+
| ( GenericT
6497+
{
6498+
bound =
6499+
OpaqueT
6500+
( _,
6501+
{
6502+
opaque_id = Opaque.UserDefinedOpaqueTypeId _;
6503+
underlying_t =
6504+
Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ };
6505+
_;
6506+
}
6507+
);
6508+
reason = r;
6509+
id;
6510+
name;
6511+
no_infer;
6512+
},
6513+
_
6514+
) ->
6515+
eval_destructor
6516+
cx
6517+
~trace
6518+
use_op
6519+
reason
6520+
(GenericT { bound = t; reason = r; id; name; no_infer })
6521+
d
6522+
tout
64616523
| (OpaqueT (r, opaquetype), ReactDRO _) -> destruct_and_preserve_opaque_t r opaquetype
64626524
| ( OpaqueT
6463-
(_, { opaque_id = Opaque.UserDefinedOpaqueTypeId (id, _); underlying_t = Some t; _ }),
6525+
( _,
6526+
{
6527+
opaque_id = Opaque.UserDefinedOpaqueTypeId (id, _);
6528+
underlying_t = Opaque.NormalUnderlying { t };
6529+
_;
6530+
}
6531+
),
64646532
_
64656533
)
64666534
when ALoc.source (id :> ALoc.t) = Some (Context.file cx) ->
64676535
eval_destructor cx ~trace use_op reason t d tout
6536+
| ( OpaqueT
6537+
( _,
6538+
{
6539+
opaque_id = Opaque.UserDefinedOpaqueTypeId _;
6540+
underlying_t = Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ };
6541+
_;
6542+
}
6543+
),
6544+
_
6545+
) ->
6546+
eval_destructor cx ~trace use_op reason t d tout
64686547
(* Specialize TypeAppTs before evaluating them so that we can handle special
64696548
cases. Like the union case below. mk_typeapp_instance will return an AnnotT
64706549
which will be fully resolved using the AnnotT case above. *)
@@ -6836,7 +6915,7 @@ struct
68366915
( reason,
68376916
{
68386917
opaque_id = Opaque.StuckEval stuck_eval_kind;
6839-
underlying_t = None;
6918+
underlying_t = Opaque.FullyOpaque;
68406919
lower_t = None;
68416920
upper_t;
68426921
opaque_type_args;
@@ -9195,11 +9274,27 @@ struct
91959274
UnionT (r, rep)
91969275
| OpaqueT (r, opaquetype) ->
91979276
let r = mod_reason r in
9277+
let underlying_t =
9278+
match opaquetype.underlying_t with
9279+
| Opaque.FullyOpaque -> opaquetype.underlying_t
9280+
| Opaque.NormalUnderlying { t } ->
9281+
let t' = recurse seen t in
9282+
if t == t' then
9283+
opaquetype.underlying_t
9284+
else
9285+
Opaque.NormalUnderlying { t = t' }
9286+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc } ->
9287+
let t' = recurse seen t in
9288+
if t == t' then
9289+
opaquetype.underlying_t
9290+
else
9291+
Opaque.FullyTransparentForCustomError { t = t'; custom_error_loc }
9292+
in
91989293
OpaqueT
91999294
( r,
92009295
{
92019296
opaquetype with
9202-
underlying_t = OptionUtils.ident_map (recurse seen) opaquetype.underlying_t;
9297+
underlying_t;
92039298
lower_t = OptionUtils.ident_map (recurse seen) opaquetype.lower_t;
92049299
upper_t = OptionUtils.ident_map (recurse seen) opaquetype.upper_t;
92059300
}

src/typing/implicit_instantiation.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,7 @@ module Kit (FlowJs : Flow_common.S) (Instantiation_helper : Flow_js_utils.Instan
18141814
( reason,
18151815
{
18161816
opaque_id = Opaque.(StuckEval StuckEvalForConditionalType);
1817-
underlying_t = None;
1817+
underlying_t = Opaque.FullyOpaque;
18181818
lower_t = None;
18191819
upper_t = Some bound;
18201820
opaque_type_args;

src/typing/members.ml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,15 @@ let rec extract_type cx this_t =
580580
| DefT (reason, SymbolT) -> get_builtin_type cx reason "Symbol" |> extract_type cx
581581
| DefT (_, ReactAbstractComponentT _) as t -> Success t
582582
| DefT (_, RendersT _) as t -> Success t
583-
| OpaqueT (_, { underlying_t = Some t; _ })
583+
| OpaqueT
584+
( _,
585+
{
586+
underlying_t =
587+
( Opaque.NormalUnderlying { t }
588+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ } );
589+
_;
590+
}
591+
)
584592
| OpaqueT (_, { upper_t = Some t; _ }) ->
585593
extract_type cx t
586594
| DefT (reason, ArrT arrtype) ->

src/typing/merge_js.ml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,16 @@ let detect_sketchy_null_checks cx tast =
6767
(* Ignore AnyTs for sketchy null checks; otherwise they'd always trigger the lint. *)
6868
| AnyT _ -> cur_checks
6969
| GenericT { bound = t; _ }
70-
| OpaqueT (_, { underlying_t = Some t; _ })
71-
| OpaqueT (_, { underlying_t = None; upper_t = Some t; _ }) ->
70+
| OpaqueT
71+
( _,
72+
{
73+
underlying_t =
74+
( Opaque.NormalUnderlying { t }
75+
| Opaque.FullyTransparentForCustomError { t; custom_error_loc = _ } );
76+
_;
77+
}
78+
)
79+
| OpaqueT (_, { underlying_t = Opaque.FullyOpaque; upper_t = Some t; _ }) ->
7280
make_checks seen cur_checks loc t
7381
| MaybeT (r, t) ->
7482
let acc = make_checks seen cur_checks loc t in
@@ -732,7 +740,7 @@ let enforce_optimize cx loc t =
732740
( reason,
733741
{
734742
opaque_id = Opaque.InternalEnforceUnionOptimized;
735-
underlying_t = None;
743+
underlying_t = Opaque.FullyOpaque;
736744
lower_t = None;
737745
upper_t = None;
738746
opaque_type_args = [];

src/typing/predicate_kit.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,13 @@ and intersect =
608608
let upper_t =
609609
Some (Base.Option.value_map upper_t ~default:t2 ~f:(fun t -> intersect cx t t2))
610610
in
611-
let underlying_t = Base.Option.map ~f:(fun t -> intersect cx t t2) underlying_t in
611+
let underlying_t =
612+
match underlying_t with
613+
| Opaque.FullyOpaque -> Opaque.FullyOpaque
614+
| Opaque.FullyTransparentForCustomError { custom_error_loc; t } ->
615+
Opaque.FullyTransparentForCustomError { custom_error_loc; t = intersect cx t t2 }
616+
| Opaque.NormalUnderlying { t } -> Opaque.NormalUnderlying { t = intersect cx t t2 }
617+
in
612618
Some (OpaqueT (r, { opaquetype with underlying_t; upper_t }))
613619
| _ -> None
614620
in

src/typing/react_rules.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ let check_ref_use cx rrid in_hook var_reason kind t =
3535
when Base.Option.value_map ~default:false ~f:(( = ) opaque_id) rrid ->
3636
[Error_message.EReactRefInRender { usage = var_reason; kind; in_hook }]
3737
| OpaqueT (_, { underlying_t; upper_t; _ }) ->
38-
Base.Option.value_map ~default:[] ~f:recur underlying_t
38+
begin
39+
match underlying_t with
40+
| Type.Opaque.NormalUnderlying { t } -> recur t
41+
| Type.Opaque.FullyTransparentForCustomError { t; _ } -> recur t
42+
| Type.Opaque.FullyOpaque -> []
43+
end
3944
@ Base.Option.value_map ~default:[] ~f:recur upper_t
4045
| OpenT (_, id) when ISet.mem id seen -> []
4146
| OpenT (_, id) ->
@@ -106,9 +111,10 @@ let hook_callee cx t =
106111
| DefT (r, FunT (_, { effect_ = ArbitraryEffect; _ })) -> NotHookCallee (set_of_reason r)
107112
| OpaqueT (_, { underlying_t; upper_t; _ }) -> begin
108113
match (underlying_t, upper_t) with
109-
| (Some t, _)
110-
| (None, Some t) ->
114+
| (Type.Opaque.NormalUnderlying { t }, _)
115+
| (Type.Opaque.FullyTransparentForCustomError { t; _ }, _) ->
111116
recur t
117+
| (Type.Opaque.FullyOpaque, Some t) -> recur t
112118
| _ -> AnyCallee
113119
end
114120
| OpenT (_, id) when ISet.mem id seen -> AnyCallee

0 commit comments

Comments
 (0)