Skip to content

Commit 2023c96

Browse files
authored
Rollup merge of rust-lang#155948 - SynapLink:fix/pub-visibility-order, r=petrochenkov,mu001999
Fix order-dependent visibility diagnostics Fixes rust-lang#40066. Fixes rust-lang#109657. Delay visibility path diagnostics until module collection has finished, so paths to later non-ancestor modules report E0742 instead of an unresolved path error.
2 parents 8ca00c4 + f7c62f5 commit 2023c96

11 files changed

Lines changed: 220 additions & 158 deletions

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 124 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ use crate::imports::{ImportData, ImportKind, OnUnknownData};
3535
use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
3636
use crate::ref_mut::CmCell;
3737
use crate::{
38-
BindingKey, Decl, DeclData, DeclKind, ExternModule, ExternPreludeEntry, Finalize, IdentKey,
39-
LocalModule, MacroData, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, Res,
40-
Resolver, Segment, Used, VisResolutionError, errors,
38+
BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule,
39+
ExternPreludeEntry, Finalize, IdentKey, LocalModule, MacroData, Module, ModuleKind,
40+
ModuleOrUniformRoot, ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError,
41+
errors,
4142
};
4243

4344
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
@@ -237,6 +238,111 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
237238
}
238239
}
239240

241+
pub(crate) fn try_resolve_visibility(
242+
&mut self,
243+
parent_scope: &ParentScope<'ra>,
244+
vis: &ast::Visibility,
245+
finalize: bool,
246+
) -> Result<Visibility, VisResolutionError> {
247+
match vis.kind {
248+
ast::VisibilityKind::Public => Ok(Visibility::Public),
249+
ast::VisibilityKind::Inherited => {
250+
Ok(match parent_scope.module.kind {
251+
// Any inherited visibility resolved directly inside an enum or trait
252+
// (i.e. variants, fields, and trait items) inherits from the visibility
253+
// of the enum or trait.
254+
ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => {
255+
self.tcx.visibility(def_id).expect_local()
256+
}
257+
// Otherwise, the visibility is restricted to the nearest parent `mod` item.
258+
_ => Visibility::Restricted(
259+
parent_scope.module.nearest_parent_mod().expect_local(),
260+
),
261+
})
262+
}
263+
ast::VisibilityKind::Restricted { ref path, id, .. } => {
264+
// For visibilities we are not ready to provide correct implementation of "uniform
265+
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
266+
// On 2015 edition visibilities are resolved as crate-relative by default,
267+
// so we are prepending a root segment if necessary.
268+
let ident = path.segments.get(0).expect("empty path in visibility").ident;
269+
let crate_root = if ident.is_path_segment_keyword() {
270+
None
271+
} else if ident.span.is_rust_2015() {
272+
Some(Segment::from_ident(Ident::new(
273+
kw::PathRoot,
274+
path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
275+
)))
276+
} else {
277+
return Err(VisResolutionError::Relative2018(
278+
ident.span,
279+
path.as_ref().clone(),
280+
));
281+
};
282+
let segments = crate_root
283+
.into_iter()
284+
.chain(path.segments.iter().map(|seg| seg.into()))
285+
.collect::<Vec<_>>();
286+
let expected_found_error = |res| {
287+
Err(VisResolutionError::ExpectedFound(
288+
path.span,
289+
Segment::names_to_string(&segments),
290+
res,
291+
))
292+
};
293+
match self.cm().resolve_path(
294+
&segments,
295+
None,
296+
parent_scope,
297+
finalize.then(|| Finalize::new(id, path.span)),
298+
None,
299+
None,
300+
) {
301+
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
302+
let res = module.res().expect("visibility resolved to unnamed block");
303+
if module.is_normal() {
304+
match res {
305+
Res::Err => {
306+
if finalize {
307+
self.record_partial_res(id, PartialRes::new(res));
308+
}
309+
Ok(Visibility::Public)
310+
}
311+
_ => {
312+
let vis = Visibility::Restricted(res.def_id());
313+
if self.is_accessible_from(vis, parent_scope.module) {
314+
if finalize {
315+
self.record_partial_res(id, PartialRes::new(res));
316+
}
317+
Ok(vis.expect_local())
318+
} else {
319+
Err(VisResolutionError::AncestorOnly(path.span))
320+
}
321+
}
322+
}
323+
} else {
324+
expected_found_error(res)
325+
}
326+
}
327+
PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)),
328+
PathResult::NonModule(partial_res) => {
329+
expected_found_error(partial_res.expect_full_res())
330+
}
331+
PathResult::Failed {
332+
span, label, suggestion, message, segment_name, ..
333+
} => Err(VisResolutionError::FailedToResolve(
334+
span,
335+
segment_name,
336+
label,
337+
suggestion,
338+
message,
339+
)),
340+
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
341+
}
342+
}
343+
}
344+
}
345+
240346
pub(crate) fn build_reduced_graph_external(&self, module: ExternModule<'ra>) {
241347
let def_id = module.def_id();
242348
let children = self.tcx.module_children(def_id);
@@ -364,106 +470,15 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
364470
}
365471

