@@ -17,7 +17,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
17
17
use rustc_data_structures:: sync:: { AtomicU32 , Lrc , MappedReadGuard , ReadGuard , RwLock } ;
18
18
use std:: cmp;
19
19
use std:: hash:: Hash ;
20
- use std:: path:: { Path , PathBuf } ;
20
+ use std:: path:: { self , Path , PathBuf } ;
21
21
use std:: sync:: atomic:: Ordering ;
22
22
23
23
use std:: fs;
@@ -1071,12 +1071,24 @@ impl SourceMap {
1071
1071
1072
1072
pub fn ensure_source_file_source_present ( & self , source_file : Lrc < SourceFile > ) -> bool {
1073
1073
source_file. add_external_src ( || {
1074
- match source_file. name {
1075
- FileName :: Real ( ref name) if let Some ( local_path) = name. local_path ( ) => {
1076
- self . file_loader . read_file ( local_path) . ok ( )
1074
+ let FileName :: Real ( ref name) = source_file. name else {
1075
+ return None ;
1076
+ } ;
1077
+
1078
+ let local_path: Cow < ' _ , Path > = match name {
1079
+ RealFileName :: LocalPath ( local_path) => local_path. into ( ) ,
1080
+ RealFileName :: Remapped { local_path : Some ( local_path) , .. } => local_path. into ( ) ,
1081
+ RealFileName :: Remapped { local_path : None , virtual_name } => {
1082
+ // The compiler produces better error messages if the sources of dependencies
1083
+ // are available. Attempt to undo any path mapping so we can find remapped
1084
+ // dependencies.
1085
+ // We can only use the heuristic because `add_external_src` checks the file
1086
+ // content hash.
1087
+ self . path_mapping . reverse_map_prefix_heuristically ( virtual_name) ?. into ( )
1077
1088
}
1078
- _ => None ,
1079
- }
1089
+ } ;
1090
+
1091
+ self . file_loader . read_file ( & local_path) . ok ( )
1080
1092
} )
1081
1093
}
1082
1094
@@ -1277,4 +1289,43 @@ impl FilePathMapping {
1277
1289
}
1278
1290
}
1279
1291
}
1292
+
1293
+ /// Attempts to (heuristically) reverse a prefix mapping.
1294
+ ///
1295
+ /// Returns [`Some`] if there is exactly one mapping where the "to" part is
1296
+ /// a prefix of `path` and has at least one non-empty
1297
+ /// [`Normal`](path::Component::Normal) component. The component
1298
+ /// restriction exists to avoid reverse mapping overly generic paths like
1299
+ /// `/` or `.`).
1300
+ ///
1301
+ /// This is a heuristic and not guaranteed to return the actual original
1302
+ /// path! Do not rely on the result unless you have other means to verify
1303
+ /// that the mapping is correct (e.g. by checking the file content hash).
1304
+ #[ instrument( level = "debug" , skip( self ) , ret) ]
1305
+ fn reverse_map_prefix_heuristically ( & self , path : & Path ) -> Option < PathBuf > {
1306
+ let mut found = None ;
1307
+
1308
+ for ( from, to) in self . mapping . iter ( ) {
1309
+ let has_normal_component = to. components ( ) . any ( |c| match c {
1310
+ path:: Component :: Normal ( s) => !s. is_empty ( ) ,
1311
+ _ => false ,
1312
+ } ) ;
1313
+
1314
+ if !has_normal_component {
1315
+ continue ;
1316
+ }
1317
+
1318
+ let Ok ( rest) = path. strip_prefix ( to) else {
1319
+ continue ;
1320
+ } ;
1321
+
1322
+ if found. is_some ( ) {
1323
+ return None ;
1324
+ }
1325
+
1326
+ found = Some ( from. join ( rest) ) ;
1327
+ }
1328
+
1329
+ found
1330
+ }
1280
1331
}
0 commit comments