Skip to content

Commit d8cd8f1

Browse files
authored
fix(compiler): Raise appropriate exception when modules are missing during dependency graph construction (#1485)
1 parent 6a09953 commit d8cd8f1

File tree

7 files changed

+76
-15
lines changed

7 files changed

+76
-15
lines changed

compiler/src/parsing/driver.re

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ let parse = (~name=?, lexbuf, source): Parsetree.parsed_program => {
126126
};
127127
};
128128

129-
let scan_for_imports = (~defer_errors=true, filename: string): list(string) => {
129+
let scan_for_imports =
130+
(~defer_errors=true, filename: string): list(loc(string)) => {
130131
let ic = open_in(filename);
131132
let lexbuf = Sedlexing.Utf8.from_channel(ic);
132133
try({
@@ -142,8 +143,9 @@ let scan_for_imports = (~defer_errors=true, filename: string): list(string) => {
142143
List.map(
143144
o => {
144145
switch (o) {
145-
| Grain_utils.Config.Pervasives_mod => "pervasives"
146-
| Grain_utils.Config.Gc_mod => "runtime/gc"
146+
| Grain_utils.Config.Pervasives_mod =>
147+
Location.mknoloc("pervasives")
148+
| Grain_utils.Config.Gc_mod => Location.mknoloc("runtime/gc")
147149
}
148150
},
149151
switch (comments) {
@@ -158,12 +160,12 @@ let scan_for_imports = (~defer_errors=true, filename: string): list(string) => {
158160
);
159161
let found_imports = ref([]);
160162
let iter_mod = (self, import) =>
161-
found_imports := [import.Parsetree.pimp_path.txt, ...found_imports^];
163+
found_imports := [import.Parsetree.pimp_path, ...found_imports^];
162164
let iterator = {...Ast_iterator.default_iterator, import: iter_mod};
163165
List.iter(iterator.toplevel(iterator), statements);
164166
close_in(ic);
165167
List.sort_uniq(
166-
String.compare,
168+
(a, b) => String.compare(a.txt, b.txt),
167169
List.append(implicit_opens, found_imports^),
168170
);
169171
}) {

compiler/src/parsing/driver.rei

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ let parse:
44
(~name: string=?, Sedlexing.lexbuf, unit => string) =>
55
Parsetree.parsed_program;
66

7-
let scan_for_imports: (~defer_errors: bool=?, string) => list(string);
7+
let scan_for_imports:
8+
(~defer_errors: bool=?, string) => list(Location.loc(string));

compiler/src/typed/module_resolution.re

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ open Cmi_format;
44

55
type error =
66
| Missing_module(Location.t, Path.t, Path.t)
7-
| No_module_file(string, option(string));
7+
| No_module_file(Location.t, string, option(string));
88

99
exception Error(error);
1010

@@ -280,16 +280,32 @@ module Dependency_graph =
280280
let from_srcpath = srcpath => {
281281
List.map(
282282
name => {
283-
let located = locate_module(base_dir, active_search_path, name);
283+
let located =
284+
try(
285+
locate_module(
286+
base_dir,
287+
active_search_path,
288+
name.Location.txt,
289+
)
290+
) {
291+
| Not_found =>
292+
error(
293+
No_module_file(
294+
name.Location.loc,
295+
name.Location.txt,
296+
None,
297+
),
298+
)
299+
};
284300
let out_file_name = located_to_out_file_name(located);
285301
let existing_dependency = lookup(out_file_name);
286302
switch (existing_dependency) {
287303
| Some(ed) =>
288-
Hashtbl.add(ed.dn_unit_name, Some(dn), name);
304+
Hashtbl.add(ed.dn_unit_name, Some(dn), name.Location.txt);
289305
ed;
290306
| None =>
291307
let tbl = Hashtbl.create(8);
292-
Hashtbl.add(tbl, Some(dn), name);
308+
Hashtbl.add(tbl, Some(dn), name.Location.txt);
293309
{
294310
dn_unit_name: tbl,
295311
dn_file_name: out_file_name,
@@ -315,7 +331,16 @@ module Dependency_graph =
315331
List.map(
316332
((name, _)) => {
317333
let located =
318-
locate_module(base_dir, active_search_path, name);
334+
try(locate_module(base_dir, active_search_path, name)) {
335+
| Not_found =>
336+
error(
337+
No_module_file(
338+
Location.in_file(dn.dn_file_name),
339+
name,
340+
None,
341+
),
342+
)
343+
};
319344
let out_file_name = located_to_out_file_name(located);
320345
let existing_dependency = lookup(out_file_name);
321346
switch (existing_dependency) {
@@ -435,7 +460,7 @@ let locate_module_file = (~loc, ~disable_relpath=false, unit_name) => {
435460
let path = Config.module_search_path();
436461
let located =
437462
try(locate_module(~disable_relpath, base_dir, path, unit_name)) {
438-
| Not_found => error(No_module_file(unit_name, None))
463+
| Not_found => error(No_module_file(loc, unit_name, None))
439464
};
440465
let out_file = located_to_out_file_name(located);
441466
let current_dep_node =
@@ -509,14 +534,16 @@ let report_error = ppf =>
509534
"was not found",
510535
);
511536
}
512-
| No_module_file(m, None) => fprintf(ppf, "Missing file for module %s", m)
513-
| No_module_file(m, Some(msg)) =>
537+
| No_module_file(_, m, None) =>
538+
fprintf(ppf, "Missing file for module %s", m)
539+
| No_module_file(_, m, Some(msg)) =>
514540
fprintf(ppf, "Missing file for module %s: %s", m, msg);
515541

516542
let () =
517543
Location.register_error_of_exn(
518544
fun
519-
| Error(Missing_module(loc, _, _) as err) when loc != Location.dummy_loc =>
545+
| Error(Missing_module(loc, _, _) as err)
546+
| Error(No_module_file(loc, _, _) as err) when loc != Location.dummy_loc =>
520547
Some(Location.error_of_printer(loc, report_error, err))
521548
| Error(err) => Some(Location.error_of_printer_file(report_error, err))
522549
| _ => None,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import Number from "number"
2+
import Foo from "./foo"
3+
4+
export let min = Number.min
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Broken from "./broken"
2+
3+
print(Broken.min(2, 3))

compiler/test/runner.re

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,24 @@ let makeFileRunner =
295295
});
296296
};
297297

298+
let makeFileCompileErrorRunner = (test, name, filename, expected) => {
299+
test(
300+
name,
301+
({expect}) => {
302+
let error =
303+
try({
304+
let infile = grainfile(filename);
305+
let outfile = wasmfile(name);
306+
ignore @@ compile_file(infile, outfile);
307+
"";
308+
}) {
309+
| exn => Printexc.to_string(exn)
310+
};
311+
expect.string(error).toMatch(expected);
312+
},
313+
);
314+
};
315+
298316
let makeFileErrorRunner = (test, name, filename, expected) => {
299317
test(
300318
name,

compiler/test/suites/imports.re

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe("imports", ({test, testSkip}) => {
99
let assertCompileError = makeCompileErrorRunner(test);
1010
let assertRun = makeRunner(test_or_skip);
1111
let assertFileRun = makeFileRunner(test_or_skip);
12+
let assertFileCompileError = makeFileCompileErrorRunner(test_or_skip);
1213
let assertFileSnapshot = makeSnapshotFileRunner(test);
1314

1415
/* import * tests */
@@ -212,4 +213,9 @@ describe("imports", ({test, testSkip}) => {
212213
"import TList, { Empty } from \"tlists\"; let foo : TList.TList<String> = Empty; foo",
213214
);
214215
assertFileRun("relative_import_linking", "relativeImportLinking", "2\n2\n");
216+
assertFileCompileError(
217+
"import_broken",
218+
"brokenImports/main",
219+
"./broken.gr\", line 2, characters 16-23",
220+
);
215221
});

0 commit comments

Comments
 (0)