366472
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility {
367-
self.try_resolve_visibility(vis, true).unwrap_or_else(|err| {
368-
self.r.report_vis_error(err);
369-
Visibility::Public
370-
})
371-
}
372-
373-
fn try_resolve_visibility<'ast>(
374-
&mut self,
375-
vis: &'ast ast::Visibility,
376-
finalize: bool,
377-
) -> Result<Visibility, VisResolutionError<'ast>> {
378-
let parent_scope = &self.parent_scope;
379-
match vis.kind {
380-
ast::VisibilityKind::Public => Ok(Visibility::Public),
381-
ast::VisibilityKind::Inherited => {
382-
Ok(match self.parent_scope.module.kind {
383-
// Any inherited visibility resolved directly inside an enum or trait
384-
// (i.e. variants, fields, and trait items) inherits from the visibility
385-
// of the enum or trait.
386-
ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => {
387-
self.r.tcx.visibility(def_id).expect_local()
388-
}
389-
// Otherwise, the visibility is restricted to the nearest parent `mod` item.
390-
_ => Visibility::Restricted(
391-
self.parent_scope.module.nearest_parent_mod().expect_local(),
392-
),
393-
})
394-
}
395-
ast::VisibilityKind::Restricted { ref path, id, .. } => {
396-
// For visibilities we are not ready to provide correct implementation of "uniform
397-
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
398-
// On 2015 edition visibilities are resolved as crate-relative by default,
399-
// so we are prepending a root segment if necessary.
400-
let ident = path.segments.get(0).expect("empty path in visibility").ident;
401-
let crate_root = if ident.is_path_segment_keyword() {
402-
None
403-
} else if ident.span.is_rust_2015() {
404-
Some(Segment::from_ident(Ident::new(
405-
kw::PathRoot,
406-
path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
407-
)))
408-
} else {
409-
return Err(VisResolutionError::Relative2018(ident.span, path));
410-
};
411-
412-
let segments = crate_root
413-
.into_iter()
414-
.chain(path.segments.iter().map(|seg| seg.into()))
415-
.collect::<Vec<_>>();
416-
let expected_found_error = |res| {
417-
Err(VisResolutionError::ExpectedFound(
418-
path.span,
419-
Segment::names_to_string(&segments),
420-
res,
421-
))
422-
};
423-
match self.r.cm().resolve_path(
424-
&segments,
425-
None,
426-
parent_scope,
427-
finalize.then(|| Finalize::new(id, path.span)),
428-
None,
429-
None,
430-
) {
431-
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
432-
let res = module.res().expect("visibility resolved to unnamed block");
433-
if finalize {
434-
self.r.record_partial_res(id, PartialRes::new(res));
435-
}
436-
if module.is_normal() {
437-
match res {
438-
Res::Err => Ok(Visibility::Public),
439-
_ => {
440-
let vis = Visibility::Restricted(res.def_id());
441-
if self.r.is_accessible_from(vis, parent_scope.module) {
442-
Ok(vis.expect_local())
443-
} else {
444-
Err(VisResolutionError::AncestorOnly(path.span))
445-
}
446-
}
447-
}
448-
} else {
449-
expected_found_error(res)
450-
}
451-
}
452-
PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)),
453-
PathResult::NonModule(partial_res) => {
454-
expected_found_error(partial_res.expect_full_res())
455-
}
456-
PathResult::Failed {
457-
span, label, suggestion, message, segment_name, ..
458-
} => Err(VisResolutionError::FailedToResolve(
459-
span,
460-
segment_name,
461-
label,
462-
suggestion,
463-
message,
464-
)),
465-
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
466-
}
473+
match self.r.try_resolve_visibility(&self.parent_scope, vis, true) {
474+
Ok(vis) => vis,
475+
Err(error) => {
476+
self.r.delayed_vis_resolution_errors.push(DelayedVisResolutionError {
477+
vis: vis.clone(),
478+
parent_scope: self.parent_scope,
479+
error,
480+
});
481+
Visibility::Public
467482
}
468483
}
469484
}
@@ -906,7 +921,8 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
906921
// correct visibilities for unnamed field placeholders specifically, so the
907922
// constructor visibility should still be determined correctly.
908923
let field_vis = self
909-
.try_resolve_visibility(&field.vis, false)
924+
.r
925+
.try_resolve_visibility(&self.parent_scope, &field.vis, false)
910926
.unwrap_or(Visibility::Public);
911927
if ctor_vis.greater_than(field_vis, self.r.tcx) {
912928
ctor_vis = field_vis;
@@ -1341,9 +1357,10 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
13411357
let vis = match item.kind {
13421358
// Visibilities must not be resolved non-speculatively twice
13431359
// and we already resolved this one as a `fn` item visibility.
1344-
ItemKind::Fn(..) => {
1345-
self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public)
1346-
}
1360+
ItemKind::Fn(..) => self
1361+
.r
1362+
.try_resolve_visibility(&self.parent_scope, &item.vis, false)
1363+
.unwrap_or(Visibility::Public),
13471364
_ => self.resolve_visibility(&item.vis),
13481365
};
13491366
if !vis.is_public() {

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// ignore-tidy-filelength
2+
use std::mem;
23
use std::ops::ControlFlow;
34

45
use itertools::Itertools as _;
@@ -48,10 +49,10 @@ use crate::imports::{Import, ImportKind};
4849
use crate::late::{DiagMetadata, PatternSource, Rib};
4950
use crate::{
5051
AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind,
51-
Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, LateDecl, MacroRulesScope,
52-
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res,
53-
ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError,
54-
errors as errs, path_names_to_string,
52+
DelayedVisResolutionError, Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey,
53+
LateDecl, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult,
54+
PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
55+
VisResolutionError, errors as errs, path_names_to_string,
5556
};
5657

5758
/// A vector of spans and replacements, a message and applicability.
@@ -137,6 +138,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
137138
}
138139

