Skip to content

Commit

Permalink
Auto merge of #58498 - euclio:e0432-suggestions, r=estebank
Browse files Browse the repository at this point in the history
use structured suggestions for E0432
  • Loading branch information
bors committed Mar 10, 2019
2 parents 26b4cb4 + 4bbe883 commit 8ad727e
Show file tree
Hide file tree
Showing 19 changed files with 310 additions and 152 deletions.
94 changes: 69 additions & 25 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ impl Ord for BindingError {
}
}

/// A span, message, replacement text, and applicability.
type Suggestion = (Span, String, String, Applicability);

enum ResolutionError<'a> {
/// Error E0401: can't use type or const parameters from outer function.
GenericParamsFromOuterFunction(Def),
Expand Down Expand Up @@ -166,7 +169,7 @@ enum ResolutionError<'a> {
/// Error E0431: `self` import can only appear in an import list with a non-empty prefix.
SelfImportOnlyInImportListWithNonEmptyPrefix,
/// Error E0433: failed to resolve.
FailedToResolve(&'a str),
FailedToResolve { label: String, suggestion: Option<Suggestion> },
/// Error E0434: can't capture dynamic environment in a fn item.
CannotCaptureDynamicEnvironmentInFnItem,
/// Error E0435: attempt to use a non-constant value in a constant.
Expand Down Expand Up @@ -380,10 +383,15 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
err.span_label(span, "can only appear in an import list with a non-empty prefix");
err
}
ResolutionError::FailedToResolve(msg) => {
ResolutionError::FailedToResolve { label, suggestion } => {
let mut err = struct_span_err!(resolver.session, span, E0433,
"failed to resolve: {}", msg);
err.span_label(span, msg);
"failed to resolve: {}", &label);
err.span_label(span, label);

if let Some((span, msg, suggestion, applicability)) = suggestion {
err.span_suggestion(span, &msg, suggestion, applicability);
}

err
}
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
Expand Down Expand Up @@ -1050,7 +1058,12 @@ enum PathResult<'a> {
Module(ModuleOrUniformRoot<'a>),
NonModule(PathResolution),
Indeterminate,
Failed(Span, String, bool /* is the error from the last segment? */),
Failed {
span: Span,
label: String,
suggestion: Option<Suggestion>,
is_error_from_last_segment: bool,
},
}

enum ModuleKind {
Expand Down Expand Up @@ -1775,13 +1788,18 @@ impl<'a> Resolver<'a> {
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
path_res.base_def(),
PathResult::NonModule(..) => {
let msg = "type-relative paths are not supported in this context";
error_callback(self, span, ResolutionError::FailedToResolve(msg));
error_callback(self, span, ResolutionError::FailedToResolve {
label: String::from("type-relative paths are not supported in this context"),
suggestion: None,
});
Def::Err
}
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
PathResult::Failed(span, msg, _) => {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
PathResult::Failed { span, label, suggestion, .. } => {
error_callback(self, span, ResolutionError::FailedToResolve {
label,
suggestion,
});
Def::Err
}
};
Expand Down Expand Up @@ -3429,7 +3447,7 @@ impl<'a> Resolver<'a> {
// Such behavior is required for backward compatibility.
// The same fallback is used when `a` resolves to nothing.
PathResult::Module(ModuleOrUniformRoot::Module(_)) |
PathResult::Failed(..)
PathResult::Failed { .. }
if (ns == TypeNS || path.len() > 1) &&
self.primitive_type_table.primitive_types
.contains_key(&path[0].ident.name) => {
Expand All @@ -3438,11 +3456,11 @@ impl<'a> Resolver<'a> {
}
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
PathResolution::new(module.def().unwrap()),
PathResult::Failed(span, msg, false) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion });
err_path_resolution()
}
PathResult::Module(..) | PathResult::Failed(..) => return None,
PathResult::Module(..) | PathResult::Failed { .. } => return None,
PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
};

