Skip to content

Commit 8ad727e

Browse files
committed
Auto merge of #58498 - euclio:e0432-suggestions, r=estebank
use structured suggestions for E0432
2 parents 26b4cb4 + 4bbe883 commit 8ad727e

19 files changed

+310
-152
lines changed

src/librustc_resolve/lib.rs

+69-25
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ impl Ord for BindingError {
137137
}
138138
}
139139

140+
/// A span, message, replacement text, and applicability.
141+
type Suggestion = (Span, String, String, Applicability);
142+
140143
enum ResolutionError<'a> {
141144
/// Error E0401: can't use type or const parameters from outer function.
142145
GenericParamsFromOuterFunction(Def),
@@ -166,7 +169,7 @@ enum ResolutionError<'a> {
166169
/// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
167170
SelfImportOnlyInImportListWithNonEmptyPrefix,
168171
/// Error E0433: failed to resolve.
169-
FailedToResolve(&'a str),
172+
FailedToResolve { label: String, suggestion: Option<Suggestion> },
170173
/// Error E0434: can't capture dynamic environment in a fn item.
171174
CannotCaptureDynamicEnvironmentInFnItem,
172175
/// Error E0435: attempt to use a non-constant value in a constant.
@@ -380,10 +383,15 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
380383
err.span_label(span, "can only appear in an import list with a non-empty prefix");
381384
err
382385
}
383-
ResolutionError::FailedToResolve(msg) => {
386+
ResolutionError::FailedToResolve { label, suggestion } => {
384387
let mut err = struct_span_err!(resolver.session, span, E0433,
385-
"failed to resolve: {}", msg);
386-
err.span_label(span, msg);
388+
"failed to resolve: {}", &label);
389+
err.span_label(span, label);
390+
391+
if let Some((span, msg, suggestion, applicability)) = suggestion {
392+
err.span_suggestion(span, &msg, suggestion, applicability);
393+
}
394+
387395
err
388396
}
389397
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
@@ -1050,7 +1058,12 @@ enum PathResult<'a> {
10501058
Module(ModuleOrUniformRoot<'a>),
10511059
NonModule(PathResolution),
10521060
Indeterminate,
1053-
Failed(Span, String, bool /* is the error from the last segment? */),
1061+
Failed {
1062+
span: Span,
1063+
label: String,
1064+
suggestion: Option<Suggestion>,
1065+
is_error_from_last_segment: bool,
1066+
},
10541067
}
10551068