139140
pub(crate) fn report_errors(&mut self, krate: &Crate) {
141+
self.report_delayed_vis_resolution_errors();
140142
self.report_with_use_injections(krate);
141143

142144
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
@@ -171,16 +173,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
171173
}
172174

173175
let mut reported_spans = FxHashSet::default();
174-
for error in std::mem::take(&mut self.privacy_errors) {
176+
for error in mem::take(&mut self.privacy_errors) {
175177
if reported_spans.insert(error.dedup_span) {
176178
self.report_privacy_error(&error);
177179
}
178180
}
179181
}
180182

183+
fn report_delayed_vis_resolution_errors(&mut self) {
184+
for DelayedVisResolutionError { vis, parent_scope, error } in
185+
mem::take(&mut self.delayed_vis_resolution_errors)
186+
{
187+
match self.try_resolve_visibility(&parent_scope, &vis, true) {
188+
Ok(_) => self.report_vis_error(error),
189+
Err(error) => self.report_vis_error(error),
190+
};
191+
}
192+
}
193+
181194
fn report_with_use_injections(&mut self, krate: &Crate) {
182195
for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
183-
std::mem::take(&mut self.use_injections)
196+
mem::take(&mut self.use_injections)
184197
{
185198
let (span, found_use) = if let Some(def_id) = def_id.as_local() {
186199
UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id))
@@ -1137,7 +1150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11371150

11381151
pub(crate) fn report_vis_error(
11391152
&mut self,
1140-
vis_resolution_error: VisResolutionError<'_>,
1153+
vis_resolution_error: VisResolutionError,
11411154
) -> ErrorGuaranteed {
11421155
match vis_resolution_error {
11431156
VisResolutionError::Relative2018(span, path) => {
@@ -1146,7 +1159,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11461159
path_span: path.span,
11471160
// intentionally converting to String, as the text would also be used as
11481161
// in suggestion context
1149-
path_str: pprust::path_to_string(path),
1162+
path_str: pprust::path_to_string(&path),
11501163
})
11511164
}
11521165
VisResolutionError::AncestorOnly(span) => {

compiler/rustc_resolve/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,9 @@ enum ResolutionError<'ra> {
337337
BindingInNeverPattern,
338338
}
339339

340-
enum VisResolutionError<'a> {
341-
Relative2018(Span, &'a ast::Path),
340+
#[derive(Debug)]
341+
enum VisResolutionError {
342+
Relative2018(Span, ast::Path),
342343
AncestorOnly(Span),
343344
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
344345
ExpectedFound(Span, String, Res),
@@ -1004,6 +1005,13 @@ struct UseError<'a> {
10041005
is_call: bool,
10051006
}
10061007

1008+
#[derive(Debug)]
1009+
struct DelayedVisResolutionError<'ra> {
1010+
vis: ast::Visibility,
1011+
parent_scope: ParentScope<'ra>,
1012+
error: VisResolutionError,
1013+
}
1014+
10071015
#[derive(Clone, Copy, PartialEq, Debug)]
10081016
enum AmbiguityKind {
10091017
BuiltinAttr,
@@ -1364,6 +1372,8 @@ pub struct Resolver<'ra, 'tcx> {
13641372
issue_145575_hack_applied: bool = false,
13651373
/// `use` injections are delayed for better placement and deduplication.
13661374
use_injections: Vec<UseError<'tcx>> = Vec::new(),
1375+
/// Visibility path resolution failures are delayed until all modules are collected.
1376+
delayed_vis_resolution_errors: Vec<DelayedVisResolutionError<'ra>> = Vec::new(),
13671377
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
13681378
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
13691379

0 commit comments

Comments
 (0)