@@ -5,11 +5,14 @@ use std::path::{Path, PathBuf};
5
5
use rustc_ast:: ast;
6
6
use rustc_ast:: visit:: Visitor ;
7
7
use rustc_span:: symbol:: { self , sym, Symbol } ;
8
+ use thiserror:: Error ;
8
9
9
10
use crate :: attr:: MetaVisitor ;
10
11
use crate :: config:: FileName ;
11
12
use crate :: items:: is_mod_decl;
12
- use crate :: syntux:: parser:: { Directory , DirectoryOwnership , ModulePathSuccess , Parser } ;
13
+ use crate :: syntux:: parser:: {
14
+ Directory , DirectoryOwnership , ModulePathSuccess , Parser , ParserError ,
15
+ } ;
13
16
use crate :: syntux:: session:: ParseSess ;
14
17
use crate :: utils:: contains_skip;
15
18
@@ -29,6 +32,24 @@ pub(crate) struct ModResolver<'ast, 'sess> {
29
32
recursive : bool ,
30
33
}
31
34
35
+ /// Represents errors while trying to resolve modules.
36
+ #[ error( "failed to resolve mod `{module}`: {kind}" ) ]
37
+ #[ derive( Debug , Error ) ]
38
+ pub struct ModuleResolutionError {
39
+ module : String ,
40
+ kind : ModuleResolutionErrorKind ,
41
+ }
42
+
43
+ #[ derive( Debug , Error ) ]
44
+ pub ( crate ) enum ModuleResolutionErrorKind {
45
+ /// Find a file that cannot be parsed.
46
+ #[ error( "cannot parse {file}" ) ]
47
+ ParseError { file : PathBuf } ,
48
+ /// File cannot be found.
49
+ #[ error( "{file} does not exist" ) ]
50
+ NotFound { file : PathBuf } ,
51
+ }
52
+
32
53
#[ derive( Clone ) ]
33
54
enum SubModKind < ' a , ' ast > {
34
55
/// `mod foo;`
@@ -63,7 +84,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
63
84
pub ( crate ) fn visit_crate (
64
85
mut self ,
65
86
krate : & ' ast ast:: Crate ,
66
- ) -> Result < FileModMap < ' ast > , String > {
87
+ ) -> Result < FileModMap < ' ast > , ModuleResolutionError > {
67
88
let root_filename = self . parse_sess . span_to_filename ( krate. span ) ;
68
89
self . directory . path = match root_filename {
69
90
FileName :: Real ( ref p) => p. parent ( ) . unwrap_or ( Path :: new ( "" ) ) . to_path_buf ( ) ,
@@ -81,7 +102,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
81
102
}
82
103
83
104
/// Visit `cfg_if` macro and look for module declarations.
84
- fn visit_cfg_if ( & mut self , item : Cow < ' ast , ast:: Item > ) -> Result < ( ) , String > {
105
+ fn visit_cfg_if ( & mut self , item : Cow < ' ast , ast:: Item > ) -> Result < ( ) , ModuleResolutionError > {
85
106
let mut visitor = visitor:: CfgIfVisitor :: new ( self . parse_sess ) ;
86
107
visitor. visit_item ( & item) ;
87
108
for module_item in visitor. mods ( ) {
@@ -93,7 +114,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
93
114
}
94
115
95
116
/// Visit modules defined inside macro calls.
96
- fn visit_mod_outside_ast ( & mut self , module : ast:: Mod ) -> Result < ( ) , String > {
117
+ fn visit_mod_outside_ast ( & mut self , module : ast:: Mod ) -> Result < ( ) , ModuleResolutionError > {
97
118
for item in module. items {
98
119
if is_cfg_if ( & item) {
99
120
self . visit_cfg_if ( Cow :: Owned ( item. into_inner ( ) ) ) ?;
@@ -108,7 +129,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
108
129
}
109
130
110
131
/// Visit modules from AST.
111
- fn visit_mod_from_ast ( & mut self , module : & ' ast ast:: Mod ) -> Result < ( ) , String > {
132
+ fn visit_mod_from_ast ( & mut self , module : & ' ast ast:: Mod ) -> Result < ( ) , ModuleResolutionError > {
112
133
for item in & module. items {
113
134
if is_cfg_if ( item) {
114
135
self . visit_cfg_if ( Cow :: Borrowed ( item) ) ?;
@@ -125,7 +146,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
125
146
& mut self ,
126
147
item : & ' c ast:: Item ,
127
148
sub_mod : Cow < ' ast , ast:: Mod > ,
128
- ) -> Result < ( ) , String > {
149
+ ) -> Result < ( ) , ModuleResolutionError > {
129
150
let old_directory = self . directory . clone ( ) ;
130
151
let sub_mod_kind = self . peek_sub_mod ( item, & sub_mod) ?;
131
152
if let Some ( sub_mod_kind) = sub_mod_kind {
@@ -141,7 +162,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
141
162
& self ,
142
163
item : & ' c ast:: Item ,
143
164
sub_mod : & Cow < ' ast , ast:: Mod > ,
144
- ) -> Result < Option < SubModKind < ' c , ' ast > > , String > {
165
+ ) -> Result < Option < SubModKind < ' c , ' ast > > , ModuleResolutionError > {
145
166
if contains_skip ( & item. attrs ) {
146
167
return Ok ( None ) ;
147
168
}
@@ -165,7 +186,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
165
186
& mut self ,
166
187
sub_mod_kind : SubModKind < ' c , ' ast > ,
167
188
_sub_mod : Cow < ' ast , ast:: Mod > ,
168
- ) -> Result < ( ) , String > {
189
+ ) -> Result < ( ) , ModuleResolutionError > {
169
190
match sub_mod_kind {
170
191
SubModKind :: External ( mod_path, _, sub_mod) => {
171
192
self . file_map
@@ -188,7 +209,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
188
209
& mut self ,
189
210
sub_mod : Cow < ' ast , ast:: Mod > ,
190
211
sub_mod_kind : SubModKind < ' c , ' ast > ,
191
- ) -> Result < ( ) , String > {
212
+ ) -> Result < ( ) , ModuleResolutionError > {
192
213
match sub_mod_kind {
193
214
SubModKind :: External ( mod_path, directory_ownership, sub_mod) => {
194
215
let directory = Directory {
@@ -226,7 +247,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
226
247
& mut self ,
227
248
sub_mod : Cow < ' ast , ast:: Mod > ,
228
249
directory : Option < Directory > ,
229
- ) -> Result < ( ) , String > {
250
+ ) -> Result < ( ) , ModuleResolutionError > {
230
251
if let Some ( directory) = directory {
231
252
self . directory = directory;
232
253
}
@@ -242,7 +263,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
242
263
mod_name : symbol:: Ident ,
243
264
attrs : & [ ast:: Attribute ] ,
244
265
sub_mod : & Cow < ' ast , ast:: Mod > ,
245
- ) -> Result < Option < SubModKind < ' c , ' ast > > , String > {
266
+ ) -> Result < Option < SubModKind < ' c , ' ast > > , ModuleResolutionError > {
246
267
let relative = match self . directory . ownership {
247
268
DirectoryOwnership :: Owned { relative } => relative,
248
269
DirectoryOwnership :: UnownedViaBlock | DirectoryOwnership :: UnownedViaMod => None ,
@@ -252,16 +273,20 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
252
273
return Ok ( None ) ;
253
274
}
254
275
return match Parser :: parse_file_as_module ( self . parse_sess , & path, sub_mod. inner ) {
255
- Some ( ( _, ref attrs) ) if contains_skip ( attrs) => Ok ( None ) ,
256
- Some ( ( m, _) ) => Ok ( Some ( SubModKind :: External (
276
+ Ok ( ( _, ref attrs) ) if contains_skip ( attrs) => Ok ( None ) ,
277
+ Ok ( ( m, _) ) => Ok ( Some ( SubModKind :: External (
257
278
path,
258
279
DirectoryOwnership :: Owned { relative : None } ,
259
280
Cow :: Owned ( m) ,
260
281
) ) ) ,
261
- None => Err ( format ! (
262
- "Failed to find module {} in {:?} {:?}" ,
263
- mod_name, self . directory. path, relative,
264
- ) ) ,
282
+ Err ( ParserError :: ParseError ) => Err ( ModuleResolutionError {
283
+ module : mod_name. to_string ( ) ,
284
+ kind : ModuleResolutionErrorKind :: ParseError { file : path } ,
285
+ } ) ,
286
+ Err ( ..) => Err ( ModuleResolutionError {
287
+ module : mod_name. to_string ( ) ,
288
+ kind : ModuleResolutionErrorKind :: NotFound { file : path } ,
289
+ } ) ,
265
290
} ;
266
291
}
267
292
@@ -291,22 +316,26 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
291
316
}
292
317
}
293
318
match Parser :: parse_file_as_module ( self . parse_sess , & path, sub_mod. inner ) {
294
- Some ( ( _, ref attrs) ) if contains_skip ( attrs) => Ok ( None ) ,
295
- Some ( ( m, _) ) if outside_mods_empty => {
319
+ Ok ( ( _, ref attrs) ) if contains_skip ( attrs) => Ok ( None ) ,
320
+ Ok ( ( m, _) ) if outside_mods_empty => {
296
321
Ok ( Some ( SubModKind :: External ( path, ownership, Cow :: Owned ( m) ) ) )
297
322
}
298
- Some ( ( m, _) ) => {
323
+ Ok ( ( m, _) ) => {
299
324
mods_outside_ast. push ( ( path. clone ( ) , ownership, Cow :: Owned ( m) ) ) ;
300
325
if should_insert {
301
326
mods_outside_ast. push ( ( path, ownership, sub_mod. clone ( ) ) ) ;
302
327
}
303
328
Ok ( Some ( SubModKind :: MultiExternal ( mods_outside_ast) ) )
304
329
}
305
- None if outside_mods_empty => Err ( format ! (
306
- "Failed to find module {} in {:?} {:?}" ,
307
- mod_name, self . directory. path, relative,
308
- ) ) ,
309
- None => {
330
+ Err ( ParserError :: ParseError ) => Err ( ModuleResolutionError {
331
+ module : mod_name. to_string ( ) ,
332
+ kind : ModuleResolutionErrorKind :: ParseError { file : path } ,
333
+ } ) ,
334
+ Err ( ..) if outside_mods_empty => Err ( ModuleResolutionError {
335
+ module : mod_name. to_string ( ) ,
336
+ kind : ModuleResolutionErrorKind :: NotFound { file : path } ,
337
+ } ) ,
338
+ Err ( ..) => {
310
339
if should_insert {
311
340
mods_outside_ast. push ( ( path, ownership, sub_mod. clone ( ) ) ) ;
312
341
}
@@ -320,10 +349,12 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
320
349
}
321
350
Err ( mut e) => {
322
351
e. cancel ( ) ;
323
- Err ( format ! (
324
- "Failed to find module {} in {:?} {:?}" ,
325
- mod_name, self . directory. path, relative,
326
- ) )
352
+ Err ( ModuleResolutionError {
353
+ module : mod_name. to_string ( ) ,
354
+ kind : ModuleResolutionErrorKind :: NotFound {
355
+ file : self . directory . path . clone ( ) ,
356
+ } ,
357
+ } )
327
358
}
328
359
}
329
360
}
@@ -379,9 +410,9 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
379
410
}
380
411
let m = match Parser :: parse_file_as_module ( self . parse_sess , & actual_path, sub_mod. inner )
381
412
{
382
- Some ( ( _, ref attrs) ) if contains_skip ( attrs) => continue ,
383
- Some ( ( m, _) ) => m,
384
- None => continue ,
413
+ Ok ( ( _, ref attrs) ) if contains_skip ( attrs) => continue ,
414
+ Ok ( ( m, _) ) => m,
415
+ Err ( .. ) => continue ,
385
416
} ;
386
417
387
418
result. push ( (
0 commit comments