@@ -1116,6 +1116,83 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1116
1116
}
1117
1117
}
1118
1118
1119
+ /// Visit every module reachable from `start_module` and bring any proc and derive macro
1120
+ /// encountered into `self.macro_map` to be used for suggestions.
1121
+ fn lookup_macros_from_module ( & mut self ) {
1122
+ let parent_scope = ParentScope :: module ( self . graph_root , self ) ;
1123
+ let mut seen_modules = FxHashSet :: default ( ) ;
1124
+ let mut worklist = vec ! [ ( self . graph_root, ThinVec :: <ast:: PathSegment >:: new( ) , true ) ] ;
1125
+ let mut worklist_via_import = vec ! [ ] ;
1126
+
1127
+ while let Some ( ( in_module, path_segments, accessible) ) = match worklist. pop ( ) {
1128
+ None => worklist_via_import. pop ( ) ,
1129
+ Some ( x) => Some ( x) ,
1130
+ } {
1131
+ let in_module_is_extern = !in_module. opt_def_id ( ) . map_or ( false , |id| id. is_local ( ) ) ;
1132
+ // We have to visit module children in deterministic order to avoid
1133
+ // instabilities in reported imports (#43552).
1134
+ in_module. for_each_child ( self , |this, ident, _ns, name_binding| {
1135
+ if let Res :: Def ( DefKind :: Macro ( MacroKind :: Derive | MacroKind :: Attr ) , def_id) =
1136
+ name_binding. res ( )
1137
+ {
1138
+ // By doing this all *imported* macros get added to the `macro_map` even if they
1139
+ // are *unused*, which makes the later suggestions find them and work.
1140
+ let _ = this. get_macro_by_def_id ( def_id) ;
1141
+ }
1142
+ // avoid non-importable candidates
1143
+ if !name_binding. is_importable ( ) {
1144
+ return ;
1145
+ }
1146
+
1147
+ let child_accessible =
1148
+ accessible && this. is_accessible_from ( name_binding. vis , parent_scope. module ) ;
1149
+
1150
+ // do not venture inside inaccessible items of other crates
1151
+ if in_module_is_extern && !child_accessible {
1152
+ return ;
1153
+ }
1154
+
1155
+ let via_import = name_binding. is_import ( ) && !name_binding. is_extern_crate ( ) ;
1156
+
1157
+ // There is an assumption elsewhere that paths of variants are in the enum's
1158
+ // declaration and not imported. With this assumption, the variant component is
1159
+ // chopped and the rest of the path is assumed to be the enum's own path. For
1160
+ // errors where a variant is used as the type instead of the enum, this causes
1161
+ // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
1162
+ if via_import && name_binding. is_possibly_imported_variant ( ) {
1163
+ return ;
1164
+ }
1165
+
1166
+ // #90113: Do not count an inaccessible reexported item as a candidate.
1167
+ if let NameBindingKind :: Import { binding, .. } = name_binding. kind {
1168
+ if this. is_accessible_from ( binding. vis , parent_scope. module )
1169
+ && !this. is_accessible_from ( name_binding. vis , parent_scope. module )
1170
+ {
1171
+ return ;
1172
+ }
1173
+ }
1174
+
1175
+ // collect submodules to explore
1176
+ if let Some ( module) = name_binding. module ( ) {
1177
+ // form the path
1178
+ let mut path_segments = path_segments. clone ( ) ;
1179
+ path_segments. push ( ast:: PathSegment :: from_ident ( ident) ) ;
1180
+
1181
+ let is_extern_crate_that_also_appears_in_prelude =
1182
+ name_binding. is_extern_crate ( ) ;
1183
+
1184
+ if !is_extern_crate_that_also_appears_in_prelude {
1185
+ // add the module to the lookup
1186
+ if seen_modules. insert ( module. def_id ( ) ) {
1187
+ if via_import { & mut worklist_via_import } else { & mut worklist }
1188
+ . push ( ( module, path_segments, child_accessible) ) ;
1189
+ }
1190
+ }
1191
+ }
1192
+ } )
1193
+ }
1194
+ }
1195
+
1119
1196
fn lookup_import_candidates_from_module < FilterFn > (
1120
1197
& mut self ,
1121
1198
lookup_ident : Ident ,
@@ -1336,6 +1413,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1336
1413
) {
1337
1414
// Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
1338
1415
// for suggestions.
1416
+ self . lookup_macros_from_module ( ) ;
1339
1417
self . visit_scopes (
1340
1418
ScopeSet :: Macro ( MacroKind :: Derive ) ,
1341
1419
& parent_scope,
@@ -1364,16 +1442,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1364
1442
is_expected,
1365
1443
) ;
1366
1444
if !self . add_typo_suggestion ( err, suggestion, ident. span ) {
1367
- // FIXME: this only works if the macro that has the helper_attr has already
1368
- // been imported.
1445
+ // FIXME: this only works if the crate that owns the macro that has the helper_attr
1446
+ // has already been imported.
1369
1447
let mut derives = vec ! [ ] ;
1370
1448
let mut all_attrs: FxHashMap < Symbol , Vec < _ > > = FxHashMap :: default ( ) ;
1371
1449
for ( def_id, data) in & self . macro_map {
1372
1450
for helper_attr in & data. ext . helper_attrs {
1373
1451
let item_name = self . tcx . item_name ( * def_id) ;
1374
1452
all_attrs. entry ( * helper_attr) . or_default ( ) . push ( item_name) ;
1375
1453
if helper_attr == & ident. name {
1376
- // FIXME: we should also do Levenshtein distance checks here.
1377
1454
derives. push ( item_name) ;
1378
1455
}
1379
1456
}
@@ -1401,11 +1478,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1401
1478
if span. from_expansion ( ) {
1402
1479
None
1403
1480
} else {
1404
- // For enum variants, ` sugg_span` is empty, but we can get the ` enum` 's ` Span` .
1481
+ // For enum variants sugg_span is empty but we can get the enum's Span.
1405
1482
Some ( span. shrink_to_lo ( ) )
1406
1483
}
1407
1484
} else {
1408
- // For items, this `Span` will be populated, everything else it'll be ` None` .
1485
+ // For items this `Span` will be populated, everything else it'll be None.
1409
1486
sugg_span
1410
1487
} ;
1411
1488
match sugg_span {
0 commit comments