Skip to content

Commit bbf68d0

Browse files
committed
Perform type instantiation in field autocompletion
Fixes #349
1 parent 829e6aa commit bbf68d0

File tree

4 files changed

+82
-19
lines changed

4 files changed

+82
-19
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#### :bug: Bug Fix
2323

24+
- Fix issue where field autocomplete in records would not perform type instantiation https://github.com/rescript-lang/rescript-vscode/pull/561
2425
- Fix issue where hovering over a field in record construction would show the type without instantiating its type arguments https://github.com/rescript-lang/rescript-vscode/pull/560
2526
- Fix Incorrect semantic highlighting of `external` declarations https://github.com/rescript-lang/rescript-vscode/pull/517
2627
- Fix issue where doc comment with nested comments inside is not shown properly on hover https://github.com/rescript-lang/rescript-vscode/pull/526

analysis/src/CompletionBackEnd.ml

+56-3
Original file line numberDiff line numberDiff line change
@@ -983,10 +983,10 @@ let findLocalCompletionsWithOpens ~pos ~(env : QueryEnv.t) ~prefix ~exact ~opens
983983
let rec extractRecordType ~env ~package (t : Types.type_expr) =
984984
match t.desc with
985985
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractRecordType ~env ~package t1
986-
| Tconstr (path, _, _) -> (
986+
| Tconstr (path, args, _) -> (
987987
match References.digConstructor ~env ~package path with
988988
| Some (env, ({item = {kind = Record fields}} as typ)) ->
989-
Some (env, fields, typ)
989+
Some (env, fields, typ, args)
990990
| Some (env, {item = {decl = {type_manifest = Some t1}}}) ->
991991
extractRecordType ~env ~package t1
992992
| _ -> None)
@@ -1087,6 +1087,54 @@ let completionsGetTypeEnv = function
10871087
| {Completion.kind = Field ({typ}, _); env} :: _ -> Some (typ, env)
10881088
| _ -> None
10891089

1090+
let instantiateType ~typeParams ~typeArgs (t : Types.type_expr) =
1091+
if typeParams = [] || typeArgs = [] then t
1092+
else
1093+
let rec applySub tp ta t =
1094+
match (tp, ta) with
1095+
| t1 :: tRest1, t2 :: tRest2 ->
1096+
if t1 = t then t2 else applySub tRest1 tRest2 t
1097+
| [], _ | _, [] -> assert false
1098+
in
1099+
let rec loop (t : Types.type_expr) =
1100+
match t.desc with
1101+
| Tlink t -> loop t
1102+
| Tvar _ -> applySub typeParams typeArgs t
1103+
| Tunivar _ -> t
1104+
| Tconstr (path, args, memo) ->
1105+
{t with desc = Tconstr (path, args |> List.map loop, memo)}
1106+
| Tsubst t -> loop t
1107+
| Tvariant rd -> {t with desc = Tvariant (rowDesc rd)}
1108+
| Tnil -> t
1109+
| Tarrow (lbl, t1, t2, c) ->
1110+
{t with desc = Tarrow (lbl, loop t1, loop t2, c)}
1111+
| Ttuple tl -> {t with desc = Ttuple (tl |> List.map loop)}
1112+
| Tobject (t, r) -> {t with desc = Tobject (loop t, r)}
1113+
| Tfield (n, k, t1, t2) -> {t with desc = Tfield (n, k, loop t1, loop t2)}
1114+
| Tpoly (t, []) -> loop t
1115+
| Tpoly (t, tl) -> {t with desc = Tpoly (loop t, tl |> List.map loop)}
1116+
| Tpackage (p, l, tl) ->
1117+
{t with desc = Tpackage (p, l, tl |> List.map loop)}
1118+
and rowDesc (rd : Types.row_desc) =
1119+
let row_fields =
1120+
rd.row_fields |> List.map (fun (l, rf) -> (l, rowField rf))
1121+
in
1122+
let row_more = loop rd.row_more in
1123+
let row_name =
1124+
match rd.row_name with
1125+
| None -> None
1126+
| Some (p, tl) -> Some (p, tl |> List.map loop)
1127+
in
1128+
{rd with row_fields; row_more; row_name}
1129+
and rowField (rf : Types.row_field) =
1130+
match rf with
1131+
| Rpresent None -> rf
1132+
| Rpresent (Some t) -> Rpresent (Some (loop t))
1133+
| Reither (b1, tl, b2, r) -> Reither (b1, tl |> List.map loop, b2, r)
1134+
| Rabsent -> Rabsent
1135+
in
1136+
loop t
1137+
10901138
let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
10911139
~env ~exact ~scope (contextPath : Completable.contextPath) =
10921140
match contextPath with
@@ -1163,9 +1211,14 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos
11631211
with
11641212
| Some (typ, env) -> (
11651213
match typ |> extractRecordType ~env ~package with
1166-
| Some (env, fields, typDecl) ->
1214+
| Some (env, fields, typDecl, typeArgs) ->
1215+
let typeParams = typDecl.item.decl.type_params in
11671216
fields
11681217
|> Utils.filterMap (fun field ->
1218+
let fieldTyp =
1219+
field.typ |> instantiateType ~typeParams ~typeArgs
1220+
in
1221+
let field = {field with typ = fieldTyp} in
11691222
if checkName field.fname.txt ~prefix:fieldName ~exact then
11701223
Some
11711224
(Completion.create ~name:field.fname.txt ~env

analysis/tests/src/Hover.res

+3-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ module TypeSubstitutionRecords = {
166166
let x2: foobar = {content: {age: 42}, zzz: ""}
167167
// ^hov
168168

169-
// ^db+
170-
171169
// x1.content.
172170
// ^com
171+
172+
// x2.content.
173+
// ^com
173174
}

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

+22-14
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,27 @@ Hover src/Hover.res 163:23
110110
Hover src/Hover.res 165:22
111111
{"contents": "```rescript\nfoobar\n```\n\n```rescript\ntype foobar = foo<bar>\n```"}
112112

113-
114-
Complete src/Hover.res 170:16
115-
posCursor:[170:16] posNoWhite:[170:15] Found expr:[170:5->170:16]
116-
Pexp_field [170:5->170:15] _:[172:0->170:16]
113+
Complete src/Hover.res 168:16
114+
posCursor:[168:16] posNoWhite:[168:15] Found expr:[168:5->168:16]
115+
Pexp_field [168:5->168:15] _:[173:0->168:16]
117116
Completable: Cpath Value[x1].content.""
118-
Ident!! Dep
119-
Ident!! JsLogger
120-
Ident!! A
121-
Ident!! B
122-
Ident!! Comp
123-
Raw ppens: 0
124-
Package opens
125-
Resolved opens 0
126-
findLocalCompletionsWithOpens uri:Hover.res pos:170:16
127-
[]
117+
[{
118+
"label": "age",
119+
"kind": 5,
120+
"tags": [],
121+
"detail": "age: int\n\ntype bar = {age: int}",
122+
"documentation": null
123+
}]
124+
125+
Complete src/Hover.res 171:16
126+
posCursor:[171:16] posNoWhite:[171:15] Found expr:[171:5->171:16]
127+
Pexp_field [171:5->171:15] _:[173:0->171:16]
128+
Completable: Cpath Value[x2].content.""
129+
[{
130+
"label": "age",
131+
"kind": 5,
132+
"tags": [],
133+
"detail": "age: int\n\ntype bar = {age: int}",
134+
"documentation": null
135+
}]
128136

0 commit comments

Comments
 (0)