From 5598f351627bf1c235e7b7d06bd60ad0bad537cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Dec 2016 17:44:41 -0800 Subject: [PATCH] Suggest solutions for `fn foo(&foo: Foo)` --- src/librustc_typeck/check/_match.rs | 21 ++++++++++++++- src/librustc_typeck/check/demand.rs | 18 ++++++++++--- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 4 ++- src/test/ui/mismatched_types/issue-38371.rs | 26 +++++++++++++++++++ .../ui/mismatched_types/issue-38371.stderr | 13 ++++++++++ 6 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/mismatched_types/issue-38371.rs create mode 100644 src/test/ui/mismatched_types/issue-38371.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 9b86196b3ece..fcd61b3c7c8c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -27,6 +27,10 @@ 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); + } + + 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); @@ -212,7 +216,22 @@ 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); + let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); + if let Some(mut err) = err { + if is_arg { + if let Ok(snippet) = self.sess().codemap() + .span_to_snippet(pat.span) + { + err.help(&format!("did you mean `{}: &{}`?", + snippet, + expected)); + 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 393d9341a084..8838eb9b1b3f 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 7275fbd12036..b89654138dd1 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 c80db7fa4d0e..4c124cdd60c0 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 000000000000..20998447737d --- /dev/null +++ b/src/test/ui/mismatched_types/issue-38371.rs @@ -0,0 +1,26 @@ +// Copyright 2016 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. + +struct Foo { +} + +fn foo(&foo: Foo) { // illegal syntax +} + +fn bar(foo: Foo) { // legal +} + +fn qux(foo: &Foo) { // legal +} + +fn zar(&foo: &Foo) { // legal +} + +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 000000000000..8b27218f497d --- /dev/null +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/issue-38371.rs:14:8 + | +14 | fn foo(&foo: Foo) { // illegal syntax + | ^^^^ expected struct `Foo`, found reference + | + = note: expected type `Foo` + = note: found type `&_` + = help: did you mean `&foo: &Foo`? + = help: did you mean `foo: Foo`? + +error: aborting due to previous error +