Navigation Menu

Skip to content

Commit

Permalink
typeck: move method errors/suggestions to their own file.
Browse files Browse the repository at this point in the history
  • Loading branch information
huonw committed Jan 13, 2015
1 parent 3d5fbae commit af506fa
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 101 deletions.
105 changes: 4 additions & 101 deletions src/librustc_typeck/check/method/mod.rs
Expand Up @@ -12,15 +12,14 @@

use astconv::AstConv;
use check::{FnCtxt};
use check::{impl_self_ty};
use check::vtable;
use check::vtable::select_new_fcx_obligations;
use middle::subst;
use middle::traits;
use middle::ty::*;
use middle::ty;
use middle::infer;
use util::ppaux::{Repr, UserString};
use util::ppaux::Repr;

use std::rc::Rc;
use syntax::ast::{DefId};
Expand All @@ -30,9 +29,12 @@ use syntax::codemap::Span;
pub use self::MethodError::*;
pub use self::CandidateSource::*;

pub use self::suggest::report_error;

mod confirm;
mod doc;
mod probe;
mod suggest;

pub enum MethodError {
// Did not find an applicable method, but we did find various
Expand Down Expand Up @@ -294,105 +296,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(callee)
}

pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
rcvr_ty: Ty<'tcx>,
method_name: ast::Name,
error: MethodError)
{
match error {
NoMatch(static_sources) => {
let cx = fcx.tcx();
let method_ustring = method_name.user_string(cx);

// True if the type is a struct and contains a field with
// the same name as the not-found method
let is_field = match rcvr_ty.sty {
ty_struct(did, _) =>
ty::lookup_struct_fields(cx, did)
.iter()
.any(|f| f.name.user_string(cx) == method_ustring),
_ => false
};

fcx.type_error_message(
span,
|actual| {
format!("type `{}` does not implement any \
method in scope named `{}`",
actual,
method_ustring)
},
rcvr_ty,
None);

// If the method has the name of a field, give a help note
if is_field {
cx.sess.span_note(span,
&format!("use `(s.{0})(...)` if you meant to call the \
function stored in the `{0}` field", method_ustring)[]);
}

if static_sources.len() > 0 {
fcx.tcx().sess.fileline_note(
span,
"found defined static methods, maybe a `self` is missing?");

report_candidates(fcx, span, method_name, static_sources);
}
}

Ambiguity(sources) => {
span_err!(fcx.sess(), span, E0034,
"multiple applicable methods in scope");

report_candidates(fcx, span, method_name, sources);
}
}

fn report_candidates(fcx: &FnCtxt,
span: Span,
method_name: ast::Name,
mut sources: Vec<CandidateSource>) {
sources.sort();
sources.dedup();

for (idx, source) in sources.iter().enumerate() {
match *source {
ImplSource(impl_did) => {
// Provide the best span we can. Use the method, if local to crate, else
// the impl, if local to crate (method may be defaulted), else the call site.
let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);

let impl_ty = impl_self_ty(fcx, span, impl_did).ty;

let insertion = match impl_trait_ref(fcx.tcx(), impl_did) {
None => format!(""),
Some(trait_ref) => format!(" of the trait `{}`",
ty::item_path_str(fcx.tcx(),
trait_ref.def_id)),
};

span_note!(fcx.sess(), method_span,
"candidate #{} is defined in an impl{} for the type `{}`",
idx + 1u,
insertion,
impl_ty.user_string(fcx.tcx()));
}
TraitSource(trait_did) => {
let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
span_note!(fcx.sess(), method_span,
"candidate #{} is defined in the trait `{}`",
idx + 1u,
ty::item_path_str(fcx.tcx(), trait_did));
}
}
}
}
}

/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
/// index (or `None`, if no such method).
Expand Down
122 changes: 122 additions & 0 deletions src/librustc_typeck/check/method/suggest.rs
@@ -0,0 +1,122 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Give useful errors and suggestions to users when a method can't be
//! found or is otherwise invalid.

use astconv::AstConv;
use check::{self, FnCtxt};
use middle::ty::{self, Ty};
use util::ppaux::UserString;

use syntax::ast;
use syntax::codemap::Span;

use super::{MethodError, CandidateSource, impl_method, trait_method};

pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
rcvr_ty: Ty<'tcx>,
method_name: ast::Name,
error: MethodError)
{
match error {
MethodError::NoMatch(static_sources) => {
let cx = fcx.tcx();
let method_ustring = method_name.user_string(cx);

// True if the type is a struct and contains a field with
// the same name as the not-found method
let is_field = match rcvr_ty.sty {
ty::ty_struct(did, _) =>
ty::lookup_struct_fields(cx, did)
.iter()
.any(|f| f.name.user_string(cx) == method_ustring),
_ => false
};

fcx.type_error_message(
span,
|actual| {
format!("type `{}` does not implement any \
method in scope named `{}`",
actual,
method_ustring)
},
rcvr_ty,
None);

// If the method has the name of a field, give a help note
if is_field {
cx.sess.span_note(span,
&format!("use `(s.{0})(...)` if you meant to call the \
function stored in the `{0}` field", method_ustring)[]);
}

if static_sources.len() > 0 {
fcx.tcx().sess.fileline_note(
span,
"found defined static methods, maybe a `self` is missing?");

report_candidates(fcx, span, method_name, static_sources);
}
}

MethodError::Ambiguity(sources) => {
span_err!(fcx.sess(), span, E0034,
"multiple applicable methods in scope");

report_candidates(fcx, span, method_name, sources);
}
}

fn report_candidates(fcx: &FnCtxt,
span: Span,
method_name: ast::Name,
mut sources: Vec<CandidateSource>) {
sources.sort();
sources.dedup();

for (idx, source) in sources.iter().enumerate() {
match *source {
CandidateSource::ImplSource(impl_did) => {
// Provide the best span we can. Use the method, if local to crate, else
// the impl, if local to crate (method may be defaulted), else the call site.
let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);

let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty;

let insertion = match ty::impl_trait_ref(fcx.tcx(), impl_did) {
None => format!(""),
Some(trait_ref) => format!(" of the trait `{}`",
ty::item_path_str(fcx.tcx(),
trait_ref.def_id)),
};

span_note!(fcx.sess(), method_span,
"candidate #{} is defined in an impl{} for the type `{}`",
idx + 1u,
insertion,
impl_ty.user_string(fcx.tcx()));
}
CandidateSource::TraitSource(trait_did) => {
let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
span_note!(fcx.sess(), method_span,
"candidate #{} is defined in the trait `{}`",
idx + 1u,
ty::item_path_str(fcx.tcx(), trait_did));
}
}
}
}
}

0 comments on commit af506fa

Please sign in to comment.