10561069
enum ModuleKind {
@@ -1775,13 +1788,18 @@ impl<'a> Resolver<'a> {
17751788
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
17761789
path_res.base_def(),
17771790
PathResult::NonModule(..) => {
1778-
let msg = "type-relative paths are not supported in this context";
1779-
error_callback(self, span, ResolutionError::FailedToResolve(msg));
1791+
error_callback(self, span, ResolutionError::FailedToResolve {
1792+
label: String::from("type-relative paths are not supported in this context"),
1793+
suggestion: None,
1794+
});
17801795
Def::Err
17811796
}
17821797
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
1783-
PathResult::Failed(span, msg, _) => {
1784-
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
1798+
PathResult::Failed { span, label, suggestion, .. } => {
1799+
error_callback(self, span, ResolutionError::FailedToResolve {
1800+
label,
1801+
suggestion,
1802+
});
17851803
Def::Err
17861804
}
17871805
};
@@ -3429,7 +3447,7 @@ impl<'a> Resolver<'a> {
34293447
// Such behavior is required for backward compatibility.
34303448
// The same fallback is used when `a` resolves to nothing.
34313449
PathResult::Module(ModuleOrUniformRoot::Module(_)) |
3432-
PathResult::Failed(..)
3450+
PathResult::Failed { .. }
34333451
if (ns == TypeNS || path.len() > 1) &&
34343452
self.primitive_type_table.primitive_types
34353453
.contains_key(&path[0].ident.name) => {
@@ -3438,11 +3456,11 @@ impl<'a> Resolver<'a> {
34383456
}
34393457
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
34403458
PathResolution::new(module.def().unwrap()),
3441-
PathResult::Failed(span, msg, false) => {
3442-
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
3459+
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
3460+
resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
34433461
err_path_resolution()
34443462
}
3445-
PathResult::Module(..) | PathResult::Failed(..) => return None,
3463+
PathResult::Module(..) | PathResult::Failed { .. } => return None,
34463464
PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
34473465
};
34483466

@@ -3550,7 +3568,12 @@ impl<'a> Resolver<'a> {
35503568
}
35513569
}
35523570
let msg = "there are too many initial `super`s.".to_string();
3553-
return PathResult::Failed(ident.span, msg, false);
3571+
return PathResult::Failed {
3572+
span: ident.span,
3573+
label: msg,
3574+
suggestion: None,
3575+
is_error_from_last_segment: false,
3576+
};
35543577
}
35553578
if i == 0 {
35563579
if name == keywords::SelfLower.name() {
@@ -3587,12 +3610,17 @@ impl<'a> Resolver<'a> {
35873610
} else {
35883611
format!("`{}`", name)
35893612
};
3590-
let msg = if i == 1 && path[0].ident.name == keywords::PathRoot.name() {
3613+
let label = if i == 1 && path[0].ident.name == keywords::PathRoot.name() {
35913614
format!("global paths cannot start with {}", name_str)
35923615
} else {
35933616
format!("{} in paths can only be used in start position", name_str)
35943617
};
3595-
return PathResult::Failed(ident.span, msg, false);
3618+
return PathResult::Failed {
3619+
span: ident.span,
3620+
label,
3621+
suggestion: None,
3622+
is_error_from_last_segment: false,
3623+
};
35963624
}
35973625

35983626
let binding = if let Some(module) = module {
@@ -3653,9 +3681,12 @@ impl<'a> Resolver<'a> {
36533681
def, path.len() - i - 1
36543682
));
36553683
} else {
3656-
return PathResult::Failed(ident.span,
3657-
format!("not a module `{}`", ident),
3658-
is_last);
3684+
return PathResult::Failed {
3685+
span: ident.span,
3686+
label: format!("not a module `{}`", ident),
3687+
suggestion: None,
3688+
is_error_from_last_segment: is_last,
3689+
};
36593690
}
36603691
}
36613692
Err(Undetermined) => return PathResult::Indeterminate,
@@ -3671,27 +3702,40 @@ impl<'a> Resolver<'a> {
36713702
Some(ModuleOrUniformRoot::Module(module)) => module.def(),
36723703
_ => None,
36733704
};
3674-
let msg = if module_def == self.graph_root.def() {
3705+
let (label, suggestion) = if module_def == self.graph_root.def() {
36753706
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
36763707
let mut candidates =
36773708
self.lookup_import_candidates(ident, TypeNS, is_mod);
36783709
candidates.sort_by_cached_key(|c| {
36793710
(c.path.segments.len(), c.path.to_string())
36803711
});
36813712
if let Some(candidate) = candidates.get(0) {
3682-
format!("did you mean `{}`?", candidate.path)
3713+
(
3714+
String::from("unresolved import"),
3715+
Some((
3716+
ident.span,
3717+
String::from("a similar path exists"),
3718+
candidate.path.to_string(),
3719+
Applicability::MaybeIncorrect,
3720+
)),
3721+
)
36833722
} else if !ident.is_reserved() {
3684-
format!("maybe a missing `extern crate {};`?", ident)
3723+
(format!("maybe a missing `extern crate {};`?", ident), None)
36853724
} else {
36863725
// the parser will already have complained about the keyword being used
36873726
return PathResult::NonModule(err_path_resolution());
36883727
}
36893728
} else if i == 0 {
3690-
format!("use of undeclared type or module `{}`", ident)
3729+
(format!("use of undeclared type or module `{}`", ident), None)
36913730
} else {
3692-
format!("could not find `{}` in `{}`", ident, path[i - 1].ident)
3731+
(format!("could not find `{}` in `{}`", ident, path[i - 1].ident), None)
3732+
};
3733+
return PathResult::Failed {
3734+
span: ident.span,
3735+
label,
3736+
suggestion,
3737+
is_error_from_last_segment: is_last,
36933738
};
3694-
return PathResult::Failed(ident.span, msg, is_last);
36953739
}
36963740
}
36973741
}

src/librustc_resolve/macros.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,9 @@ impl<'a> Resolver<'a> {
426426
Ok(path_res.base_def())
427427
}
428428
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
429-
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
430-
Err(Determinacy::Determined)
431-
}
429+
PathResult::NonModule(..)
430+
| PathResult::Indeterminate
431+
| PathResult::Failed { .. } => Err(Determinacy::Determined),
432432
PathResult::Module(..) => unreachable!(),
433433
};
434434

@@ -990,14 +990,17 @@ impl<'a> Resolver<'a> {
990990
let def = path_res.base_def();
991991
check_consistency(self, &path, path_span, kind, initial_def, def);
992992
}
993-
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => {
994-
let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
995-
(span, msg)
993+
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
994+
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
995+
(span, label)
996996
} else {
997997
(path_span, format!("partially resolved path in {} {}",
998998
kind.article(), kind.descr()))
999999
};
1000-
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
1000+
resolve_error(self, span, ResolutionError::FailedToResolve {
1001+
label,
1002+
suggestion: None
1003+
});
10011004
}
10021005
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
10031006
}

0 commit comments

Comments
 (0)