diff --git a/CHANGELOG.md b/CHANGELOG.md index 990cbb3c9..b0238454a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ #### :bug: Bug Fix +- Fix issue where autocomplete would not perform type instantiation https://github.com/rescript-lang/rescript-vscode/pull/561 - 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 - Fix Incorrect semantic highlighting of `external` declarations https://github.com/rescript-lang/rescript-vscode/pull/517 - Fix issue where doc comment with nested comments inside is not shown properly on hover https://github.com/rescript-lang/rescript-vscode/pull/526 diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 387abd6b8..603066b95 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -980,14 +980,75 @@ let findLocalCompletionsWithOpens ~pos ~(env : QueryEnv.t) ~prefix ~exact ~opens (* There's no local completion for fields *) [] +let instantiateType ~typeParams ~typeArgs (t : Types.type_expr) = + if typeParams = [] || typeArgs = [] then t + else + let rec applySub tp ta t = + match (tp, ta) with + | t1 :: tRest1, t2 :: tRest2 -> + if t1 = t then t2 else applySub tRest1 tRest2 t + | [], _ | _, [] -> assert false + in + let rec loop (t : Types.type_expr) = + match t.desc with + | Tlink t -> loop t + | Tvar _ -> applySub typeParams typeArgs t + | Tunivar _ -> t + | Tconstr (path, args, memo) -> + {t with desc = Tconstr (path, args |> List.map loop, memo)} + | Tsubst t -> loop t + | Tvariant rd -> {t with desc = Tvariant (rowDesc rd)} + | Tnil -> t + | Tarrow (lbl, t1, t2, c) -> + {t with desc = Tarrow (lbl, loop t1, loop t2, c)} + | Ttuple tl -> {t with desc = Ttuple (tl |> List.map loop)} + | Tobject (t, r) -> {t with desc = Tobject (loop t, r)} + | Tfield (n, k, t1, t2) -> {t with desc = Tfield (n, k, loop t1, loop t2)} + | Tpoly (t, []) -> loop t + | Tpoly (t, tl) -> {t with desc = Tpoly (loop t, tl |> List.map loop)} + | Tpackage (p, l, tl) -> + {t with desc = Tpackage (p, l, tl |> List.map loop)} + and rowDesc (rd : Types.row_desc) = + let row_fields = + rd.row_fields |> List.map (fun (l, rf) -> (l, rowField rf)) + in + let row_more = loop rd.row_more in + let row_name = + match rd.row_name with + | None -> None + | Some (p, tl) -> Some (p, tl |> List.map loop) + in + {rd with row_fields; row_more; row_name} + and rowField (rf : Types.row_field) = + match rf with + | Rpresent None -> rf + | Rpresent (Some t) -> Rpresent (Some (loop t)) + | Reither (b1, tl, b2, r) -> Reither (b1, tl |> List.map loop, b2, r) + | Rabsent -> Rabsent + in + loop t + let rec extractRecordType ~env ~package (t : Types.type_expr) = match t.desc with | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractRecordType ~env ~package t1 - | Tconstr (path, _, _) -> ( + | Tconstr (path, typeArgs, _) -> ( match References.digConstructor ~env ~package path with | Some (env, ({item = {kind = Record fields}} as typ)) -> + let typeParams = typ.item.decl.type_params in + let fields = + fields + |> List.map (fun field -> + let fieldTyp = + field.typ |> instantiateType ~typeParams ~typeArgs + in + {field with typ = fieldTyp}) + in Some (env, fields, typ) - | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + | Some + ( env, + {item = {decl = {type_manifest = Some t1; type_params = typeParams}}} + ) -> + let t1 = t1 |> instantiateType ~typeParams ~typeArgs in extractRecordType ~env ~package t1 | _ -> None) | _ -> None @@ -996,9 +1057,13 @@ let rec extractObjectType ~env ~package (t : Types.type_expr) = match t.desc with | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractObjectType ~env ~package t1 | Tobject (tObj, _) -> Some (env, tObj) - | Tconstr (path, _, _) -> ( + | Tconstr (path, typeArgs, _) -> ( match References.digConstructor ~env ~package path with - | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + | Some + ( env, + {item = {decl = {type_manifest = Some t1; type_params = typeParams}}} + ) -> + let t1 = t1 |> instantiateType ~typeParams ~typeArgs in extractObjectType ~env ~package t1 | _ -> None) | _ -> None @@ -1008,9 +1073,14 @@ let extractFunctionType ~env ~package typ = match t.desc with | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> loop ~env acc t1 | Tarrow (label, tArg, tRet, _) -> loop ~env ((label, tArg) :: acc) tRet - | Tconstr (path, _, _) -> ( + | Tconstr (path, typeArgs, _) -> ( match References.digConstructor ~env ~package path with - | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + | Some + ( env, + { + item = {decl = {type_manifest = Some t1; type_params = typeParams}}; + } ) -> + let t1 = t1 |> instantiateType ~typeParams ~typeArgs in loop ~env acc t1 | _ -> (List.rev acc, t)) | _ -> (List.rev acc, t) @@ -1234,17 +1304,17 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos | _ :: rest -> List.rev rest | [] -> []) in - let getConstr typ = + let getConstrPath typ = match typ.Types.desc with - | Tconstr (path, _, _) - | Tlink {desc = Tconstr (path, _, _)} - | Tsubst {desc = Tconstr (path, _, _)} - | Tpoly ({desc = Tconstr (path, _, _)}, []) -> + | Tconstr (path, _typeArgs, _) + | Tlink {desc = Tconstr (path, _typeArgs, _)} + | Tsubst {desc = Tconstr (path, _typeArgs, _)} + | Tpoly ({desc = Tconstr (path, _typeArgs, _)}, []) -> Some path | _ -> None in let fromType typ = - match getConstr typ with + match getConstrPath typ with | None -> None | Some path -> Some (getModulePath path) in @@ -1668,9 +1738,18 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i | Tarrow ((Labelled l | Optional l), tArg, tRet, _) -> (l, tArg) :: getLabels ~env tRet | Tarrow (Nolabel, _, tRet, _) -> getLabels ~env tRet - | Tconstr (path, _, _) -> ( + | Tconstr (path, typeArgs, _) -> ( match References.digConstructor ~env ~package path with - | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + | Some + ( env, + { + item = + { + decl = + {type_manifest = Some t1; type_params = typeParams}; + }; + } ) -> + let t1 = t1 |> instantiateType ~typeParams ~typeArgs in getLabels ~env t1 | _ -> []) | _ -> [] diff --git a/analysis/tests/src/Hover.res b/analysis/tests/src/Hover.res index 732213a82..593d40473 100644 --- a/analysis/tests/src/Hover.res +++ b/analysis/tests/src/Hover.res @@ -165,4 +165,22 @@ module TypeSubstitutionRecords = { // ^hov let x2: foobar = {content: {age: 42}, zzz: ""} // ^hov + + // x1.content. + // ^com + + // x2.content. + // ^com + + type foo2<'b> = foo<'b> + type foobar2 = foo2 + + let y1: foo2 = {content: {age: 42}, zzz: ""} + let y2: foobar2 = {content: {age: 42}, zzz: ""} + + // y1.content. + // ^com + + // y2.content. + // ^com } diff --git a/analysis/tests/src/expected/Hover.res.txt b/analysis/tests/src/expected/Hover.res.txt index db5dc5dfa..93d8616be 100644 --- a/analysis/tests/src/expected/Hover.res.txt +++ b/analysis/tests/src/expected/Hover.res.txt @@ -110,3 +110,51 @@ Hover src/Hover.res 163:23 Hover src/Hover.res 165:22 {"contents": "```rescript\nfoobar\n```\n\n```rescript\ntype foobar = foo\n```"} +Complete src/Hover.res 168:16 +posCursor:[168:16] posNoWhite:[168:15] Found expr:[168:5->168:16] +Pexp_field [168:5->168:15] _:[174:2->168:16] +Completable: Cpath Value[x1].content."" +[{ + "label": "age", + "kind": 5, + "tags": [], + "detail": "age: int\n\ntype bar = {age: int}", + "documentation": null + }] + +Complete src/Hover.res 171:16 +posCursor:[171:16] posNoWhite:[171:15] Found expr:[171:5->171:16] +Pexp_field [171:5->171:15] _:[174:2->171:16] +Completable: Cpath Value[x2].content."" +[{ + "label": "age", + "kind": 5, + "tags": [], + "detail": "age: int\n\ntype bar = {age: int}", + "documentation": null + }] + +Complete src/Hover.res 180:16 +posCursor:[180:16] posNoWhite:[180:15] Found expr:[180:5->180:16] +Pexp_field [180:5->180:15] _:[185:0->180:16] +Completable: Cpath Value[y1].content."" +[{ + "label": "age", + "kind": 5, + "tags": [], + "detail": "age: int\n\ntype bar = {age: int}", + "documentation": null + }] + +Complete src/Hover.res 183:16 +posCursor:[183:16] posNoWhite:[183:15] Found expr:[183:5->183:16] +Pexp_field [183:5->183:15] _:[185:0->183:16] +Completable: Cpath Value[y2].content."" +[{ + "label": "age", + "kind": 5, + "tags": [], + "detail": "age: int\n\ntype bar = {age: int}", + "documentation": null + }] +