Skip to content

Commit 8209dbf

Browse files
petrochenkovMark-Simulacrum
authored andcommitted
resolve: Make visibility resolution more speculative
To avoid potential duplicate diagnostics and separate the error reporting logic
1 parent d9d7203 commit 8209dbf

File tree

5 files changed

+87
-69
lines changed

5 files changed

+87
-69
lines changed

src/librustc_resolve/build_reduced_graph.rs

+36-59
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm
1111
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
1212
use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
1313
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
14-
use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
14+
use crate::{ResolutionError, VisResolutionError, Determinacy, PathResult, CrateLint};
1515

1616
use rustc::bug;
1717
use rustc::hir::def::{self, *};
@@ -35,7 +35,7 @@ use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
3535
use syntax::feature_gate::is_builtin_attr;
3636
use syntax::parse::token::{self, Token};
3737
use syntax::print::pprust;
38-
use syntax::{span_err, struct_span_err};
38+
use syntax::span_err;
3939
use syntax::source_map::{respan, Spanned};
4040
use syntax::symbol::{kw, sym};
4141
use syntax::visit::{self, Visitor};
@@ -194,22 +194,25 @@ impl<'a> AsMut<Resolver<'a>> for BuildReducedGraphVisitor<'a, '_> {
194194

195195
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
196196
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
197-
self.resolve_visibility_speculative(vis, false)
197+
self.resolve_visibility_speculative(vis, false).unwrap_or_else(|err| {
198+
self.r.report_vis_error(err);
199+
ty::Visibility::Public
200+
})
198201
}
199202

200-
fn resolve_visibility_speculative(
203+
fn resolve_visibility_speculative<'ast>(
201204
&mut self,
202-
vis: &ast::Visibility,
205+
vis: &'ast ast::Visibility,
203206
speculative: bool,
204-
) -> ty::Visibility {
207+
) -> Result<ty::Visibility, VisResolutionError<'ast>> {
205208
let parent_scope = &self.parent_scope;
206209
match vis.node {
207-
ast::VisibilityKind::Public => ty::Visibility::Public,
210+
ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
208211
ast::VisibilityKind::Crate(..) => {
209-
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
212+
Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
210213
}
211214
ast::VisibilityKind::Inherited => {
212-
ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
215+
Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id))
213216
}
214217
ast::VisibilityKind::Restricted { ref path, id, .. } => {
215218
// For visibilities we are not ready to provide correct implementation of "uniform
@@ -219,32 +222,19 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
219222
let ident = path.segments.get(0).expect("empty path in visibility").ident;
220223
let crate_root = if ident.is_path_segment_keyword() {
221224
None
222-
} else if ident.span.rust_2018() {
223-
let msg = "relative paths are not supported in visibilities on 2018 edition";
224-
self.r.session.struct_span_err(ident.span, msg)
225-
.span_suggestion(
226-
path.span,
227-
"try",
228-
format!("crate::{}", pprust::path_to_string(&path)),
229-
Applicability::MaybeIncorrect,
230-
)
231-
.emit();
232-
return ty::Visibility::Public;
233-
} else {
234-
let ctxt = ident.span.ctxt();
225+
} else if ident.span.rust_2015() {
235226
Some(Segment::from_ident(Ident::new(
236-
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
227+
kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ident.span.ctxt())
237228
)))
229+
} else {
230+
return Err(VisResolutionError::Relative2018(ident.span, path));
238231
};
239232

