mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 14:57:14 +00:00
typeck: move method errors/suggestions to their own file.
This commit is contained in:
parent
3d5fbae338
commit
af506fa5d1
@ -12,7 +12,6 @@
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::{FnCtxt};
|
||||
use check::{impl_self_ty};
|
||||
use check::vtable;
|
||||
use check::vtable::select_new_fcx_obligations;
|
||||
use middle::subst;
|
||||
@ -20,7 +19,7 @@ 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};
|
||||
@ -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
|
||||
@ -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).
|
||||
|
122
src/librustc_typeck/check/method/suggest.rs
Normal file
122
src/librustc_typeck/check/method/suggest.rs
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user