Skip to content

Commit 4850458

Browse files
authored
feat(lsp): Support displaying multiple errors in the lsp (#2354)
1 parent 5f3f54d commit 4850458

File tree

4 files changed

+98
-115
lines changed

4 files changed

+98
-115
lines changed

compiler/src/compile.re

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ let compile_wasi_polyfill = () => {
244244

245245
let reset_compiler_state = () => {
246246
Driver.reset();
247+
Location.reset_exceptions();
247248
Ident.setup();
248249
Ctype.reset_levels();
249250
Env.clear_persistent_structures();

compiler/src/language_server/code_file.re

Lines changed: 87 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module NotificationParams = {
1616

1717
type compile_result = {
1818
program: option(Typedtree.typed_program),
19-
error: option(Protocol.diagnostic),
19+
error: list(Protocol.diagnostic),
2020
warnings: list(Protocol.diagnostic),
2121
};
2222

@@ -75,110 +75,86 @@ let compile_source = (uri, source) => {
7575
})
7676
) {
7777
| exception exn =>
78-
switch (Grain_parsing.Location.error_of_exn(exn)) {
79-
| Some(`Ok(e)) =>
80-
let (file, line, startchar) =
81-
Grain_parsing.Location.get_pos_info(e.error_loc.loc_start);
82-
let (_, endline, endchar) =
83-
Grain_parsing.Location.get_pos_info(e.error_loc.loc_end);
84-
85-
let startchar = startchar < 0 ? 0 : startchar;
86-
let endchar = endchar < 0 ? 0 : endchar;
87-
88-
let error: Protocol.diagnostic =
89-
if (filename == file) {
90-
let source_range: Protocol.range = {
91-
range_start: {
92-
line: line - 1,
93-
character: startchar,
94-
},
95-
range_end: {
96-
line: endline - 1,
97-
character: endchar,
98-
},
99-
};
100-
101-
{
102-
range: source_range,
103-
severity: Error,
104-
message: e.msg,
105-
related_information: [],
106-
};
107-
} else {
108-
let source_range: Protocol.range = {
109-
range_start: {
110-
line: 0,
111-
character: 0,
112-
},
113-
range_end: {
114-
line: 0,
115-
character: 1,
116-
},
117-
};
78+
let file_start_range: Protocol.range = {
79+
range_start: {
80+
line: 0,
81+
character: 0,
82+
},
83+
range_end: {
84+
line: 0,
85+
character: 1,
86+
},
87+
};
88+
let errors =
89+
List.map(
90+
exn => {
91+
switch (Grain_parsing.Location.error_of_exn(exn)) {
92+
| Some(`Ok(e)) =>
93+
let (file, line, startchar) =
94+
Grain_parsing.Location.get_pos_info(e.error_loc.loc_start);
95+
let (_, endline, endchar) =
96+
Grain_parsing.Location.get_pos_info(e.error_loc.loc_end);
11897

119-
let file_range: Protocol.range = {
120-
range_start: {
121-
line: line - 1,
122-
character: startchar,
123-
},
124-
range_end: {
125-
line: endline - 1,
126-
character: endchar,
127-
},
128-
};
98+
let startchar = startchar < 0 ? 0 : startchar;
99+
let endchar = endchar < 0 ? 0 : endchar;
129100

130-
{
131-
range: source_range,
132-
severity: Error,
133-
message: "Failed to compile " ++ file,
134-
related_information: [
135-
{
136-
location: {
137-
uri: Utils.filename_to_uri(file),
138-
range: file_range,
139-
},
140-
message: e.msg,
101+
let file_range: Protocol.range = {
102+
range_start: {
103+
line: line - 1,
104+
character: startchar,
105+
},
106+
range_end: {
107+
line: endline - 1,
108+
character: endchar,
141109
},
142-
],
143-
};
144-
};
110+
};
145111

146-
{
147-
program: None,
148-
error: Some(error),
149-
warnings: [],
150-
};
151-
| _ =>
152-
let range: Protocol.range = {
153-
range_start: {
154-
line: 0,
155-
character: 0,
156-
},
157-
range_end: {
158-
line: 0,
159-
character: 1,
112+
let error: Protocol.diagnostic =
113+
if (filename == file) {
114+
{
115+
range: file_range,
116+
severity: Error,
117+
message: e.msg,
118+
related_information: [],
119+
};
120+
} else {
121+
{
122+
range: file_start_range,
123+
severity: Error,
124+
message: "Failed to compile " ++ file,
125+
related_information: [
126+
{
127+
location: {
128+
uri: Utils.filename_to_uri(file),
129+
range: file_range,
130+
},
131+
message: e.msg,
132+
},
133+
],
134+
};
135+
};
136+
error;
137+
| _ => {
138+
range: file_start_range,
139+
severity: Error,
140+
message: "Unable to parse",
141+
related_information: [],
142+
}
143+
}
160144
},
161-
};
162-
163-
{
164-
program: None,
165-
error:
166-
Some({
167-
range,
168-
severity: Error,
169-
message: "Unable to parse",
170-
related_information: [],
171-
}),
172-
warnings: [],
173-
};
174-
}
175-
145+
[exn, ...Grain_parsing.Location.reported_exceptions^],
146+
);
147+
{
148+
program: None,
149+
error: errors,
150+
warnings: [],
151+
};
176152
| {cstate_desc: TypedWellFormed(typed_program)} =>
177153
let warnings =
178154
List.map(warning_to_diagnostic, Grain_utils.Warnings.get_warnings());
179155
{
180156
program: Some(typed_program),
181-
error: None,
157+
error: [],
182158
warnings,
183159
};
184160
| _ =>
@@ -195,13 +171,14 @@ let compile_source = (uri, source) => {
195171

196172
{
197173
program: None,
198-
error:
199-
Some({
174+
error: [
175+
{
200176
range,
201177
severity: Error,
202178
message: "Compilation failed with an internal error",
203179
related_information: [],
204-
}),
180+
},
181+
],
205182
warnings: [],
206183
};
207184
};
@@ -211,13 +188,9 @@ let send_diagnostics =
211188
(
212189
~uri,
213190
warnings: list(Protocol.diagnostic),
214-
error: option(Protocol.diagnostic),
191+
errors: list(Protocol.diagnostic),
215192
) => {
216-
let diagnostics =
217-
switch (error) {
218-
| None => warnings
219-
| Some(err) => [err, ...warnings]
220-
};
193+
let diagnostics = List.append(errors, warnings);
221194

222195
Protocol.notification(
223196
~method="textDocument/publishDiagnostics",
@@ -259,7 +232,7 @@ module DidOpen = {
259232

260233
let compilerRes = compile_source(uri, params.text_document.text);
261234
switch (compilerRes) {
262-
| {program: Some(typed_program), error: None, warnings} =>
235+
| {program: Some(typed_program), error: [], warnings} =>
263236
Hashtbl.replace(
264237
compiled_code,
265238
uri,
@@ -271,10 +244,10 @@ module DidOpen = {
271244
);
272245
switch (warnings) {
273246
| [] => clear_diagnostics(~uri, ())
274-
| _ => send_diagnostics(~uri, warnings, None)
247+
| _ => send_diagnostics(~uri, warnings, [])
275248
};
276249

277-
| {program, error: Some(err), warnings} =>
250+
| {program, error: [_, ..._] as errs, warnings} =>
278251
switch (Hashtbl.find_opt(compiled_code, uri)) {
279252
| Some(code) =>
280253
Hashtbl.replace(
@@ -287,8 +260,8 @@ module DidOpen = {
287260
)
288261
| None => ()
289262
};
290-
send_diagnostics(~uri, warnings, Some(err));
291-
| {program: None, error: None, warnings} => clear_diagnostics(~uri, ())
263+
send_diagnostics(~uri, warnings, errs);
264+
| {program: None, error: [], warnings} => clear_diagnostics(~uri, ())
292265
};
293266
};
294267
};
@@ -326,7 +299,7 @@ module DidChange = {
326299

327300
let compilerRes = compile_source(uri, change.text);
328301
switch (compilerRes) {
329-
| {program: Some(typed_program), error: None, warnings} =>
302+
| {program: Some(typed_program), error: [], warnings} =>
330303
Hashtbl.replace(
331304
compiled_code,
332305
uri,
@@ -338,10 +311,10 @@ module DidChange = {
338311
);
339312
switch (warnings) {
340313
| [] => clear_diagnostics(~uri, ())
341-
| _ => send_diagnostics(~uri, warnings, None)
314+
| _ => send_diagnostics(~uri, warnings, [])
342315
};
343316

344-
| {program, error: Some(err), warnings} =>
317+
| {program, error: [_, ..._] as errs, warnings} =>
345318
switch (Hashtbl.find_opt(compiled_code, uri)) {
346319
| Some(code) =>
347320
Hashtbl.replace(
@@ -354,8 +327,8 @@ module DidChange = {
354327
)
355328
| None => ()
356329
};
357-
send_diagnostics(~uri, warnings, Some(err));
358-
| {program: None, error: None, warnings} => clear_diagnostics(~uri, ())
330+
send_diagnostics(~uri, warnings, errs);
331+
| {program: None, error: [], warnings} => clear_diagnostics(~uri, ())
359332
};
360333
};
361334
};

compiler/src/parsing/location.re

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ let register_error_of_exn = f => error_of_exn := [f, ...error_of_exn^];
538538

539539
exception Already_displayed_error = Warnings.Errors;
540540

541-
let error_of_exn = exn =>
541+
let error_of_exn = exn => {
542542
switch (exn) {
543543
| Already_displayed_error => Some(`Already_displayed)
544544
| _ =>
@@ -554,6 +554,7 @@ let error_of_exn = exn =>
554554

555555
loop(error_of_exn^);
556556
};
557+
};
557558

558559
let rec default_error_reporter = (ppf, {error_loc, msg, sub, if_highlight}) => {
559560
fprintf(ppf, "@[<v>%a %s", print_error, error_loc, msg);
@@ -593,7 +594,11 @@ let () =
593594

594595
external reraise: exn => 'a = "%reraise";
595596

597+
let reported_exceptions = ref([]);
598+
let reset_exceptions = () => reported_exceptions := [];
599+
596600
let rec report_exception = (ppf, exn) => {
601+
reported_exceptions := [exn, ...reported_exceptions^];
597602
let rec loop = (n, exn) =>
598603
switch (error_of_exn(exn)) {
599604
| None => reraise(exn)

compiler/src/parsing/location.rei

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ let error_of_printer: (t, (formatter, 'a) => unit, 'a) => error;
137137

138138
let error_of_printer_file: ((formatter, 'a) => unit, 'a) => error;
139139

140+
let reported_exceptions: ref(list(exn));
141+
142+
let reset_exceptions: unit => unit;
143+
140144
let error_of_exn:
141145
exn =>
142146
option(

0 commit comments

Comments
 (0)