Expand Down Expand Up @@ -3550,7 +3568,12 @@ impl<'a> Resolver<'a> {
}
}
let msg = "there are too many initial `super`s.".to_string();
return PathResult::Failed(ident.span, msg, false);
return PathResult::Failed {
span: ident.span,
label: msg,
suggestion: None,
is_error_from_last_segment: false,
};
}
if i == 0 {
if name == keywords::SelfLower.name() {
Expand Down Expand Up @@ -3587,12 +3610,17 @@ impl<'a> Resolver<'a> {
} else {
format!("`{}`", name)
};
let msg = if i == 1 && path[0].ident.name == keywords::PathRoot.name() {
let label = if i == 1 && path[0].ident.name == keywords::PathRoot.name() {
format!("global paths cannot start with {}", name_str)
} else {
format!("{} in paths can only be used in start position", name_str)
};
return PathResult::Failed(ident.span, msg, false);
return PathResult::Failed {
span: ident.span,
label,
suggestion: None,
is_error_from_last_segment: false,
};
}

let binding = if let Some(module) = module {
Expand Down Expand Up @@ -3653,9 +3681,12 @@ impl<'a> Resolver<'a> {
def, path.len() - i - 1
));
} else {
return PathResult::Failed(ident.span,
format!("not a module `{}`", ident),
is_last);
return PathResult::Failed {
span: ident.span,
label: format!("not a module `{}`", ident),
suggestion: None,
is_error_from_last_segment: is_last,
};
}
}
Err(Undetermined) => return PathResult::Indeterminate,
Expand All @@ -3671,27 +3702,40 @@ impl<'a> Resolver<'a> {
Some(ModuleOrUniformRoot::Module(module)) => module.def(),
_ => None,
};
let msg = if module_def == self.graph_root.def() {
let (label, suggestion) = if module_def == self.graph_root.def() {
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
let mut candidates =
self.lookup_import_candidates(ident, TypeNS, is_mod);
candidates.sort_by_cached_key(|c| {
(c.path.segments.len(), c.path.to_string())
});
if let Some(candidate) = candidates.get(0) {
format!("did you mean `{}`?", candidate.path)
(
String::from("unresolved import"),
Some((
ident.span,
String::from("a similar path exists"),
candidate.path.to_string(),
Applicability::MaybeIncorrect,
)),
)
} else if !ident.is_reserved() {
format!("maybe a missing `extern crate {};`?", ident)
(format!("maybe a missing `extern crate {};`?", ident), None)
} else {
// the parser will already have complained about the keyword being used
return PathResult::NonModule(err_path_resolution());
}
} else if i == 0 {
format!("use of undeclared type or module `{}`", ident)
(format!("use of undeclared type or module `{}`", ident), None)
} else {
format!("could not find `{}` in `{}`", ident, path[i - 1].ident)
(format!("could not find `{}` in `{}`", ident, path[i - 1].ident), None)
};
return PathResult::Failed {
span: ident.span,
label,
suggestion,
is_error_from_last_segment: is_last,
};
return PathResult::Failed(ident.span, msg, is_last);
}
}
}
Expand Down
17 changes: 10 additions & 7 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,9 @@ impl<'a> Resolver<'a> {
Ok(path_res.base_def())
}
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
Err(Determinacy::Determined)
}
PathResult::NonModule(..)
| PathResult::Indeterminate
| PathResult::Failed { .. } => Err(Determinacy::Determined),
PathResult::Module(..) => unreachable!(),
};

Expand Down Expand Up @@ -990,14 +990,17 @@ impl<'a> Resolver<'a> {
let def = path_res.base_def();
check_consistency(self, &path, path_span, kind, initial_def, def);
}
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => {
let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
(span, msg)
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
(span, label)
} else {
(path_span, format!("partially resolved path in {} {}",
kind.article(), kind.descr()))
};
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
resolve_error(self, span, ResolutionError::FailedToResolve {
label,
suggestion: None
});
}
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
}
Expand Down
Loading

0 comments on commit 8ad727e

Please sign in to comment.