Skip to content

New function to extract record type. #319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Fix issue with autocomplete then punned props are used in JSX. E.g. `<M foo ...>`.
- Fix issue with JSX autocompletion not working after `foo=#variant`.
- Fix issue in JSX autocompletion where the `key` label would always appear.
- Fix issue in record field autocomplete not working with type aliases.

## 1.1.3

Expand Down
150 changes: 73 additions & 77 deletions analysis/src/NewCompletions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,29 @@ let resolveRawOpens ~env ~rawOpens ~package =
in
opens

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, _, _) -> (
match References.digConstructor ~env ~package path with
| Some (env, ({item = {kind = Record fields}} as typ)) ->
Some (env, fields, typ)
| Some (env, {item = {decl = {type_manifest = Some t1}}}) ->
extractRecordType ~env ~package t1
| _ -> None)
| _ -> None

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, _, _) -> (
match References.digConstructor ~env ~package path with
| Some (env, {item = {decl = {type_manifest = Some t1}}}) ->
extractObjectType ~env ~package t1
| _ -> None)
| _ -> None

let getItems ~full ~rawOpens ~allFiles ~pos ~parts =
Log.log
("Opens folkz > "
Expand Down Expand Up @@ -801,49 +824,36 @@ let getItems ~full ~rawOpens ~allFiles ~pos ~parts =
| None -> []
| Some declared -> (
Log.log ("Found it! " ^ declared.name.txt);
match declared.item |> Shared.digConstructor with
match declared.item |> extractRecordType ~env ~package with
| None -> []
| Some path -> (
match References.digConstructor ~env ~package path with
| None -> []
| Some (env, typ) -> (
match
rest
|> List.fold_left
(fun current name ->
match current with
| Some (env, fields, typ) -> (
match
rest
|> List.fold_left
(fun current name ->
match current with
| None -> None
| Some (env, fields, _) -> (
match
fields |> List.find_opt (fun f -> f.fname.txt = name)
with
| None -> None
| Some (env, typ) -> (
match typ.item.SharedTypes.Type.kind with
| Record fields -> (
match
fields
|> List.find_opt (fun f -> f.fname.txt = name)
with
| None -> None
| Some attr -> (
Log.log ("Found attr " ^ name);
match attr.typ |> Shared.digConstructor with
| None -> None
| Some path ->
References.digConstructor ~env ~package path))
| _ -> None))
(Some (env, typ))
with
| None -> []
| Some (_env, typ) -> (
match typ.item.kind with
| Record fields ->
fields
|> Utils.filterMap (fun f ->
if Utils.startsWith f.fname.txt suffix then
Some
{
(emptyDeclared f.fname.txt) with
item = Field (f, typ);
}
else None)
| _ -> []))))))
| Some attr ->
Log.log ("Found attr " ^ name);
attr.typ |> extractRecordType ~env ~package))
(Some (env, fields, typ))
with
| None -> []
| Some (_env, fields, typ) ->
fields
|> Utils.filterMap (fun f ->
if Utils.startsWith f.fname.txt suffix then
Some
{
(emptyDeclared f.fname.txt) with
item = Field (f, typ);
}
else None)))))
| `AbsAttribute path -> (
match getEnvWithOpens ~pos ~env ~package ~opens path with
| None -> []
Expand Down Expand Up @@ -993,22 +1003,15 @@ let processCompletable ~findItems ~full ~package ~rawOpens
Some (modulePath, partialName)
in
let getField ~env ~typ fieldName =
match getConstr typ with
| Some path -> (
match References.digConstructor ~env ~package path with
match extractRecordType typ ~env ~package with
| Some (env1, fields, _) -> (
match
fields
|> List.find_opt (fun field ->
field.SharedTypes.fname.txt = fieldName)
with
| None -> None
| Some (env1, declared) -> (
let t = declared.item in
match t.kind with
| Record fields -> (
match
fields
|> List.find_opt (fun field ->
field.SharedTypes.fname.txt = fieldName)
with
| None -> None
| Some field -> Some (field.typ, env1))
| _ -> None))
| Some field -> Some (field.typ, env1))
| None -> None
in
let rec getFields ~env ~typ = function
Expand Down Expand Up @@ -1160,35 +1163,28 @@ let processCompletable ~findItems ~full ~package ~rawOpens
| Tvar None -> []
| _ -> []
in
let envRef = ref (QueryEnv.fromFile full.file) in
let rec getObj (t : Types.type_expr) =
match t.desc with
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> getObj t1
| Tobject (tObj, _) -> getFields tObj
| Tconstr (path, _, _) -> (
match References.digConstructor ~env:envRef.contents ~package path with
| Some (env, {item = {decl = {type_manifest = Some tt}}}) ->
envRef := env;
getObj tt
| _ -> [])
| _ -> []
let getObjectFields ~env (t : Types.type_expr) =
match t |> extractObjectType ~env ~package with
| Some (env, tObj) -> (env, getFields tObj)
| None -> (env, [])
in
let fields =
match [lhs] |> findItems ~exact:true with
| {SharedTypes.item = Value typ} :: _ -> getObj typ
| _ -> []
in
let rec resolvePath fields path =
let rec resolvePath ~env fields path =
match path with
| name :: restPath -> (
match fields |> List.find_opt (fun (n, _) -> n = name) with
| Some (_, fieldType) ->
let innerFields = getObj fieldType in
resolvePath innerFields restPath
let env, innerFields = getObjectFields ~env fieldType in
resolvePath ~env innerFields restPath
| None -> [])
| [] -> fields
in
let labels = resolvePath fields path in
let env0 = QueryEnv.fromFile full.file in
let env, fields =
match [lhs] |> findItems ~exact:true with
| {SharedTypes.item = Value typ} :: _ -> getObjectFields ~env:env0 typ
| _ -> (env0, [])
in
let labels = resolvePath ~env fields path in
let mkLabel_ name typString =
mkItem ~name ~kind:4 ~deprecated:None ~detail:typString ~docstring:[]
in
Expand Down
5 changes: 5 additions & 0 deletions analysis/tests/src/Completion.res
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,8 @@ let o : Obj.objT = assert false
type nestedObjT = {"x": Obj.nestedObjT}
let no : nestedObjT = assert false
//^com no["x"]["y"]["

type r = {x:int, y:string}
type rAlias = r
let r:rAlias = assert false
// ^com r.
30 changes: 30 additions & 0 deletions analysis/tests/src/expected/Completion.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,21 @@ DocumentSymbol tests/src/Completion.res
"name": "no",
"kind": 13,
"location": {"uri": "Completion.res", "range": {"start": {"line": 83, "character": 4}, "end": {"line": 83, "character": 6}}}
},
{
"name": "r",
"kind": 11,
"location": {"uri": "Completion.res", "range": {"start": {"line": 86, "character": 0}, "end": {"line": 86, "character": 26}}}
},
{
"name": "rAlias",
"kind": 26,
"location": {"uri": "Completion.res", "range": {"start": {"line": 87, "character": 0}, "end": {"line": 87, "character": 15}}}
},
{
"name": "r",
"kind": 13,
"location": {"uri": "Completion.res", "range": {"start": {"line": 88, "character": 4}, "end": {"line": 88, "character": 5}}}
}
]

Expand Down Expand Up @@ -665,3 +680,18 @@ Complete tests/src/Completion.res 83:2
"documentation": null
}]

Complete tests/src/Completion.res 88:3
[{
"label": "x",
"kind": 5,
"tags": [],
"detail": "x: int\n\ntype r = {x: int, y: string}",
"documentation": null
}, {
"label": "y",
"kind": 5,
"tags": [],
"detail": "y: string\n\ntype r = {x: int, y: string}",
"documentation": null
}]