diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 9b86196b3ece2..f7fd78097b80b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -27,9 +27,17 @@ use syntax_pos::Span; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { + self.check_pat_arg(pat, expected, false); + } + + /// The `is_arg` argument indicates whether this pattern is the + /// *outermost* pattern in an argument (e.g., in `fn foo(&x: + /// &u32)`, it is true for the `&x` pattern but not `x`). This is + /// used to tailor error reporting. + pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: bool) { let tcx = self.tcx; - debug!("check_pat(pat={:?},expected={:?})", pat, expected); + debug!("check_pat(pat={:?},expected={:?},is_arg={})", pat, expected, is_arg); let ty = match pat.node { PatKind::Wild => { @@ -202,6 +210,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // can, to avoid creating needless variables. This // also helps with the bad interactions of the given // hack detailed in (*) below. + debug!("check_pat_arg: expected={:?}", expected); let (rptr_ty, inner_ty) = match expected.sty { ty::TyRef(_, mt) if mt.mutbl == mutbl => { (expected, mt.ty) @@ -212,7 +221,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; let region = self.next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = tcx.mk_ref(region, mt); - self.demand_eqtype(pat.span, expected, rptr_ty); + debug!("check_pat_arg: demanding {:?} = {:?}", expected, rptr_ty); + let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); + + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + if is_arg { + if let PatKind::Binding(..) = inner.node { + if let Ok(snippet) = self.sess().codemap() + .span_to_snippet(pat.span) + { + err.help(&format!("did you mean `{}: &{}`?", + &snippet[1..], + expected)); + } + } + } + err.emit(); + } (rptr_ty, inner_ty) } }; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 393d9341a0843..8838eb9b1b3ff 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -19,6 +19,7 @@ use syntax_pos::{self, Span}; use rustc::hir; use rustc::hir::def::Def; use rustc::ty::{self, AssociatedItem}; +use errors::DiagnosticBuilder; use super::method::probe; @@ -38,20 +39,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - self.demand_eqtype_with_origin(&self.misc(sp), expected, actual); + if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) { + err.emit(); + } + } + + pub fn demand_eqtype_diag(&self, + sp: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>) -> Option> { + self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } pub fn demand_eqtype_with_origin(&self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, - actual: Ty<'tcx>) - { + actual: Ty<'tcx>) -> Option> { match self.eq_types(false, cause, actual, expected) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); + None }, Err(e) => { - self.report_mismatched_types(cause, expected, actual, e).emit(); + Some(self.report_mismatched_types(cause, expected, actual, e)) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7275fbd12036b..b89654138dd13 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -798,7 +798,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation); // Check the pattern. - fcx.check_pat(&arg.pat, arg_ty); + fcx.check_pat_arg(&arg.pat, arg_ty, true); fcx.write_ty(arg.id, arg_ty); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index c80db7fa4d0e0..4c124cdd60c0f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -505,7 +505,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); - fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty); + if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) { + err.emit(); + } } fn check_variances_for_type_defn(&self, diff --git a/src/test/ui/mismatched_types/issue-38371.rs b/src/test/ui/mismatched_types/issue-38371.rs new file mode 100644 index 0000000000000..cf66330017f58 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-38371.rs @@ -0,0 +1,37 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(slice_patterns)] + + +struct Foo { +} + +fn foo(&foo: Foo) { +} + +fn bar(foo: Foo) { +} + +fn qux(foo: &Foo) { +} + +fn zar(&foo: &Foo) { +} + +fn agh(&&bar: &u32) { +} + +fn bgh(&&bar: u32) { +} + +fn ugh(&[bar]: &u32) { +} + +fn main() {} diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr new file mode 100644 index 0000000000000..b0e56094fcff3 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -0,0 +1,36 @@ +error[E0308]: mismatched types + --> $DIR/issue-38371.rs:16:8 + | +16 | fn foo(&foo: Foo) { + | ^^^^ expected struct `Foo`, found reference + | + = note: expected type `Foo` + = note: found type `&_` + = help: did you mean `foo: &Foo`? + +error[E0308]: mismatched types + --> $DIR/issue-38371.rs:28:9 + | +28 | fn agh(&&bar: &u32) { + | ^^^^ expected u32, found reference + | + = note: expected type `u32` + = note: found type `&_` + +error[E0308]: mismatched types + --> $DIR/issue-38371.rs:31:8 + | +31 | fn bgh(&&bar: u32) { + | ^^^^^ expected u32, found reference + | + = note: expected type `u32` + = note: found type `&_` + +error[E0529]: expected an array or slice, found `u32` + --> $DIR/issue-38371.rs:34:9 + | +34 | fn ugh(&[bar]: &u32) { + | ^^^^^ pattern cannot match with input type `u32` + +error: aborting due to 4 previous errors +