Skip to content

Commit 477d8fa

Browse files
committed
simple %typeof poc
1 parent 4276895 commit 477d8fa

File tree

6 files changed

+51
-2
lines changed

6 files changed

+51
-2
lines changed

compiler/ml/typetexp.ml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,26 @@ and transl_type_aux env policy styp =
565565
pack_txt = p;
566566
})
567567
ty
568-
| Ptyp_extension ext ->
569-
raise (Error_forward (Builtin_attributes.error_of_extension ext))
568+
| Ptyp_extension ext -> (
569+
match ext with
570+
| ({txt = "typeof"; loc = ext_loc}, payload) -> (
571+
(* %typeof payload must be a single identifier *)
572+
match Ast_payload.as_ident payload with
573+
| Some ({txt = lid; loc = lid_loc} as _ident) -> (
574+
(* Lookup the value and embed a generic instance of its type.
575+
Using a generic instance avoids capturing weak (non-generalized)
576+
type variables from the value into a type position. *)
577+
let (_path, desc) = find_value env lid_loc lid in
578+
let ty = Ctype.generic_instance env desc.val_type in
579+
(* Build a core_type node carrying the looked up type; we mark the
580+
desc as any since downstream only consults ctyp_type for typing. *)
581+
ctyp Ttyp_any ty)
582+
| None ->
583+
let msg =
584+
"%%typeof expects an identifier. Example: type t = %typeof(x)"
585+
in
586+
raise (Error_forward (Location.error ~loc:ext_loc msg)))
587+
| _ -> raise (Error_forward (Builtin_attributes.error_of_extension ext)))
570588

571589
and transl_poly_type env policy t =
572590
transl_type env policy (Ast_helper.Typ.force_poly t)

tests/analysis_tests/tests/src/Hover.res

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,8 @@ module Arr = Belt.Array
281281

282282
type aliased = variant
283283
// ^hov
284+
285+
let myFn = (a, b) => a ++ b->Int.toString
286+
287+
type fnType = %typeof(myFn)
288+
// ^hov

tests/analysis_tests/tests/src/expected/Hover.res.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,6 @@ Hover src/Hover.res 278:8
348348
Hover src/Hover.res 281:6
349349
{"contents": {"kind": "markdown", "value": "```rescript\ntype aliased = variant\n```\n\n---\n\n```\n \n```\n```rescript\ntype variant = CoolVariant | OtherCoolVariant\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C251%2C0%5D)\n"}}
350350

351+
Hover src/Hover.res 286:6
352+
{"contents": {"kind": "markdown", "value": "```rescript\ntype fnType = (string, int) => string\n```"}}
353+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/typeof_mismatch.res:6:28
4+
5+
4 │
6+
5 │ let f: fnType = myFn
7+
6 │ let ff: fnType = (a, b) => a->Int.toString + b
8+
9+
This has type: string
10+
But this function argument is expecting: int
11+
12+
You can convert string to int with Int.fromString.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
let myFn = (a, b) => a ++ b->Int.toString
2+
3+
type fnType = %typeof(myFn)
4+
5+
let f: fnType = myFn
6+
let ff: fnType = (a, b) => a->Int.toString + b

tests/tests/src/Typeof.res

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let myFn = (a, b) => a ++ b->Int.toString
2+
3+
type fnType = %typeof(myFn)
4+
5+
let f: fnType = myFn

0 commit comments

Comments
 (0)