Skip to content

Commit 2263d4c

Browse files
committed
add experimental mainTypeForModule annotation
1 parent 17c52a8 commit 2263d4c

13 files changed

+129
-64
lines changed

analysis/src/CompletionBackEnd.ml

+30-20
Original file line numberDiff line numberDiff line change
@@ -990,35 +990,44 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
990990
with
991991
| Some (TypeExpr typ, env) -> (
992992
match typ |> TypeUtils.extractRecordType ~env ~package with
993-
| Some (env, fields, typDecl, path) ->
993+
| Some (env, fields, typDecl, path, attributes) ->
994994
Some
995995
( env,
996996
fields,
997997
typDecl.item.decl |> Shared.declToString typDecl.name.txt,
998-
Some path )
998+
Some path,
999+
attributes )
9991000
| None -> None)
10001001
| Some (ExtractedType typ, env) -> (
10011002
match typ with
1002-
| Trecord {fields; path} ->
1003-
Some (env, fields, typ |> TypeUtils.extractedTypeToString, path)
1003+
| Trecord {fields; path; attributes} ->
1004+
Some
1005+
( env,
1006+
fields,
1007+
typ |> TypeUtils.extractedTypeToString,
1008+
path,
1009+
attributes )
10041010
| _ -> None)
10051011
| None -> None
10061012
in
10071013
match extracted with
10081014
| None -> []
1009-
| Some (env, fields, recordAsString, path) ->
1010-
let pipeCompletionsForModule =
1011-
match path with
1012-
| Some path ->
1013-
let completionPath =
1014-
(* Remove the last part of the path since we're only after the parent module *)
1015-
match
1015+
| Some (env, fields, recordAsString, path, attributes) ->
1016+
let pipeCompletion =
1017+
match
1018+
(path, ProcessAttributes.findMainTypeForModuleAttribute attributes)
1019+
with
1020+
| Some path, _ when Path.last path = "t" ->
1021+
Some
1022+
( path,
10161023
path |> SharedTypes.pathIdentToString |> String.split_on_char '.'
1017-
|> List.rev
1018-
with
1019-
| _ :: rest -> rest
1020-
| [] -> []
1021-
in
1024+
|> List.rev |> List.tl )
1025+
| Some path, Some modulePath -> Some (path, modulePath)
1026+
| _ -> None
1027+
in
1028+
let pipeCompletionsForModule =
1029+
match pipeCompletion with
1030+
| Some (path, completionPath) ->
10221031
(* Most of this is copied from the pipe completion code. Should probably be unified. *)
10231032
let completions =
10241033
completionPath @ [fieldName]
@@ -1046,10 +1055,8 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
10461055
match
10471056
TypeUtils.extractFunctionType ~env ~package:full.package t
10481057
with
1049-
| ( (Nolabel, {desc = Tconstr (Path.Pident {name = "t"}, _, _)})
1050-
:: _,
1051-
_ ) ->
1052-
true
1058+
| (Nolabel, {desc = Tconstr (p, _, _)}) :: _, _ ->
1059+
Path.same p path || Path.name p = "t"
10531060
| _ -> false)
10541061
| _ -> false
10551062
in
@@ -2031,6 +2038,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
20312038
env;
20322039
definition = `NameOnly "jsxConfig";
20332040
path = None;
2041+
attributes = [];
20342042
fields =
20352043
[
20362044
mkField ~name:"version" ~primitive:"int";
@@ -2061,6 +2069,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
20612069
{
20622070
env;
20632071
path = None;
2072+
attributes = [];
20642073
definition = `NameOnly "importAttributesConfig";
20652074
fields = [mkField ~name:"type_" ~primitive:"string"];
20662075
}
@@ -2070,6 +2079,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
20702079
{
20712080
env;
20722081
path = None;
2082+
attributes = [];
20732083
definition = `NameOnly "moduleConfig";
20742084
fields =
20752085
[

analysis/src/ProcessAttributes.ml

+16
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,19 @@ let newDeclared ~item ~extent ~name ~stamp ~modulePath isExported attributes =
4848
| Some d -> [d]);
4949
item;
5050
}
51+
52+
let rec findMainTypeForModuleAttribute attributes =
53+
let open Parsetree in
54+
match attributes with
55+
| [] -> None
56+
| ( {Asttypes.txt = "mainTypeForModule"},
57+
PStr
58+
[
59+
{
60+
pstr_desc =
61+
Pstr_eval ({pexp_desc = Pexp_construct ({txt = path}, None)}, _);
62+
};
63+
] )
64+
:: _ ->
65+
Some (Utils.flattenLongIdent path)
66+
| _ :: rest -> findMainTypeForModuleAttribute rest

analysis/src/SharedTypes.ml

+1
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ and completionType =
355355
env: QueryEnv.t;
356356
fields: field list;
357357
path: Path.t option;
358+
attributes: Parsetree.attributes;
358359
definition:
359360
[ `NameOnly of string
360361
(** When we only have the name, like when pulling the record from a declared type. *)

analysis/src/TypeUtils.ml

+15-4
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ let rec extractRecordType ~env ~package (t : Types.type_expr) =
203203
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractRecordType ~env ~package t1
204204
| Tconstr (path, typeArgs, _) -> (
205205
match References.digConstructor ~env ~package path with
206-
| Some (env, ({item = {kind = Record fields}} as typ)) ->
206+
| Some (env, ({item = {kind = Record fields; attributes}} as typ)) ->
207207
let typeParams = typ.item.decl.type_params in
208208
let fields =
209209
fields
@@ -213,7 +213,7 @@ let rec extractRecordType ~env ~package (t : Types.type_expr) =
213213
in
214214
{field with typ = fieldTyp})
215215
in
216-
Some (env, fields, typ, path)
216+
Some (env, fields, typ, path, attributes)
217217
| Some
218218
( env,
219219
{item = {decl = {type_manifest = Some t1; type_params = typeParams}}}
@@ -383,7 +383,9 @@ let rec extractType ?(printOpeningDebug = true)
383383
variantDecl = decl;
384384
},
385385
typeArgContext )
386-
| Some (envFromDeclaration, {item = {kind = Record fields; decl}}) ->
386+
| Some
387+
(envFromDeclaration, {item = {kind = Record fields; decl; attributes}})
388+
->
387389
if Debug.verbose () then print_endline "[extract_type]--> found record";
388390
(* Need to create a new type arg context here because we're sending along a type expr that might have type vars. *)
389391
let typeArgContext =
@@ -396,6 +398,7 @@ let rec extractType ?(printOpeningDebug = true)
396398
path = Some path;
397399
fields;
398400
definition = `TypeExpr t;
401+
attributes;
399402
},
400403
typeArgContext )
401404
| Some (envFromDeclaration, {item = {name = "t"; decl = {type_params}}}) ->
@@ -577,7 +580,15 @@ let extractTypeFromResolvedType (typ : Type.t) ~env ~full =
577580
match typ.kind with
578581
| Tuple items -> Some (Tuple (env, items, Ctype.newty (Ttuple items)))
579582
| Record fields ->
580-
Some (Trecord {env; fields; path = None; definition = `NameOnly typ.name})
583+
Some
584+
(Trecord
585+
{
586+
env;
587+
fields;
588+
path = None;
589+
definition = `NameOnly typ.name;
590+
attributes = typ.attributes;
591+
})
581592
| Variant constructors ->
582593
Some
583594
(Tvariant

analysis/tests/src/CompletionFromModule.res

+22
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,25 @@ let n = {SomeModule.name: "hello"}
1212
// n.
1313
// ^com
1414
// ^dv-
15+
16+
@mainTypeForModule(SomeOtherModule)
17+
type typeOutsideModule = {nname: string}
18+
19+
module SomeOtherModule = {
20+
type t = typeOutsideModule
21+
22+
type irrelevantType = string
23+
24+
@get external getNName: t => string = "nname"
25+
@get external getNName2: typeOutsideModule => string = "nname"
26+
@get external getNName3: irrelevantType => string = "nname"
27+
28+
let thisShouldNotBeCompletedFor = () => "hi"
29+
}
30+
31+
let nn: SomeOtherModule.t = {nname: "hello"}
32+
33+
// ^dv+
34+
// nn.
35+
// ^com
36+
// ^dv-

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

-13
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,6 @@ Resolved opens 1 pervasives
728728
ContextPath Value[r].""
729729
ContextPath Value[r]
730730
Path r
731-
Path
732731
[{
733732
"label": "x",
734733
"kind": 5,
@@ -752,7 +751,6 @@ Resolved opens 1 pervasives
752751
ContextPath Value[Objects, Rec, recordVal].""
753752
ContextPath Value[Objects, Rec, recordVal]
754753
Path Objects.Rec.recordVal
755-
Path
756754
[{
757755
"label": "xx",
758756
"kind": 5,
@@ -835,8 +833,6 @@ ContextPath Value[q].aa.""
835833
ContextPath Value[q].aa
836834
ContextPath Value[q]
837835
Path q
838-
Path aa
839-
Path
840836
[{
841837
"label": "x",
842838
"kind": 5,
@@ -861,8 +857,6 @@ ContextPath Value[q].aa.n
861857
ContextPath Value[q].aa
862858
ContextPath Value[q]
863859
Path q
864-
Path aa
865-
Path n
866860
[{
867861
"label": "name",
868862
"kind": 5,
@@ -1087,7 +1081,6 @@ ContextPath Value[FAO, forAutoObject]["forAutoLabel"].""
10871081
ContextPath Value[FAO, forAutoObject]["forAutoLabel"]
10881082
ContextPath Value[FAO, forAutoObject]
10891083
Path FAO.forAutoObject
1090-
Path FAR.
10911084
[{
10921085
"label": "forAuto",
10931086
"kind": 5,
@@ -1113,7 +1106,6 @@ ContextPath Value[FAO, forAutoObject]["forAutoLabel"].forAuto
11131106
ContextPath Value[FAO, forAutoObject]["forAutoLabel"]
11141107
ContextPath Value[FAO, forAutoObject]
11151108
Path FAO.forAutoObject
1116-
Path FAR.forAuto
11171109
CPPipe env:Completion envFromCompletionItem:Completion.FAR
11181110
CPPipe type path:ForAuto.t
11191111
CPPipe pathFromEnv:ForAuto found:false
@@ -1197,7 +1189,6 @@ Resolved opens 3 pervasives Completion.res Completion.res
11971189
ContextPath Value[_z].""
11981190
ContextPath Value[_z]
11991191
Path _z
1200-
Path
12011192
[{
12021193
"label": "x",
12031194
"kind": 5,
@@ -1356,7 +1347,6 @@ Resolved opens 3 pervasives Completion.res Completion.res
13561347
ContextPath Value[funRecord].someFun
13571348
ContextPath Value[funRecord]
13581349
Path funRecord
1359-
Path someFun
13601350
Found type for function (~name: string) => unit
13611351
[{
13621352
"label": "name",
@@ -1377,7 +1367,6 @@ ContextPath Value[retAA](Nolabel).""
13771367
ContextPath Value[retAA](Nolabel)
13781368
ContextPath Value[retAA]
13791369
Path retAA
1380-
Path
13811370
[{
13821371
"label": "x",
13831372
"kind": 5,
@@ -1908,7 +1897,6 @@ Resolved opens 3 pervasives Completion.res Completion.res
19081897
ContextPath Value[funRecord].""
19091898
ContextPath Value[funRecord]
19101899
Path funRecord
1911-
Path
19121900
[{
19131901
"label": "someFun",
19141902
"kind": 5,
@@ -2165,7 +2153,6 @@ Resolved opens 3 pervasives Completion.res Completion.res
21652153
ContextPath Value[rWithDepr].so
21662154
ContextPath Value[rWithDepr]
21672155
Path rWithDepr
2168-
Path so
21692156
[{
21702157
"label": "someInt",
21712158
"kind": 5,

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

-3
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,6 @@ Resolved opens 1 pervasives
946946
ContextPath Value[fff].someOpt
947947
ContextPath Value[fff]
948948
Path fff
949-
Path someOpt
950949
[{
951950
"label": "someOptField",
952951
"kind": 5,
@@ -1416,7 +1415,6 @@ Resolved opens 2 pervasives CompletionSupport.res
14161415
ContextPath Value[someTyp].""
14171416
ContextPath Value[someTyp]
14181417
Path someTyp
1419-
Path
14201418
[{
14211419
"label": "test",
14221420
"kind": 5,
@@ -1472,7 +1470,6 @@ Resolved opens 2 pervasives CompletionSupport.res
14721470
ContextPath Value[someTyp].""
14731471
ContextPath Value[someTyp]
14741472
Path someTyp
1475-
Path
14761473
[{
14771474
"label": "test",
14781475
"kind": 5,

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

+45
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,48 @@ Path SomeModule.
3232
}]
3333

3434

35+
36+
Complete src/CompletionFromModule.res 33:6
37+
posCursor:[33:6] posNoWhite:[33:5] Found expr:[33:3->33:6]
38+
Pexp_field [33:3->33:5] _:[37:0->33:6]
39+
[set_result] set new result to Cpath Value[nn].""
40+
Completable: Cpath Value[nn].""
41+
Package opens Pervasives.JsxModules.place holder
42+
Resolved opens 1 pervasives
43+
ContextPath Value[nn].""
44+
[ctx_path]--> CPField
45+
ContextPath Value[nn]
46+
[ctx_path]--> CPId
47+
Path nn
48+
Path SomeOtherModule.
49+
[{
50+
"label": "->SomeOtherModule.getNName",
51+
"kind": 12,
52+
"tags": [],
53+
"detail": "t => string",
54+
"documentation": null,
55+
"sortText": "getNName",
56+
"textEdit": {
57+
"range": {"start": {"line": 33, "character": 5}, "end": {"line": 33, "character": 5}},
58+
"newText": "->SomeOtherModule.getNName"
59+
}
60+
}, {
61+
"label": "->SomeOtherModule.getNName2",
62+
"kind": 12,
63+
"tags": [],
64+
"detail": "typeOutsideModule => string",
65+
"documentation": null,
66+
"sortText": "getNName2",
67+
"textEdit": {
68+
"range": {"start": {"line": 33, "character": 5}, "end": {"line": 33, "character": 5}},
69+
"newText": "->SomeOtherModule.getNName2"
70+
}
71+
}, {
72+
"label": "nname",
73+
"kind": 5,
74+
"tags": [],
75+
"detail": "string",
76+
"documentation": {"kind": "markdown", "value": "```rescript\nnname: string\n```\n\n```rescript\ntype typeOutsideModule = {nname: string}\n```"}
77+
}]
78+
79+

0 commit comments

Comments
 (0)