Improve path resolution diagnostics

This commit is contained in:
Jeffrey Seyfried 2016-04-07 00:42:29 +00:00
parent 7fd331e166
commit 20ee53c2f1

View File

@ -1716,9 +1716,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match self.resolve_crate_relative_path(prefix.span, match self.resolve_crate_relative_path(prefix.span,
&prefix.segments, &prefix.segments,
TypeNS) { TypeNS) {
Some(def) => Ok(def) =>
self.record_def(item.id, PathResolution::new(def, 0)), self.record_def(item.id, PathResolution::new(def, 0)),
None => { Err(true) => self.record_def(item.id, err_path_resolution()),
Err(false) => {
resolve_error(self, resolve_error(self,
prefix.span, prefix.span,
ResolutionError::FailedToResolve( ResolutionError::FailedToResolve(
@ -1837,7 +1838,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
trait_path: &Path, trait_path: &Path,
path_depth: usize) path_depth: usize)
-> Result<PathResolution, ()> { -> Result<PathResolution, ()> {
if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS) { self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| {
if let Def::Trait(_) = path_res.base_def { if let Def::Trait(_) = path_res.base_def {
debug!("(resolving trait) found trait def: {:?}", path_res); debug!("(resolving trait) found trait def: {:?}", path_res);
Ok(path_res) Ok(path_res)
@ -1857,9 +1858,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
err.emit(); err.emit();
Err(()) Err(true)
} }
} else { }).map_err(|error_reported| {
if error_reported { return }
// find possible candidates // find possible candidates
let trait_name = trait_path.segments.last().unwrap().identifier.name; let trait_name = trait_path.segments.last().unwrap().identifier.name;
@ -1882,8 +1884,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
); );
resolve_error(self, trait_path.span, error); resolve_error(self, trait_path.span, error);
Err(()) })
}
} }
fn resolve_generics(&mut self, generics: &Generics) { fn resolve_generics(&mut self, generics: &Generics) {
@ -1892,15 +1893,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&hir::WherePredicate::BoundPredicate(_) | &hir::WherePredicate::BoundPredicate(_) |
&hir::WherePredicate::RegionPredicate(_) => {} &hir::WherePredicate::RegionPredicate(_) => {}
&hir::WherePredicate::EqPredicate(ref eq_pred) => { &hir::WherePredicate::EqPredicate(ref eq_pred) => {
let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS); self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS).and_then(|path_res| {
if let Some(PathResolution { base_def: Def::TyParam(..), .. }) = path_res { if let PathResolution { base_def: Def::TyParam(..), .. } = path_res {
self.record_def(eq_pred.id, path_res.unwrap()); Ok(self.record_def(eq_pred.id, path_res))
} else { } else {
resolve_error(self, Err(false)
eq_pred.span, }
ResolutionError::UndeclaredAssociatedType); }).map_err(|error_reported| {
self.record_def(eq_pred.id, err_path_resolution()); self.record_def(eq_pred.id, err_path_resolution());
} if error_reported { return }
resolve_error(self, eq_pred.span, ResolutionError::UndeclaredAssociatedType);
}).unwrap_or(());
} }
} }
} }
@ -2170,21 +2173,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// This is a path in the type namespace. Walk through scopes // This is a path in the type namespace. Walk through scopes
// looking for it. // looking for it.
match resolution { if let Some(def) = resolution {
Some(def) => { // Write the result into the def map.
// Write the result into the def map. debug!("(resolving type) writing resolution for `{}` (id {}) = {:?}",
debug!("(resolving type) writing resolution for `{}` (id {}) = {:?}", path_names_to_string(path, 0), ty.id, def);
path_names_to_string(path, 0), self.record_def(ty.id, def);
ty.id, } else {
def); self.record_def(ty.id, err_path_resolution());
self.record_def(ty.id, def);
}
None => {
self.record_def(ty.id, err_path_resolution());
// Keep reporting some errors even if they're ignored above.
self.resolve_path(ty.id, path, 0, TypeNS);
// Keep reporting some errors even if they're ignored above.
if let Err(true) = self.resolve_path(ty.id, path, 0, TypeNS) {
// `resolve_path` already reported the error
} else {
let kind = if maybe_qself.is_some() { let kind = if maybe_qself.is_some() {
"associated type" "associated type"
} else { } else {
@ -2483,11 +2483,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PatKind::Struct(ref path, _, _) => { PatKind::Struct(ref path, _, _) => {
match self.resolve_path(pat_id, path, 0, TypeNS) { match self.resolve_path(pat_id, path, 0, TypeNS) {
Some(definition) => { Ok(definition) => {
self.record_def(pattern.id, definition); self.record_def(pattern.id, definition);
} }
result => { Err(true) => self.record_def(pattern.id, err_path_resolution()),
debug!("(resolving pattern) didn't find struct def: {:?}", result); Err(false) => {
resolve_error( resolve_error(
self, self,
path.span, path.span,
@ -2554,14 +2554,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
let mut resolution = self.with_no_errors(|this| { let mut resolution = self.with_no_errors(|this| {
this.resolve_path(id, path, 0, namespace) this.resolve_path(id, path, 0, namespace).ok()
}); });
for depth in 1..max_assoc_types { for depth in 1..max_assoc_types {
if resolution.is_some() { if resolution.is_some() {
break; break;
} }
self.with_no_errors(|this| { self.with_no_errors(|this| {
resolution = this.resolve_path(id, path, depth, TypeNS); resolution = this.resolve_path(id, path, depth, TypeNS).ok();
}); });
} }
if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) { if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) {
@ -2574,7 +2574,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Skips `path_depth` trailing segments, which is also reflected in the /// Skips `path_depth` trailing segments, which is also reflected in the
/// returned value. See `middle::def::PathResolution` for more info. /// returned value. See `middle::def::PathResolution` for more info.
fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace) fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace)
-> Option<PathResolution> { -> Result<PathResolution, bool /* true if an error was reported */ > {
let span = path.span; let span = path.span;
let segments = &path.segments[..path.segments.len() - path_depth]; let segments = &path.segments[..path.segments.len() - path_depth];
@ -2613,14 +2613,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// //
// Such behavior is required for backward compatibility. // Such behavior is required for backward compatibility.
// The same fallback is used when `a` resolves to nothing. // The same fallback is used when `a` resolves to nothing.
let unqualified_def = resolve_identifier_with_fallback(self, true); let def = resolve_identifier_with_fallback(self, true).ok_or(false);
return unqualified_def.and_then(|def| self.adjust_local_def(def, span)).map(mk_res); return def.and_then(|def| self.adjust_local_def(def, span).ok_or(true)).map(mk_res);
} }
let unqualified_def = resolve_identifier_with_fallback(self, false); let unqualified_def = resolve_identifier_with_fallback(self, false);
let def = self.resolve_module_relative_path(span, segments, namespace); let def = self.resolve_module_relative_path(span, segments, namespace);
match (def, unqualified_def) { match (def, unqualified_def) {
(Some(d), Some(ref ud)) if d == ud.def => { (Ok(d), Some(ref ud)) if d == ud.def => {
self.session self.session
.add_lint(lint::builtin::UNUSED_QUALIFICATIONS, .add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
id, id,
@ -2741,7 +2741,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
span: Span, span: Span,
segments: &[hir::PathSegment], segments: &[hir::PathSegment],
namespace: Namespace) namespace: Namespace)
-> Option<Def> { -> Result<Def, bool /* true if an error was reported */> {
let module_path = segments.split_last() let module_path = segments.split_last()
.unwrap() .unwrap()
.1 .1
@ -2762,9 +2762,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}; };
resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
return None; return Err(true);
} }
Indeterminate => return None, Indeterminate => return Err(false),
Success(resulting_module) => { Success(resulting_module) => {
containing_module = resulting_module; containing_module = resulting_module;
} }
@ -2775,7 +2775,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
result.success().map(|binding| { result.success().map(|binding| {
self.check_privacy(containing_module, name, binding, span); self.check_privacy(containing_module, name, binding, span);
binding.def().unwrap() binding.def().unwrap()
}) }).ok_or(false)
} }
/// Invariant: This must be called only during main resolution, not during /// Invariant: This must be called only during main resolution, not during
@ -2784,7 +2784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
span: Span, span: Span,
segments: &[hir::PathSegment], segments: &[hir::PathSegment],
namespace: Namespace) namespace: Namespace)
-> Option<Def> { -> Result<Def, bool /* true if an error was reported */> {
let module_path = segments.split_last() let module_path = segments.split_last()
.unwrap() .unwrap()
.1 .1
@ -2810,10 +2810,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}; };
resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
return None; return Err(true);
} }
Indeterminate => return None, Indeterminate => return Err(false),
Success(resulting_module) => { Success(resulting_module) => {
containing_module = resulting_module; containing_module = resulting_module;
@ -2825,7 +2825,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
result.success().map(|binding| { result.success().map(|binding| {
self.check_privacy(containing_module, name, binding, span); self.check_privacy(containing_module, name, binding, span);
binding.def().unwrap() binding.def().unwrap()
}) }).ok_or(false)
} }
fn with_no_errors<T, F>(&mut self, f: F) -> T fn with_no_errors<T, F>(&mut self, f: F) -> T
@ -3040,25 +3040,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}); });
self.record_def(expr.id, err_path_resolution()); self.record_def(expr.id, err_path_resolution());
match type_res.map(|r| r.base_def) {
Some(Def::Struct(..)) => {
let mut err = resolve_struct_error(self,
expr.span,
ResolutionError::StructVariantUsedAsFunction(&path_name));
let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", if let Ok(Def::Struct(..)) = type_res.map(|r| r.base_def) {
path_name); let error_variant = ResolutionError::StructVariantUsedAsFunction(&path_name);
if self.emit_errors { let mut err = resolve_struct_error(self, expr.span, error_variant);
err.fileline_help(expr.span, &msg);
} else { let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
err.span_help(expr.span, &msg); path_name);
}
err.emit(); if self.emit_errors {
err.fileline_help(expr.span, &msg);
} else {
err.span_help(expr.span, &msg);
} }
_ => { err.emit();
// Keep reporting some errors even if they're ignored above. } else {
self.resolve_path(expr.id, path, 0, ValueNS); // Keep reporting some errors even if they're ignored above.
if let Err(true) = self.resolve_path(expr.id, path, 0, ValueNS) {
// `resolve_path` already reported the error
} else {
let mut method_scope = false; let mut method_scope = false;
self.value_ribs.iter().rev().all(|rib| { self.value_ribs.iter().rev().all(|rib| {
method_scope = match rib.kind { method_scope = match rib.kind {
@ -3132,8 +3132,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// check to ensure that the path is actually a structure; that // check to ensure that the path is actually a structure; that
// is checked later during typeck. // is checked later during typeck.
match self.resolve_path(expr.id, path, 0, TypeNS) { match self.resolve_path(expr.id, path, 0, TypeNS) {
Some(definition) => self.record_def(expr.id, definition), Ok(definition) => self.record_def(expr.id, definition),
None => { Err(true) => self.record_def(expr.id, err_path_resolution()),
Err(false) => {
debug!("(resolving expression) didn't find struct def",); debug!("(resolving expression) didn't find struct def",);
resolve_error(self, resolve_error(self,