240233
let segments = crate_root.into_iter()
241234
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
242-
let expected_found_error = |this: &Self, res: Res| {
243-
let path_str = Segment::names_to_string(&segments);
244-
struct_span_err!(this.r.session, path.span, E0577,
245-
"expected module, found {} `{}`", res.descr(), path_str)
246-
.span_label(path.span, "not a module").emit();
247-
};
235+
let expected_found_error = |res| Err(VisResolutionError::ExpectedFound(
236+
path.span, Segment::names_to_string(&segments), res
237+
));
248238
match self.r.resolve_path(
249239
&segments,
250240
Some(TypeNS),
@@ -260,42 +250,27 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
260250
}
261251
if module.is_normal() {
262252
if res == Res::Err {
263-
ty::Visibility::Public
253+
Ok(ty::Visibility::Public)
264254
} else {
265255
let vis = ty::Visibility::Restricted(res.def_id());
266256
if self.r.is_accessible_from(vis, parent_scope.module) {
267-
vis
257+
Ok(vis)
268258
} else {
269-
struct_span_err!(self.r.session, path.span, E0742,
270-
"visibilities can only be restricted to ancestor modules")
271-
.emit();
272-
ty::Visibility::Public
259+
Err(VisResolutionError::AncestorOnly(path.span))
273260
}
274261
}
275262
} else {
276-
expected_found_error(self, res);
277-
ty::Visibility::Public
263+
expected_found_error(res)
278264
}
279265
}
280-
PathResult::Module(..) => {
281-
self.r.session.span_err(path.span, "visibility must resolve to a module");
282-
ty::Visibility::Public
283-
}
284-
PathResult::NonModule(partial_res) => {
285-
expected_found_error(self, partial_res.base_res());
286-
ty::Visibility::Public
287-
}
288-
PathResult::Failed { span, label, suggestion, .. } => {
289-
self.r.report_error(
290-
span, ResolutionError::FailedToResolve { label, suggestion }
291-
);
292-
ty::Visibility::Public
293-
}
294-
PathResult::Indeterminate => {
295-
span_err!(self.r.session, path.span, E0578,
296-
"cannot determine resolution for the visibility");
297-
ty::Visibility::Public
298-
}
266+
PathResult::Module(..) =>
267+
Err(VisResolutionError::ModuleOnly(path.span)),
268+
PathResult::NonModule(partial_res) =>
269+
expected_found_error(partial_res.base_res()),
270+
PathResult::Failed { span, label, suggestion, .. } =>
271+
Err(VisResolutionError::FailedToResolve(span, label, suggestion)),
272+
PathResult::Indeterminate =>
273+
Err(VisResolutionError::Indeterminate(path.span)),
299274
}
300275
}
301276
}
@@ -764,9 +739,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
764739
// NOTE: The field may be an expansion placeholder, but expansion sets
765740
// correct visibilities for unnamed field placeholders specifically, so the
766741
// constructor visibility should still be determined correctly.
767-
let field_vis = self.resolve_visibility_speculative(&field.vis, true);
768-
if ctor_vis.is_at_least(field_vis, &*self.r) {
769-
ctor_vis = field_vis;
742+
if let Ok(field_vis) =
743+
self.resolve_visibility_speculative(&field.vis, true) {
744+
if ctor_vis.is_at_least(field_vis, &*self.r) {
745+
ctor_vis = field_vis;
746+
}
770747
}
771748
}
772749
let ctor_res = Res::Def(

src/librustc_resolve/diagnostics.rs

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc::ty::{self, DefIdTree};
1111
use rustc::util::nodemap::FxHashSet;
1212
use syntax::ast::{self, Ident, Path};
1313
use syntax::feature_gate::BUILTIN_ATTRIBUTES;
14+
use syntax::print::pprust;
1415
use syntax::source_map::SourceMap;
1516
use syntax::struct_span_err;
1617
use syntax::symbol::{Symbol, kw};
@@ -22,6 +23,7 @@ use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportRes
2223
use crate::{path_names_to_string, KNOWN_TOOLS};
2324
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
2425
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
26+
use crate::VisResolutionError;
2527

2628
type Res = def::Res<ast::NodeId>;
2729

@@ -355,6 +357,44 @@ impl<'a> Resolver<'a> {
355357
}
356358
}
357359

360+
crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) {
361+
match vis_resolution_error {
362+
VisResolutionError::Relative2018(span, path) => {
363+
let mut err = self.session.struct_span_err(span,
364+
"relative paths are not supported in visibilities on 2018 edition");
365+
err.span_suggestion(
366+
path.span,
367+
"try",
368+
format!("crate::{}", pprust::path_to_string(&path)),
369+
Applicability::MaybeIncorrect,
370+
);
371+
err
372+
}
373+
VisResolutionError::AncestorOnly(span) => {
374+
struct_span_err!(self.session, span, E0742,
375+
"visibilities can only be restricted to ancestor modules")
376+
}
377+
VisResolutionError::FailedToResolve(span, label, suggestion) => {
378+
self.into_struct_error(
379+
span, ResolutionError::FailedToResolve { label, suggestion }
380+
)
381+
}
382+
VisResolutionError::ExpectedFound(span, path_str, res) => {
383+
let mut err = struct_span_err!(self.session, span, E0577,
384+
"expected module, found {} `{}`", res.descr(), path_str);
385+
err.span_label(span, "not a module");
386+
err
387+
}
388+
VisResolutionError::Indeterminate(span) => {
389+
struct_span_err!(self.session, span, E0578,
390+
"cannot determine resolution for the visibility")
391+
}
392+
VisResolutionError::ModuleOnly(span) => {
393+
self.session.struct_span_err(span, "visibility must resolve to a module")
394+
}
395+
}.emit()
396+
}
397+
358398
/// Lookup typo candidate in scope for a macro or import.
359399
fn early_lookup_typo_candidate(
360400
&mut self,

src/librustc_resolve/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ enum ResolutionError<'a> {
218218
SelfInTyParamDefault,
219219
}
220220

221+
enum VisResolutionError<'a> {
222+
Relative2018(Span, &'a ast::Path),
223+
AncestorOnly(Span),
224+
FailedToResolve(Span, String, Option<Suggestion>),
225+
ExpectedFound(Span, String, Res),
226+
Indeterminate(Span),
227+
ModuleOnly(Span),
228+
}
229+
221230
// A minimal representation of a path segment. We use this in resolve because
222231
// we synthesize 'path segments' which don't have the rest of an AST or HIR
223232
// `PathSegment`.

src/test/ui/attributes/field-attributes-vis-unresolved.rs

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ struct S {
2020
struct Z(
2121
#[rustfmt::skip]
2222
pub(in nonexistent) u8 //~ ERROR failed to resolve
23-
//~| ERROR cannot determine resolution for the visibility
2423
);
2524

2625
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error[E0578]: cannot determine resolution for the visibility
2-
--> $DIR/field-attributes-vis-unresolved.rs:22:12
3-
|
4-
LL | pub(in nonexistent) u8
5-
| ^^^^^^^^^^^
6-
71
error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
82
--> $DIR/field-attributes-vis-unresolved.rs:17:12
93
|
@@ -16,7 +10,6 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
1610
LL | pub(in nonexistent) u8
1711
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
1812

19-
error: aborting due to 3 previous errors
13+
error: aborting due to 2 previous errors
2014

21-
Some errors have detailed explanations: E0433, E0578.
22-
For more information about an error, try `rustc --explain E0433`.
15+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)