Skip to content

Commit f7c62f5

Browse files
committed
Fix order-dependent visibility diagnostics
1 parent 03c609a commit f7c62f5

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> {
@@ -235,6 +236,111 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
235236
}
236237
}
237238

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

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

11281141
pub(crate) fn report_vis_error(
11291142
&mut self,
1130-
vis_resolution_error: VisResolutionError<'_>,
1143+
vis_resolution_error: VisResolutionError,
11311144
) -> ErrorGuaranteed {
11321145
match vis_resolution_error {
11331146
VisResolutionError::Relative2018(span, path) => {
@@ -1136,7 +1149,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11361149
path_span: path.span,
11371150
// intentionally converting to String, as the text would also be used as
11381151
// in suggestion context
1139-
path_str: pprust::path_to_string(path),
1152+
path_str: pprust::path_to_string(&path),
11401153
})
11411154
}
11421155
VisResolutionError::AncestorOnly(span) => {

compiler/rustc_resolve/src/lib.rs

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

339-
enum VisResolutionError<'a> {
340-
Relative2018(Span, &'a ast::Path),
339+
#[derive(Debug)]
340+
enum VisResolutionError {
341+
Relative2018(Span, ast::Path),
341342
AncestorOnly(Span),
342343
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
343344
ExpectedFound(Span, String, Res),
@@ -997,6 +998,13 @@ struct UseError<'a> {
997998
is_call: bool,
998999
}
9991000

1001+
#[derive(Debug)]
1002+
struct DelayedVisResolutionError<'ra> {
1003+
vis: ast::Visibility,
1004+
parent_scope: ParentScope<'ra>,
1005+
error: VisResolutionError,
1006+
}
1007+
10001008
#[derive(Clone, Copy, PartialEq, Debug)]
10011009
enum AmbiguityKind {
10021010
BuiltinAttr,
@@ -1351,6 +1359,8 @@ pub struct Resolver<'ra, 'tcx> {
13511359
issue_145575_hack_applied: bool = false,
13521360
/// `use` injections are delayed for better placement and deduplication.
13531361
use_injections: Vec<UseError<'tcx>> = Vec::new(),
1362+
/// Visibility path resolution failures are delayed until all modules are collected.
1363+
delayed_vis_resolution_errors: Vec<DelayedVisResolutionError<'ra>> = Vec::new(),
13541364
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
13551365
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
13561366

0 commit comments

Comments
 (0)