Skip to content

Commit 1ca100d

Browse files
committed
Auto merge of #38605 - estebank:fix-38371, r=nikomatsakis
Suggest solutions for `fn foo(&foo: Foo)` For a given file: ```rust struct Foo {} fn foo(&foo: Foo) {} ``` suggest: ``` error[E0308]: mismatched types --> file.rs:3:8 | 3 | fn foo(&foo: Foo) {} | ^^^^ expected struct `Foo`, found reference | = note: expected type `Foo` = note: found type `&_` = help: did you mean `foo: &Foo`? ``` Fix #38371.
2 parents b27c709 + d723e02 commit 1ca100d

File tree

6 files changed

+120
-8
lines changed

6 files changed

+120
-8
lines changed

src/librustc_typeck/check/_match.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,17 @@ use syntax_pos::Span;
2727

2828
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2929
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
30+
self.check_pat_arg(pat, expected, false);
31+
}
32+
33+
/// The `is_arg` argument indicates whether this pattern is the
34+
/// *outermost* pattern in an argument (e.g., in `fn foo(&x:
35+
/// &u32)`, it is true for the `&x` pattern but not `x`). This is
36+
/// used to tailor error reporting.
37+
pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: bool) {
3038
let tcx = self.tcx;
3139

32-
debug!("check_pat(pat={:?},expected={:?})", pat, expected);
40+
debug!("check_pat(pat={:?},expected={:?},is_arg={})", pat, expected, is_arg);
3341

3442
let ty = match pat.node {
3543
PatKind::Wild => {
@@ -202,6 +210,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
202210
// can, to avoid creating needless variables. This
203211
// also helps with the bad interactions of the given
204212
// hack detailed in (*) below.
213+
debug!("check_pat_arg: expected={:?}", expected);
205214
let (rptr_ty, inner_ty) = match expected.sty {
206215
ty::TyRef(_, mt) if mt.mutbl == mutbl => {
207216
(expected, mt.ty)
@@ -212,7 +221,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
212221
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
213222
let region = self.next_region_var(infer::PatternRegion(pat.span));
214223
let rptr_ty = tcx.mk_ref(region, mt);
215-
self.demand_eqtype(pat.span, expected, rptr_ty);
224+
debug!("check_pat_arg: demanding {:?} = {:?}", expected, rptr_ty);
225+
let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty);
226+
227+
// Look for a case like `fn foo(&foo: u32)` and suggest
228+
// `fn foo(foo: &u32)`
229+
if let Some(mut err) = err {
230+
if is_arg {
231+
if let PatKind::Binding(..) = inner.node {
232+
if let Ok(snippet) = self.sess().codemap()
233+
.span_to_snippet(pat.span)
234+
{
235+
err.help(&format!("did you mean `{}: &{}`?",
236+
&snippet[1..],
237+
expected));
238+
}
239+
}
240+
}
241+
err.emit();
242+
}
216243
(rptr_ty, inner_ty)
217244
}
218245
};

src/librustc_typeck/check/demand.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use syntax_pos::{self, Span};
1919
use rustc::hir;
2020
use rustc::hir::def::Def;
2121
use rustc::ty::{self, AssociatedItem};
22+
use errors::DiagnosticBuilder;
2223

2324
use super::method::probe;
2425

@@ -38,20 +39,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3839
}
3940

4041
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
41-
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual);
42+
if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
43+
err.emit();
44+
}
45+
}
46+
47+
pub fn demand_eqtype_diag(&self,
48+
sp: Span,
49+
expected: Ty<'tcx>,
50+
actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
51+
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
4252
}
4353

4454
pub fn demand_eqtype_with_origin(&self,
4555
cause: &ObligationCause<'tcx>,
4656
expected: Ty<'tcx>,
47-
actual: Ty<'tcx>)
48-
{
57+
actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
4958
match self.eq_types(false, cause, actual, expected) {
5059
Ok(InferOk { obligations, value: () }) => {
5160
self.register_predicates(obligations);
61+
None
5262
},
5363
Err(e) => {
54-
self.report_mismatched_types(cause, expected, actual, e).emit();
64+
Some(self.report_mismatched_types(cause, expected, actual, e))
5565
}
5666
}
5767
}

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
796796
fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
797797

798798
// Check the pattern.
799-
fcx.check_pat(&arg.pat, arg_ty);
799+
fcx.check_pat_arg(&arg.pat, arg_ty, true);
800800
fcx.write_ty(arg.id, arg_ty);
801801
}
802802

src/librustc_typeck/check/wfcheck.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
505505
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
506506

507507
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
508-
fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty);
508+
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) {
509+
err.emit();
510+
}
509511
}
510512

511513
fn check_variances_for_type_defn(&self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![feature(slice_patterns)]
11+
12+
13+
struct Foo {
14+
}
15+
16+
fn foo(&foo: Foo) {
17+
}
18+
19+
fn bar(foo: Foo) {
20+
}
21+
22+
fn qux(foo: &Foo) {
23+
}
24+
25+
fn zar(&foo: &Foo) {
26+
}
27+
28+
fn agh(&&bar: &u32) {
29+
}
30+
31+
fn bgh(&&bar: u32) {
32+
}
33+
34+
fn ugh(&[bar]: &u32) {
35+
}
36+
37+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-38371.rs:16:8
3+
|
4+
16 | fn foo(&foo: Foo) {
5+
| ^^^^ expected struct `Foo`, found reference
6+
|
7+
= note: expected type `Foo`
8+
= note: found type `&_`
9+
= help: did you mean `foo: &Foo`?
10+
11+
error[E0308]: mismatched types
12+
--> $DIR/issue-38371.rs:28:9
13+
|
14+
28 | fn agh(&&bar: &u32) {
15+
| ^^^^ expected u32, found reference
16+
|
17+
= note: expected type `u32`
18+
= note: found type `&_`
19+
20+
error[E0308]: mismatched types
21+
--> $DIR/issue-38371.rs:31:8
22+
|
23+
31 | fn bgh(&&bar: u32) {
24+
| ^^^^^ expected u32, found reference
25+
|
26+
= note: expected type `u32`
27+
= note: found type `&_`
28+
29+
error[E0529]: expected an array or slice, found `u32`
30+
--> $DIR/issue-38371.rs:34:9
31+
|
32+
34 | fn ugh(&[bar]: &u32) {
33+
| ^^^^^ pattern cannot match with input type `u32`
34+
35+
error: aborting due to 4 previous errors
36+

0 commit comments

Comments
 (0)