auto merge of #13713 : edwardw/rust/methodcall-span, r=alexcrichton
Specifically, the method parameter cardinality mismatch or missing method error message span now gets method itself exactly. It was the whole expression. Closes #9390 Closes #13684 Closes #13709
This commit is contained in:
commit
70647ccc6d
9 changed files with 53 additions and 17 deletions
|
@ -791,7 +791,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
|
||||||
}
|
}
|
||||||
Some(method) => {
|
Some(method) => {
|
||||||
debug!("(privacy checking) checking impl method");
|
debug!("(privacy checking) checking impl method");
|
||||||
self.check_method(expr.span, method.origin, ident);
|
self.check_method(expr.span, method.origin, ident.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5083,7 +5083,7 @@ impl<'a> Resolver<'a> {
|
||||||
debug!("(recording candidate traits for expr) recording \
|
debug!("(recording candidate traits for expr) recording \
|
||||||
traits for {}",
|
traits for {}",
|
||||||
expr.id);
|
expr.id);
|
||||||
let traits = self.search_for_traits_containing_method(ident.name);
|
let traits = self.search_for_traits_containing_method(ident.node.name);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -1722,7 +1722,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
fcx.tcx().sess.span_bug(
|
fcx.tcx().sess.span_bug(
|
||||||
sp,
|
callee_expr.span,
|
||||||
format!("method without bare fn type"));
|
format!("method without bare fn type"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1936,7 +1936,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
// Checks a method call.
|
// Checks a method call.
|
||||||
fn check_method_call(fcx: &FnCtxt,
|
fn check_method_call(fcx: &FnCtxt,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
method_name: ast::Ident,
|
method_name: ast::SpannedIdent,
|
||||||
args: &[@ast::Expr],
|
args: &[@ast::Expr],
|
||||||
tps: &[ast::P<ast::Ty>]) {
|
tps: &[ast::P<ast::Ty>]) {
|
||||||
let rcvr = args[0];
|
let rcvr = args[0];
|
||||||
|
@ -1952,7 +1952,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
|
|
||||||
let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
|
let tps = tps.iter().map(|&ast_ty| fcx.to_ty(ast_ty)).collect::<Vec<_>>();
|
||||||
let fn_ty = match method::lookup(fcx, expr, rcvr,
|
let fn_ty = match method::lookup(fcx, expr, rcvr,
|
||||||
method_name.name,
|
method_name.node.name,
|
||||||
expr_t, tps.as_slice(),
|
expr_t, tps.as_slice(),
|
||||||
DontDerefArgs,
|
DontDerefArgs,
|
||||||
CheckTraitsAndInherentMethods,
|
CheckTraitsAndInherentMethods,
|
||||||
|
@ -1966,11 +1966,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
None => {
|
None => {
|
||||||
debug!("(checking method call) failing expr is {}", expr.id);
|
debug!("(checking method call) failing expr is {}", expr.id);
|
||||||
|
|
||||||
fcx.type_error_message(expr.span,
|
fcx.type_error_message(method_name.span,
|
||||||
|actual| {
|
|actual| {
|
||||||
format!("type `{}` does not implement any method in scope \
|
format!("type `{}` does not implement any method in scope named `{}`",
|
||||||
named `{}`",
|
actual, token::get_ident(method_name.node))
|
||||||
actual, token::get_ident(method_name))
|
|
||||||
},
|
},
|
||||||
expr_t,
|
expr_t,
|
||||||
None);
|
None);
|
||||||
|
@ -1982,7 +1981,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the generic checker.
|
// Call the generic checker.
|
||||||
let ret_ty = check_method_argument_types(fcx, expr.span,
|
let ret_ty = check_method_argument_types(fcx, method_name.span,
|
||||||
fn_ty, expr, args,
|
fn_ty, expr, args,
|
||||||
DontDerefArgs);
|
DontDerefArgs);
|
||||||
|
|
||||||
|
|
|
@ -481,7 +481,7 @@ pub enum Expr_ {
|
||||||
ExprBox(@Expr, @Expr),
|
ExprBox(@Expr, @Expr),
|
||||||
ExprVec(Vec<@Expr>),
|
ExprVec(Vec<@Expr>),
|
||||||
ExprCall(@Expr, Vec<@Expr>),
|
ExprCall(@Expr, Vec<@Expr>),
|
||||||
ExprMethodCall(Ident, Vec<P<Ty>>, Vec<@Expr>),
|
ExprMethodCall(SpannedIdent, Vec<P<Ty>>, Vec<@Expr>),
|
||||||
ExprTup(Vec<@Expr>),
|
ExprTup(Vec<@Expr>),
|
||||||
ExprBinary(BinOp, @Expr, @Expr),
|
ExprBinary(BinOp, @Expr, @Expr),
|
||||||
ExprUnary(UnOp, @Expr),
|
ExprUnary(UnOp, @Expr),
|
||||||
|
|
|
@ -12,7 +12,7 @@ use abi;
|
||||||
use ast::{P, Ident};
|
use ast::{P, Ident};
|
||||||
use ast;
|
use ast;
|
||||||
use ast_util;
|
use ast_util;
|
||||||
use codemap::{Span, respan, DUMMY_SP};
|
use codemap::{Span, respan, Spanned, DUMMY_SP};
|
||||||
use ext::base::ExtCtxt;
|
use ext::base::ExtCtxt;
|
||||||
use ext::quote::rt::*;
|
use ext::quote::rt::*;
|
||||||
use fold::Folder;
|
use fold::Folder;
|
||||||
|
@ -548,8 +548,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
expr: @ast::Expr,
|
expr: @ast::Expr,
|
||||||
ident: ast::Ident,
|
ident: ast::Ident,
|
||||||
mut args: Vec<@ast::Expr> ) -> @ast::Expr {
|
mut args: Vec<@ast::Expr> ) -> @ast::Expr {
|
||||||
|
let id = Spanned { node: ident, span: span };
|
||||||
args.unshift(expr);
|
args.unshift(expr);
|
||||||
self.expr(span, ast::ExprMethodCall(ident, Vec::new(), args))
|
self.expr(span, ast::ExprMethodCall(id, Vec::new(), args))
|
||||||
}
|
}
|
||||||
fn expr_block(&self, b: P<ast::Block>) -> @ast::Expr {
|
fn expr_block(&self, b: P<ast::Block>) -> @ast::Expr {
|
||||||
self.expr(b.span, ast::ExprBlock(b))
|
self.expr(b.span, ast::ExprBlock(b))
|
||||||
|
|
|
@ -798,7 +798,7 @@ pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr {
|
||||||
}
|
}
|
||||||
ExprMethodCall(i, ref tps, ref args) => {
|
ExprMethodCall(i, ref tps, ref args) => {
|
||||||
ExprMethodCall(
|
ExprMethodCall(
|
||||||
folder.fold_ident(i),
|
respan(i.span, folder.fold_ident(i.node)),
|
||||||
tps.iter().map(|&x| folder.fold_ty(x)).collect(),
|
tps.iter().map(|&x| folder.fold_ty(x)).collect(),
|
||||||
args.iter().map(|&x| folder.fold_expr(x)).collect())
|
args.iter().map(|&x| folder.fold_expr(x)).collect())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1646,7 +1646,11 @@ impl<'a> Parser<'a> {
|
||||||
ExprCall(f, args)
|
ExprCall(f, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_method_call(&mut self, ident: Ident, tps: Vec<P<Ty>> , args: Vec<@Expr> ) -> ast::Expr_ {
|
fn mk_method_call(&mut self,
|
||||||
|
ident: ast::SpannedIdent,
|
||||||
|
tps: Vec<P<Ty>>,
|
||||||
|
args: Vec<@Expr>)
|
||||||
|
-> ast::Expr_ {
|
||||||
ExprMethodCall(ident, tps, args)
|
ExprMethodCall(ident, tps, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1919,6 +1923,7 @@ impl<'a> Parser<'a> {
|
||||||
if self.eat(&token::DOT) {
|
if self.eat(&token::DOT) {
|
||||||
match self.token {
|
match self.token {
|
||||||
token::IDENT(i, _) => {
|
token::IDENT(i, _) => {
|
||||||
|
let dot = self.last_span.hi;
|
||||||
hi = self.span.hi;
|
hi = self.span.hi;
|
||||||
self.bump();
|
self.bump();
|
||||||
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
||||||
|
@ -1940,7 +1945,8 @@ impl<'a> Parser<'a> {
|
||||||
hi = self.last_span.hi;
|
hi = self.last_span.hi;
|
||||||
|
|
||||||
es.unshift(e);
|
es.unshift(e);
|
||||||
let nd = self.mk_method_call(i, tys, es);
|
let id = spanned(dot, hi, i);
|
||||||
|
let nd = self.mk_method_call(id, tys, es);
|
||||||
e = self.mk_expr(lo, hi, nd);
|
e = self.mk_expr(lo, hi, nd);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -1208,7 +1208,7 @@ impl<'a> State<'a> {
|
||||||
let base_args = args.slice_from(1);
|
let base_args = args.slice_from(1);
|
||||||
try!(self.print_expr(*args.get(0)));
|
try!(self.print_expr(*args.get(0)));
|
||||||
try!(word(&mut self.s, "."));
|
try!(word(&mut self.s, "."));
|
||||||
try!(self.print_ident(ident));
|
try!(self.print_ident(ident.node));
|
||||||
if tys.len() > 0u {
|
if tys.len() > 0u {
|
||||||
try!(word(&mut self.s, "::<"));
|
try!(word(&mut self.s, "::<"));
|
||||||
try!(self.commasep(Inconsistent, tys.as_slice(),
|
try!(self.commasep(Inconsistent, tys.as_slice(),
|
||||||
|
|
30
src/test/compile-fail/method-call-err-msg.rs
Normal file
30
src/test/compile-fail/method-call-err-msg.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2012-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.
|
||||||
|
|
||||||
|
// Test that parameter cardinality or missing method error gets span exactly.
|
||||||
|
|
||||||
|
pub struct Foo;
|
||||||
|
impl Foo {
|
||||||
|
fn zero(self) -> Foo { self }
|
||||||
|
fn one(self, _: int) -> Foo { self }
|
||||||
|
fn two(self, _: int, _: int) -> Foo { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Foo;
|
||||||
|
x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied
|
||||||
|
.one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied
|
||||||
|
.two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied
|
||||||
|
|
||||||
|
let y = Foo;
|
||||||
|
y.zero()
|
||||||
|
.take() //~ ERROR type `Foo` does not implement any method in scope named `take`
|
||||||
|
.one(0);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue