@@ -5,12 +5,13 @@ 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 :: config:: FileName ;
10
11
use crate :: formatting:: {
11
12
attr:: MetaVisitor ,
12
13
items:: is_mod_decl,
13
- syntux:: parser:: { Directory , DirectoryOwnership , ModulePathSuccess , Parser } ,
14
+ syntux:: parser:: { Directory , DirectoryOwnership , ModulePathSuccess , Parser , ParserError } ,
14
15
syntux:: session:: ParseSess ,
15
16
utils:: contains_skip,
16
17
} ;
@@ -31,6 +32,24 @@ pub(crate) struct ModResolver<'ast, 'sess> {
31
32
recursive : bool ,
32
33
}
33
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
+
34
53
#[ derive( Clone ) ]
35
54
enum SubModKind < ' a , ' ast > {
36
55
/// `mod foo;`
@@ -63,7 +82,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
63
82
pub ( crate ) fn visit_crate (
64
83
mut self ,
65
84
krate : & ' ast ast:: Crate ,
66
- ) -> Result < FileModMap < ' ast > , String > {
85
+ ) -> Result < FileModMap < ' ast > , ModuleResolutionError > {
67
86
let root_filename = self . parse_sess . span_to_filename ( krate. span ) ;
68
87
self . directory . path = match root_filename {
69
88
FileName :: Real ( ref p) => p. parent ( ) . unwrap_or_else ( || Path :: new ( "" ) ) . to_path_buf ( ) ,
@@ -81,7 +100,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
81
100
}
82
101
83
102
/// Visit `cfg_if` macro and look for module declarations.
84
- fn visit_cfg_if ( & mut self , item : Cow < ' ast , ast:: Item > ) -> Result < ( ) , String > {
103
+ fn visit_cfg_if ( & mut self , item : Cow < ' ast , ast:: Item > ) -> Result < ( ) , ModuleResolutionError > {
85
104
let mut visitor = visitor:: CfgIfVisitor :: new ( self . parse_sess ) ;
86
105
visitor. visit_item ( & item) ;
87
106
for module_item in visitor. mods ( ) {
@@ -93,7 +112,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
93
112
}
94
113
95
114
/// Visit modules defined inside macro calls.
96
- fn visit_mod_outside_ast ( & mut self , module : ast:: Mod ) -> Result < ( ) , String > {
115
+ fn visit_mod_outside_ast ( & mut self , module : ast:: Mod ) -> Result < ( ) , ModuleResolutionError > {
97
116
for item in module. items {
98
117
if is_cfg_if ( & item) {
99
118
self . visit_cfg_if ( Cow :: Owned ( item. into_inner ( ) ) ) ?;
@@ -108,7 +127,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
108
127
}
109
128
110
129
/// Visit modules from AST.
111
- fn visit_mod_from_ast ( & mut self , module : & ' ast ast:: Mod ) -> Result < ( ) , String > {
130
+ fn visit_mod_from_ast ( & mut self , module : & ' ast ast:: Mod ) -> Result < ( ) , ModuleResolutionError > {
112
131
for item in & module. items {
113
132
if is_cfg_if ( item) {
114
133
self . visit_cfg_if ( Cow :: Borrowed ( item) ) ?;
@@ -125,7 +144,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
125
144
& mut self ,
126
145
item : & ' c ast:: Item ,
127
146
sub_mod : Cow < ' ast , ast:: Mod > ,
128
- ) -> Result < ( ) , String > {
147
+ ) -> Result < ( ) , ModuleResolutionError > {
129
148
let old_directory = self . directory . clone ( ) ;
130
149
let sub_mod_kind = self . peek_sub_mod ( item, & sub_mod) ?;
131
150
if let Some ( sub_mod_kind) = sub_mod_kind {
@@ -141,7 +160,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
141
160
& self ,
142
161
item : & ' c ast:: Item ,
143
162
sub_mod : & Cow < ' ast , ast:: Mod > ,
144
- ) -> Result < Option < SubModKind < ' c , ' ast > > , String > {
163
+ ) -> Result < Option < SubModKind < ' c , ' ast > > , ModuleResolutionError > {
145
164
if contains_skip ( & item. attrs ) {
146
165
return Ok ( None ) ;
147
166
}
@@ -160,7 +179,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
160
179
& mut self ,
161
180
sub_mod_kind : SubModKind < ' c , ' ast > ,
162
181
_sub_mod : Cow < ' ast , ast:: Mod > ,
163
- ) -> Result < ( ) , String > {
182
+ ) -> Result < ( ) , ModuleResolutionError > {
164
183
match sub_mod_kind {
165
184
SubModKind :: External ( mod_path, _, sub_mod) => {
166
185
self . file_map
@@ -183,7 +202,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
183
202
& mut self ,
184
203
sub_mod : Cow < ' ast , ast:: Mod > ,
185
204
sub_mod_kind : SubModKind < ' c , ' ast > ,
186
- ) -> Result < ( ) , String > {
205
+ ) -> Result < ( ) , ModuleResolutionError > {
187
206
match sub_mod_kind {
188
207
SubModKind :: External ( mod_path, directory_ownership, sub_mod) => {
189
208
let directory = Directory {
@@ -213,7 +232,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
213
232
& mut self ,
214
233
sub_mod : Cow < ' ast , ast:: Mod > ,
215
234
directory : Option < Directory > ,
216
- ) -> Result < ( ) , String > {
235
+ ) -> Result < ( ) , ModuleResolutionError > {
217
236
if let Some ( directory) = directory {
218
237
self . directory = directory;
219
238
}
@@ -229,7 +248,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
229
248
mod_name : symbol:: Ident ,
230
249
attrs : & [ ast:: Attribute ] ,
231
250
sub_mod : & Cow < ' ast , ast:: Mod > ,
232
- ) -> Result < Option < SubModKind < ' c , ' ast > > , String > {
251
+ ) -> Result < Option < SubModKind < ' c , ' ast > > , ModuleResolutionError > {
233
252
let relative = match self . directory . ownership {
234
253
DirectoryOwnership :: Owned { relative } => relative,
235
254
DirectoryOwnership :: UnownedViaBlock | DirectoryOwnership :: UnownedViaMod => None ,
@@ -239,15 +258,19 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
239
258
return Ok ( None ) ;
240
259
}
241
260
return match Parser :: parse_file_as_module ( self . parse_sess , & path, sub_mod. inner ) {
242
- Some ( m) => Ok ( Some ( SubModKind :: External (
261
+ Ok ( m) => Ok ( Some ( SubModKind :: External (
243
262
path,
244
263
DirectoryOwnership :: Owned { relative : None } ,
245
264
Cow :: Owned ( m) ,
246
265
) ) ) ,
247
- None => Err ( format ! (
248
- "Failed to find module {} in {:?} {:?}" ,
249
- mod_name, self . directory. path, relative,
250
- ) ) ,
266
+ Err ( ParserError :: ParseError ) => Err ( ModuleResolutionError {
267
+ module : mod_name. to_string ( ) ,
268
+ kind : ModuleResolutionErrorKind :: ParseError { file : path } ,
269
+ } ) ,
270
+ Err ( ..) => Err ( ModuleResolutionError {
271
+ module : mod_name. to_string ( ) ,
272
+ kind : ModuleResolutionErrorKind :: NotFound { file : path } ,
273
+ } ) ,
251
274
} ;
252
275
}
253
276
@@ -277,21 +300,25 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
277
300
}
278
301
}
279
302
match Parser :: parse_file_as_module ( self . parse_sess , & path, sub_mod. inner ) {
280
- Some ( m) if outside_mods_empty => {
303
+ Ok ( m) if outside_mods_empty => {
281
304
Ok ( Some ( SubModKind :: External ( path, ownership, Cow :: Owned ( m) ) ) )
282
305
}
283
- Some ( m) => {
306
+ Ok ( m) => {
284
307
mods_outside_ast. push ( ( path. clone ( ) , ownership, Cow :: Owned ( m) ) ) ;
285
308
if should_insert {
286
309
mods_outside_ast. push ( ( path, ownership, sub_mod. clone ( ) ) ) ;
287
310
}
288
311
Ok ( Some ( SubModKind :: MultiExternal ( mods_outside_ast) ) )
289
312
}
290
- None if outside_mods_empty => Err ( format ! (
291
- "Failed to find module {} in {:?} {:?}" ,
292
- mod_name, self . directory. path, relative,
293
- ) ) ,
294
- None => {
313
+ Err ( ParserError :: ParseError ) => Err ( ModuleResolutionError {
314
+ module : mod_name. to_string ( ) ,
315
+ kind : ModuleResolutionErrorKind :: ParseError { file : path } ,
316
+ } ) ,
317
+ Err ( ..) if outside_mods_empty => Err ( ModuleResolutionError {
318
+ module : mod_name. to_string ( ) ,
319
+ kind : ModuleResolutionErrorKind :: NotFound { file : path } ,
320
+ } ) ,
321
+ Err ( ..) => {
295
322
if should_insert {
296
323
mods_outside_ast. push ( ( path, ownership, sub_mod. clone ( ) ) ) ;
297
324
}
@@ -305,10 +332,12 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
305
332
}
306
333
Err ( mut e) => {
307
334
e. cancel ( ) ;
308
- Err ( format ! (
309
- "Failed to find module {} in {:?} {:?}" ,
310
- mod_name, self . directory. path, relative,
311
- ) )
335
+ Err ( ModuleResolutionError {
336
+ module : mod_name. to_string ( ) ,
337
+ kind : ModuleResolutionErrorKind :: NotFound {
338
+ file : self . directory . path . clone ( ) ,
339
+ } ,
340
+ } )
312
341
}
313
342
}
314
343
}
@@ -367,8 +396,8 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
367
396
368
397
let m = match Parser :: parse_file_as_module ( self . parse_sess , & actual_path, sub_mod. inner )
369
398
{
370
- Some ( m) => m,
371
- None => continue ,
399
+ Ok ( m) => m,
400
+ Err ( .. ) => continue ,
372
401
} ;
373
402
374
403
result. push ( (
0 commit comments