1 // Copyright 2012 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.
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.
13 use rustc::infer::InferOk;
14 use rustc::traits::ObligationCause;
17 use syntax_pos::{self, Span};
19 use rustc::hir::def::Def;
20 use rustc::ty::{self, Ty, AssociatedItem};
21 use errors::{DiagnosticBuilder, CodeMapper};
23 use super::method::probe;
25 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
26 // Requires that the two types unify, and prints an error message if
28 pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
29 self.demand_suptype_diag(sp, expected, actual).map(|mut e| e.emit());
32 pub fn demand_suptype_diag(&self,
35 actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
36 let cause = &self.misc(sp);
37 match self.at(cause, self.param_env).sup(expected, actual) {
38 Ok(InferOk { obligations, value: () }) => {
39 self.register_predicates(obligations);
43 Some(self.report_mismatched_types(&cause, expected, actual, e))
48 pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
49 if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
54 pub fn demand_eqtype_diag(&self,
57 actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
58 self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
61 pub fn demand_eqtype_with_origin(&self,
62 cause: &ObligationCause<'tcx>,
64 actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
65 match self.at(cause, self.param_env).eq(expected, actual) {
66 Ok(InferOk { obligations, value: () }) => {
67 self.register_predicates(obligations);
71 Some(self.report_mismatched_types(cause, expected, actual, e))
76 pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
77 if let Some(mut err) = self.demand_coerce_diag(expr, checked_ty, expected) {
82 // Checks that the type of `expr` can be coerced to `expected`.
84 // NB: This code relies on `self.diverges` to be accurate. In
85 // particular, assignments to `!` will be permitted if the
86 // diverges flag is currently "always".
87 pub fn demand_coerce_diag(&self,
90 expected: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
91 let expected = self.resolve_type_vars_with_obligations(expected);
93 if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
94 let cause = self.misc(expr.span);
95 let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
96 let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
97 if let Some(suggestion) = self.check_ref(expr,
100 err.help(&suggestion);
102 let mode = probe::Mode::MethodCall;
103 let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
108 if suggestions.len() > 0 {
109 err.help(&format!("here are some functions which \
110 might fulfill your needs:\n{}",
111 self.get_best_match(&suggestions).join("\n")));
119 fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
122 if self.has_no_input_arg(method) {
129 fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> Vec<String> {
132 .map(|method| self.format_method_suggestion(&*method))
133 .collect::<Vec<String>>()
136 fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec<String> {
137 let no_argument_methods: Vec<_> =
139 .filter(|ref x| self.has_no_input_arg(&*x))
142 if no_argument_methods.len() > 0 {
143 self.display_suggested_methods(&no_argument_methods)
145 self.display_suggested_methods(&methods)
149 // This function checks if the method isn't static and takes other arguments than `self`.
150 fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
152 Def::Method(def_id) => {
153 self.tcx.fn_sig(def_id).inputs().skip_binder().len() == 1
159 /// This function is used to determine potential "simple" improvements or users' errors and
160 /// provide them useful help. For example:
163 /// fn some_fn(s: &str) {}
165 /// let x = "hey!".to_owned();
166 /// some_fn(x); // error
169 /// No need to find every potential function which could make a coercion to transform a
170 /// `String` into a `&str` since a `&` would do the trick!
172 /// In addition of this check, it also checks between references mutability state. If the
173 /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
177 checked_ty: Ty<'tcx>,
180 match (&expected.sty, &checked_ty.sty) {
181 (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
182 (&ty::TyRef(_, mutability), _) => {
183 // Check if it can work when put into a ref. For example:
186 // fn bar(x: &mut i32) {}
189 // bar(&x); // error, expected &mut
191 let ref_ty = match mutability.mutbl {
192 hir::Mutability::MutMutable => self.tcx.mk_mut_ref(
193 self.tcx.mk_region(ty::ReStatic),
195 hir::Mutability::MutImmutable => self.tcx.mk_imm_ref(
196 self.tcx.mk_region(ty::ReStatic),
199 if self.can_coerce(ref_ty, expected) {
200 // Use the callsite's span if this is a macro call. #41858
201 let sp = self.sess().codemap().call_span_if_macro(expr.span);
202 if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
203 return Some(format!("try with `{}{}`",
204 match mutability.mutbl {
205 hir::Mutability::MutMutable => "&mut ",
206 hir::Mutability::MutImmutable => "&",