Skip to content

Commit a4ee5ed

Browse files
Michael Thomasfacebook-github-bot
authored andcommitted
Propagate solutions rather than rendering
Summary: At the moment we always print the solution to a type variable when rendering the reason of a type appearing in the claim. This is inconsistent with legacy errors which always capture the outermost reason - we replicate this by recursing in the outermost reason in a `Flow` but `Solved` currently ignore this. This diff changes the behavior so that we propagate solutions but only use them when the outermost reason corresponds to a type variable Reviewed By: patriciamckenzie Differential Revision: D63829943 fbshipit-source-id: ea28687016e97eb32d5449a39f7fdd3e1314d8d4
1 parent 5deffe3 commit a4ee5ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+190
-48
lines changed

hphp/hack/src/typing/typing_reason.ml

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,24 +2079,47 @@ let to_pos : type ph. ph t_ -> Pos_or_decl.t =
20792079
(* Translate a reason to a (pos, string) list, suitable for error_l. This
20802080
* previously returned a string, however the need to return multiple lines with
20812081
* multiple locations meant that it needed to more than convert to a string *)
2082-
let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
2083-
fun prefix r ->
2082+
let rec to_string_help :
2083+
type a.
2084+
string -> locl_phase t_ Tvid.Map.t -> a t_ -> (Pos_or_decl.t * string) list
2085+
=
2086+
fun prefix solutions r ->
20842087
let p = to_pos r in
20852088
match r with
20862089
| No_reason -> [(p, prefix)]
20872090
| Missing_field -> [(p, prefix)]
20882091
| Invalid -> [(p, prefix)]
2092+
| From_witness_locl
2093+
(Type_variable_generics (_, _, _, tvid) | Type_variable (_, tvid))
2094+
when Tvid.Map.mem tvid solutions ->
2095+
let r = Tvid.Map.find tvid solutions in
2096+
let solutions = Tvid.Map.remove tvid solutions in
2097+
to_string_help prefix solutions r
20892098
| From_witness_locl witness -> [witness_locl_to_string prefix witness]
20902099
| From_witness_decl witness -> [witness_decl_to_string prefix witness]
2091-
| Flow { from = r; _ }
20922100
| Upper_bound { bound = r; _ }
20932101
| Lower_bound { bound = r; _ }
20942102
| Axiom { next = r; _ }
20952103
| Def (_, r)
20962104
| Prj_both { sub_prj = r; _ }
2097-
| Prj_one { part = r; _ }
2098-
| Solved { solution = r; _ } ->
2099-
to_string prefix r
2105+
| Prj_one { part = r; _ } ->
2106+
to_string_help prefix solutions r
2107+
(* If we don't have a solution for a type variable use the origin of the flow *)
2108+
| Flow { from = r; _ } when Tvid.Map.is_empty solutions ->
2109+
to_string_help prefix solutions r
2110+
(* otherwise, follow the flow until we reach the type variable *)
2111+
| Flow { from; into; _ } ->
2112+
(match from with
2113+
| From_witness_locl
2114+
(Type_variable_generics (_, _, _, tvid) | Type_variable (_, tvid))
2115+
when Tvid.Map.mem tvid solutions ->
2116+
let r = Tvid.Map.find tvid solutions in
2117+
let solutions = Tvid.Map.remove tvid solutions in
2118+
to_string_help prefix solutions r
2119+
| _ -> to_string_help prefix solutions into)
2120+
| Solved { solution; of_; in_ = r } ->
2121+
let solutions = Tvid.Map.add of_ solution solutions in
2122+
to_string_help prefix solutions r
21002123
| Idx (_, r2) ->
21012124
[(p, prefix)]
21022125
@ [
@@ -2121,8 +2144,9 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
21212144
^ arg_pos_str s
21222145
^ " argument." );
21232146
]
2124-
@ to_string
2147+
@ to_string_help
21252148
"Here is why I think the argument is a `float`: this is a `float`"
2149+
solutions
21262150
r_last
21272151
| Arith_ret_num (_, r, s) ->
21282152
let rec find_last reason =
@@ -2140,8 +2164,9 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
21402164
^ arg_pos_str s
21412165
^ " argument, and no `float`s." );
21422166
]
2143-
@ to_string
2167+
@ to_string_help
21442168
"Here is why I think the argument is a `num`: this is a `num`"
2169+
solutions
21452170
r_last
21462171
| Lost_info (s, r1, Blame (p2, source_of_loss)) ->
21472172
let s = strip_ns s in
@@ -2152,7 +2177,7 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
21522177
| BSassignment -> "by this assignment"
21532178
| BSout_of_scope -> "because of scope change"
21542179
in
2155-
to_string prefix r1
2180+
to_string_help prefix solutions r1
21562181
@ [
21572182
( p2 |> Pos_or_decl.of_raw_pos,
21582183
"All the local information about "
@@ -2169,13 +2194,14 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
21692194
^ Markdown_lite.md_codify s
21702195
^ " format specifier"
21712196
in
2172-
(match to_string "" t with
2197+
(match to_string_help "" solutions t with
21732198
| [(_, "")] -> [(p, s)]
21742199
| el -> [(p, s)] @ el)
21752200
| Instantiate (r_orig, generic_name, r_inst) ->
2176-
to_string prefix r_orig
2177-
@ to_string
2201+
to_string_help prefix solutions r_orig
2202+
@ to_string_help
21782203
(" via this generic " ^ Markdown_lite.md_codify generic_name)
2204+
solutions
21792205
r_inst
21802206
| Typeconst (No_reason, (pos, tconst), (lazy ty_str), r_root) ->
21812207
let prefix =
@@ -2191,42 +2217,45 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
21912217
prefix
21922218
(Markdown_lite.md_codify tconst) );
21932219
]
2194-
@ to_string ("on " ^ ty_str) r_root
2220+
@ to_string_help ("on " ^ ty_str) solutions r_root
21952221
| Typeconst (r_orig, (pos, tconst), (lazy ty_str), r_root) ->
2196-
to_string prefix r_orig
2222+
to_string_help prefix solutions r_orig
21972223
@ [
21982224
(pos, sprintf " resulting from accessing the type constant '%s'" tconst);
21992225
]
2200-
@ to_string (" on " ^ ty_str) r_root
2226+
@ to_string_help (" on " ^ ty_str) solutions r_root
22012227
| Type_access (Typeconst (No_reason, _, _, _), (r, _) :: l) ->
2202-
to_string prefix (Type_access (r, l))
2228+
to_string_help prefix solutions (Type_access (r, l))
22032229
| Type_access (Typeconst (r, _, _, _), x) ->
2204-
to_string prefix (Type_access (r, x))
2230+
to_string_help prefix solutions (Type_access (r, x))
22052231
| Type_access (Type_access (r, expand2), expand1) ->
2206-
to_string prefix (Type_access (r, expand1 @ expand2))
2207-
| Type_access (r, []) -> to_string prefix r
2232+
to_string_help prefix solutions (Type_access (r, expand1 @ expand2))
2233+
| Type_access (r, []) -> to_string_help prefix solutions r
22082234
| Type_access (r, (r_hd, (lazy tconst)) :: tail) ->
2209-
to_string prefix r
2210-
@ to_string
2235+
to_string_help prefix solutions r
2236+
@ to_string_help
22112237
(" resulting from expanding the type constant "
22122238
^ Markdown_lite.md_codify tconst)
2239+
solutions
22132240
r_hd
22142241
@ List.concat_map tail ~f:(fun (r, (lazy s)) ->
2215-
to_string
2242+
to_string_help
22162243
(" then expanding the type constant " ^ Markdown_lite.md_codify s)
2244+
solutions
22172245
r)
22182246
| Expr_dep_type (r, p, e) ->
2219-
to_string prefix r @ [(p, " " ^ expr_dep_type_reason_string e)]
2247+
to_string_help prefix solutions r
2248+
@ [(p, " " ^ expr_dep_type_reason_string e)]
22202249
| Contravariant_generic (r_orig, class_name) ->
2221-
to_string prefix r_orig
2250+
to_string_help prefix solutions r_orig
22222251
@ [
22232252
( p,
22242253
"This type argument to "
22252254
^ (strip_ns class_name |> Markdown_lite.md_codify)
22262255
^ " only allows supertypes (it is contravariant)" );
22272256
]
22282257
| Invariant_generic (r_orig, class_name) ->
2229-
to_string prefix r_orig
2258+
to_string_help prefix solutions r_orig
22302259
@ [
22312260
( p,
22322261
"This type argument to "
@@ -2235,35 +2264,44 @@ let rec to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
22352264
]
22362265
(* If type originated with an unannotated lambda parameter with type variable type,
22372266
* suggested annotating the lambda parameter. Otherwise defer to original reason. *)
2267+
| Lambda_param
2268+
( _,
2269+
From_witness_locl
2270+
(Type_variable_generics (_, _, _, tvid) | Type_variable (_, tvid)) )
2271+
when Tvid.Map.mem tvid solutions ->
2272+
let r = Tvid.Map.find tvid solutions in
2273+
let solutions = Tvid.Map.remove tvid solutions in
2274+
to_string_help prefix solutions r
22382275
| Lambda_param
22392276
( _,
22402277
( From_witness_decl (Solve_fail _)
2241-
| From_witness_locl (Type_variable_generics _ | Type_variable _)
2242-
| Instantiate _ ) ) ->
2278+
| From_witness_locl (Type_variable_generics _ | Type_variable _) ) ) ->
22432279
[
22442280
( p,
22452281
prefix
22462282
^ " because the type of the lambda parameter could not be determined. "
22472283
^ "Please add a type hint to the parameter" );
22482284
]
2249-
| Lambda_param (_, r_orig) -> to_string prefix r_orig
2250-
| Dynamic_coercion r -> to_string prefix r
2285+
| Lambda_param (_, r_orig) -> to_string_help prefix solutions r_orig
2286+
| Dynamic_coercion r -> to_string_help prefix solutions r
22512287
| Dynamic_partial_enforcement (p, cn, r_orig) ->
2252-
to_string prefix r_orig
2288+
to_string_help prefix solutions r_orig
22532289
@ [(p, "while allowing dynamic to flow into " ^ Utils.strip_all_ns cn)]
22542290
| Rigid_tvar_escape (p, what, tvar, r_orig) ->
22552291
let tvar = Markdown_lite.md_codify tvar in
22562292
( Pos_or_decl.of_raw_pos p,
22572293
prefix ^ " because " ^ tvar ^ " escaped from " ^ what )
2258-
:: to_string (" where " ^ tvar ^ " originates from") r_orig
2294+
:: to_string_help (" where " ^ tvar ^ " originates from") solutions r_orig
22592295
| Opaque_type_from_module (p, module_, r_orig) ->
22602296
( p,
22612297
prefix
22622298
^ " because this is an internal symbol from module "
22632299
^ module_
22642300
^ ", which is opaque outside of the module." )
2265-
:: to_string "The type originated from here" r_orig
2301+
:: to_string_help "The type originated from here" solutions r_orig
22662302

