1
1
use crate :: base:: ModuleData ;
2
2
use rustc_ast:: ptr:: P ;
3
3
use rustc_ast:: { token, Attribute , Item } ;
4
- use rustc_errors:: { struct_span_err, PResult } ;
4
+ use rustc_errors:: { struct_span_err, DiagnosticBuilder } ;
5
5
use rustc_parse:: new_parser_from_file;
6
6
use rustc_session:: parse:: ParseSess ;
7
7
use rustc_session:: Session ;
@@ -19,14 +19,6 @@ pub enum DirOwnership {
19
19
UnownedViaBlock ,
20
20
}
21
21
22
- /// Information about the path to a module.
23
- // Public for rustfmt usage.
24
- pub struct ModulePath < ' a > {
25
- name : String ,
26
- path_exists : bool ,
27
- pub result : PResult < ' a , ModulePathSuccess > ,
28
- }
29
-
30
22
// Public for rustfmt usage.
31
23
pub struct ModulePathSuccess {
32
24
pub file_path : PathBuf ,
@@ -41,6 +33,14 @@ crate struct ParsedExternalMod {
41
33
pub dir_ownership : DirOwnership ,
42
34
}
43
35
36
+ pub enum ModError < ' a > {
37
+ CircularInclusion ( Vec < PathBuf > ) ,
38
+ ModInBlock ( Option < Ident > ) ,
39
+ FileNotFound ( Ident , PathBuf ) ,
40
+ MultipleCandidates ( Ident , String , String ) ,
41
+ ParserError ( DiagnosticBuilder < ' a > ) ,
42
+ }
43
+
44
44
crate fn parse_external_mod (
45
45
sess : & Session ,
46
46
ident : Ident ,
@@ -50,47 +50,33 @@ crate fn parse_external_mod(
50
50
attrs : & mut Vec < Attribute > ,
51
51
) -> ParsedExternalMod {
52
52
// We bail on the first error, but that error does not cause a fatal error... (1)
53
- let result: PResult < ' _ , _ > = try {
53
+ let result: Result < _ , ModError < ' _ > > = try {
54
54
// Extract the file path and the new ownership.
55
- let mp = mod_file_path ( sess, ident, span , & attrs, & module. dir_path , dir_ownership) ?;
55
+ let mp = mod_file_path ( sess, ident, & attrs, & module. dir_path , dir_ownership) ?;
56
56
dir_ownership = mp. dir_ownership ;
57
57
58
58
// Ensure file paths are acyclic.
59
- error_on_circular_module ( & sess. parse_sess , span, & mp. file_path , & module. file_path_stack ) ?;
59
+ if let Some ( pos) = module. file_path_stack . iter ( ) . position ( |p| p == & mp. file_path ) {
60
+ Err ( ModError :: CircularInclusion ( module. file_path_stack [ pos..] . to_vec ( ) ) ) ?;
61
+ }
60
62
61
63
// Actually parse the external file as a module.
62
64
let mut parser = new_parser_from_file ( & sess. parse_sess , & mp. file_path , Some ( span) ) ;
63
- let ( mut inner_attrs, items, inner_span) = parser. parse_mod ( & token:: Eof ) ?;
65
+ let ( mut inner_attrs, items, inner_span) =
66
+ parser. parse_mod ( & token:: Eof ) . map_err ( |err| ModError :: ParserError ( err) ) ?;
64
67
attrs. append ( & mut inner_attrs) ;
65
68
( items, inner_span, mp. file_path )
66
69
} ;
67
70
// (1) ...instead, we return a dummy module.
68
- let ( items, inner_span, file_path) = result. map_err ( |mut err| err. emit ( ) ) . unwrap_or_default ( ) ;
71
+ let ( items, inner_span, file_path) =
72
+ result. map_err ( |err| err. report ( sess, span) ) . unwrap_or_default ( ) ;
69
73
70
74
// Extract the directory path for submodules of the module.
71
75
let dir_path = file_path. parent ( ) . unwrap_or ( & file_path) . to_owned ( ) ;
72
76
73
77
ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership }
74
78
}
75
79
76
- fn error_on_circular_module < ' a > (
77
- sess : & ' a ParseSess ,
78
- span : Span ,
79
- file_path : & Path ,
80
- file_path_stack : & [ PathBuf ] ,
81
- ) -> PResult < ' a , ( ) > {
82
- if let Some ( i) = file_path_stack. iter ( ) . position ( |p| * p == file_path) {
83
- let mut err = String :: from ( "circular modules: " ) ;
84
- for p in & file_path_stack[ i..] {
85
- err. push_str ( & p. to_string_lossy ( ) ) ;
86
- err. push_str ( " -> " ) ;
87
- }
88
- err. push_str ( & file_path. to_string_lossy ( ) ) ;
89
- return Err ( sess. span_diagnostic . struct_span_err ( span, & err[ ..] ) ) ;
90
- }
91
- Ok ( ( ) )
92
- }
93
-
94
80
crate fn mod_dir_path (
95
81
sess : & Session ,
96
82
ident : Ident ,
@@ -125,11 +111,10 @@ crate fn mod_dir_path(
125
111
fn mod_file_path < ' a > (
126
112
sess : & ' a Session ,
127
113
ident : Ident ,
128
- span : Span ,
129
114
attrs : & [ Attribute ] ,
130
115
dir_path : & Path ,
131
116
dir_ownership : DirOwnership ,
132
- ) -> PResult < ' a , ModulePathSuccess > {
117
+ ) -> Result < ModulePathSuccess , ModError < ' a > > {
133
118
if let Some ( file_path) = mod_file_path_from_attr ( sess, attrs, dir_path) {
134
119
// All `#[path]` files are treated as though they are a `mod.rs` file.
135
120
// This means that `mod foo;` declarations inside `#[path]`-included
@@ -146,30 +131,14 @@ fn mod_file_path<'a>(
146
131
DirOwnership :: Owned { relative } => relative,
147
132
DirOwnership :: UnownedViaBlock => None ,
148
133
} ;
149
- let ModulePath { path_exists, name, result } =
150
- default_submod_path ( & sess. parse_sess , ident, span, relative, dir_path) ;
134
+ let result = default_submod_path ( & sess. parse_sess , ident, relative, dir_path) ;
151
135
match dir_ownership {
152
- DirOwnership :: Owned { .. } => Ok ( result?) ,
153
- DirOwnership :: UnownedViaBlock => {
154
- let _ = result. map_err ( |mut err| err. cancel ( ) ) ;
155
- error_decl_mod_in_block ( & sess. parse_sess , span, path_exists, & name)
156
- }
157
- }
158
- }
159
-
160
- fn error_decl_mod_in_block < ' a , T > (
161
- sess : & ' a ParseSess ,
162
- span : Span ,
163
- path_exists : bool ,
164
- name : & str ,
165
- ) -> PResult < ' a , T > {
166
- let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute" ;
167
- let mut err = sess. span_diagnostic . struct_span_err ( span, msg) ;
168
- if path_exists {
169
- let msg = format ! ( "Maybe `use` the module `{}` instead of redeclaring it" , name) ;
170
- err. span_note ( span, & msg) ;
136
+ DirOwnership :: Owned { .. } => result,
137
+ DirOwnership :: UnownedViaBlock => Err ( ModError :: ModInBlock ( match result {
138
+ Ok ( _) | Err ( ModError :: MultipleCandidates ( ..) ) => Some ( ident) ,
139
+ _ => None ,
140
+ } ) ) ,
171
141
}
172
- Err ( err)
173
142
}
174
143
175
144
/// Derive a submodule path from the first found `#[path = "path_string"]`.
@@ -197,10 +166,9 @@ fn mod_file_path_from_attr(
197
166
pub fn default_submod_path < ' a > (
198
167
sess : & ' a ParseSess ,
199
168
ident : Ident ,
200
- span : Span ,
201
169
relative : Option < Ident > ,
202
170
dir_path : & Path ,
203
- ) -> ModulePath < ' a > {
171
+ ) -> Result < ModulePathSuccess , ModError < ' a > > {
204
172
// If we're in a foo.rs file instead of a mod.rs file,
205
173
// we need to look for submodules in
206
174
// `./foo/<ident>.rs` and `./foo/<ident>/mod.rs` rather than
@@ -222,7 +190,7 @@ pub fn default_submod_path<'a>(
222
190
let default_exists = sess. source_map ( ) . file_exists ( & default_path) ;
223
191
let secondary_exists = sess. source_map ( ) . file_exists ( & secondary_path) ;
224
192
225
- let result = match ( default_exists, secondary_exists) {
193
+ match ( default_exists, secondary_exists) {
226
194
( true , false ) => Ok ( ModulePathSuccess {
227
195
file_path : default_path,
228
196
dir_ownership : DirOwnership :: Owned { relative : Some ( ident) } ,
@@ -231,35 +199,65 @@ pub fn default_submod_path<'a>(
231
199
file_path : secondary_path,
232
200
dir_ownership : DirOwnership :: Owned { relative : None } ,
233
201
} ) ,
234
- ( false , false ) => {
235
- let mut err = struct_span_err ! (
236
- sess. span_diagnostic,
237
- span,
238
- E0583 ,
239
- "file not found for module `{}`" ,
240
- mod_name,
241
- ) ;
242
- err. help ( & format ! (
243
- "to create the module `{}`, create file \" {}\" " ,
244
- mod_name,
245
- default_path. display( ) ,
246
- ) ) ;
247
- Err ( err)
248
- }
202
+ ( false , false ) => Err ( ModError :: FileNotFound ( ident, default_path) ) ,
249
203
( true , true ) => {
250
- let mut err = struct_span_err ! (
251
- sess. span_diagnostic,
252
- span,
253
- E0761 ,
254
- "file for module `{}` found at both {} and {}" ,
255
- mod_name,
256
- default_path_str,
257
- secondary_path_str,
258
- ) ;
259
- err. help ( "delete or rename one of them to remove the ambiguity" ) ;
260
- Err ( err)
204
+ Err ( ModError :: MultipleCandidates ( ident, default_path_str, secondary_path_str) )
261
205
}
262
- } ;
206
+ }
207
+ }
263
208
264
- ModulePath { name : mod_name, path_exists : default_exists || secondary_exists, result }
209
+ impl ModError < ' _ > {
210
+ fn report ( self , sess : & Session , span : Span ) {
211
+ let diag = & sess. parse_sess . span_diagnostic ;
212
+ match self {
213
+ ModError :: CircularInclusion ( file_paths) => {
214
+ let mut msg = String :: from ( "circular modules: " ) ;
215
+ for file_path in & file_paths {
216
+ msg. push_str ( & file_path. display ( ) . to_string ( ) ) ;
217
+ msg. push_str ( " -> " ) ;
218
+ }
219
+ msg. push_str ( & file_paths[ 0 ] . display ( ) . to_string ( ) ) ;
220
+ diag. struct_span_err ( span, & msg)
221
+ }
222
+ ModError :: ModInBlock ( ident) => {
223
+ let msg = "cannot declare a non-inline module inside a block unless it has a path attribute" ;
224
+ let mut err = diag. struct_span_err ( span, msg) ;
225
+ if let Some ( ident) = ident {
226
+ let note =
227
+ format ! ( "maybe `use` the module `{}` instead of redeclaring it" , ident) ;
228
+ err. span_note ( span, & note) ;
229
+ }
230
+ err
231
+ }
232
+ ModError :: FileNotFound ( ident, default_path) => {
233
+ let mut err = struct_span_err ! (
234
+ diag,
235
+ span,
236
+ E0583 ,
237
+ "file not found for module `{}`" ,
238
+ ident,
239
+ ) ;
240
+ err. help ( & format ! (
241
+ "to create the module `{}`, create file \" {}\" " ,
242
+ ident,
243
+ default_path. display( ) ,
244
+ ) ) ;
245
+ err
246
+ }
247
+ ModError :: MultipleCandidates ( ident, default_path_short, secondary_path_short) => {
248
+ let mut err = struct_span_err ! (
249
+ diag,
250
+ span,
251
+ E0761 ,
252
+ "file for module `{}` found at both {} and {}" ,
253
+ ident,
254
+ default_path_short,
255
+ secondary_path_short,
256
+ ) ;
257
+ err. help ( "delete or rename one of them to remove the ambiguity" ) ;
258
+ err
259
+ }
260
+ ModError :: ParserError ( err) => err,
261
+ } . emit ( )
262
+ }
265
263
}
0 commit comments