2303+
let to_string : type a. string -> a t_ -> (Pos_or_decl.t * string) list =
2304+
(fun prefix r -> to_string_help prefix Tvid.Map.empty r)
22672305
(* -- Constructors ---------------------------------------------------------- *)
22682306

22692307
module Constructors = struct

hphp/hack/test/sound_dynamic/typing/typeconst_access.bad.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Invalid return type (Typing[4110])
44
Expected `int`
55
File "", line 0, characters 0-0:
66
But got `<expr#2>::TIndex`
7+
File "typeconst_access.bad.php", line 21, characters 11-16:
8+
via this generic `TIndex`
79
ERROR: File "typeconst_access.bad.php", line 16, characters 12-16:
810
Invalid return type (Typing[4110])
911
File "typeconst_access.bad.php", line 14, characters 6-8:

hphp/hack/test/typecheck/argument_unpacking/unpack_call12_infer.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ Invalid argument (Typing[4110])
1212
via this generic `Tv`
1313
File "interfaces.hhi", line 92, characters 66-67:
1414
via this generic `Tv`
15+
File "unpack_call12_infer.php", line 4, characters 53-54:
16+
via this generic `Tv`

hphp/hack/test/typecheck/array/safe_vector_array/disallow_darray_with_wrong_key_type_where_varray_or_darray_is_required.php.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ ERROR: File "disallow_darray_with_wrong_key_type_where_varray_or_darray_is_requi
88
Invalid return type (Typing[4110])
99
File "disallow_darray_with_wrong_key_type_where_varray_or_darray_is_required.php", line 7, characters 43-45:
1010
Expected `int`
11-
File "disallow_darray_with_wrong_key_type_where_varray_or_darray_is_required.php", line 9, characters 17-21:
11+
File "disallow_darray_with_wrong_key_type_where_varray_or_darray_is_required.php", line 9, characters 12-27:
1212
But got `string`

hphp/hack/test/typecheck/constraints/classmeth_constraints_bad.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ ERROR: File "classmeth_constraints_bad.php", line 11, characters 6-6:
22
Invalid argument (Typing[4110])
33
File "classmeth_constraints_bad.php", line 6, characters 39-42:
44
Expected `Base`
5+
File "classmeth_constraints_bad.php", line 6, characters 46-46:
6+
via this generic `T`
57
File "classmeth_constraints_bad.php", line 11, characters 6-6:
68
But got `int`

hphp/hack/test/typecheck/expression_trees/pipe3.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ Invalid return type (Typing[4110])
1212
But got `ExampleString`
1313
File "expr_tree.php", line 37, characters 44-49:
1414
via this generic `TInfer`
15+
File "expr_tree.php", line 72, characters 47-52:
16+
via this generic `TInfer`

hphp/hack/test/typecheck/expression_trees/pipe4.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ Invalid return type (Typing[4110])
1212
But got `ExampleInt`
1313
File "expr_tree.php", line 37, characters 44-49:
1414
via this generic `TInfer`
15+
File "expr_tree.php", line 72, characters 47-52:
16+
via this generic `TInfer`

hphp/hack/test/typecheck/expression_trees/splice_err2.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ Invalid argument (Typing[4110])
44
Expected `ExampleInt`
55
File "expr_tree.php", line 88, characters 40-52:
66
But got `ExampleString`
7+
File "expr_tree.php", line 72, characters 47-52:
8+
via this generic `TInfer`
79
File "expr_tree.php", line 37, characters 44-49:
810
via this generic `TInfer`

hphp/hack/test/typecheck/expression_trees/splice_err3.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Invalid argument (Typing[4110])
44
Expected `ExampleInt`
55
File "expr_tree.php", line 88, characters 40-52:
66
But got `ExampleString`
7+
File "expr_tree.php", line 72, characters 47-52:
8+
via this generic `TInfer`

hphp/hack/test/typecheck/expression_trees/splice_err5.php.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ Invalid argument (Typing[4110])
44
Expected `ExampleInt`
55
File "expr_tree.php", line 88, characters 40-52:
66
But got `ExampleString`
7+
File "expr_tree.php", line 72, characters 47-52:
8+
via this generic `TInfer`
79
File "expr_tree.php", line 37, characters 44-49:
810
via this generic `TInfer`

0 commit comments

Comments
 (0)