]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/demand.rs
Move parse_remaining_bounds into a separate function
[rust.git] / src / librustc_typeck / check / demand.rs
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.
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
11
12 use check::FnCtxt;
13 use rustc::ty::Ty;
14 use rustc::infer::{InferOk};
15 use rustc::traits::ObligationCause;
16
17 use syntax::ast;
18 use syntax_pos::{self, Span};
19 use rustc::hir;
20 use rustc::hir::def::Def;
21 use rustc::ty::{self, AssociatedItem};
22 use errors::DiagnosticBuilder;
23
24 use super::method::probe;
25
26 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
27     // Requires that the two types unify, and prints an error message if
28     // they don't.
29     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
30         let cause = self.misc(sp);
31         match self.sub_types(false, &cause, actual, expected) {
32             Ok(InferOk { obligations, value: () }) => {
33                 self.register_predicates(obligations);
34             },
35             Err(e) => {
36                 self.report_mismatched_types(&cause, expected, actual, e).emit();
37             }
38         }
39     }
40
41     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
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)
52     }
53
54     pub fn demand_eqtype_with_origin(&self,
55                                      cause: &ObligationCause<'tcx>,
56                                      expected: Ty<'tcx>,
57                                      actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
58         match self.eq_types(false, cause, actual, expected) {
59             Ok(InferOk { obligations, value: () }) => {
60                 self.register_predicates(obligations);
61                 None
62             },
63             Err(e) => {
64                 Some(self.report_mismatched_types(cause, expected, actual, e))
65             }
66         }
67     }
68
69     // Checks that the type of `expr` can be coerced to `expected`.
70     //
71     // NB: This code relies on `self.diverges` to be accurate.  In
72     // particular, assignments to `!` will be permitted if the
73     // diverges flag is currently "always".
74     pub fn demand_coerce(&self,
75                          expr: &hir::Expr,
76                          checked_ty: Ty<'tcx>,
77                          expected: Ty<'tcx>) {
78         let expected = self.resolve_type_vars_with_obligations(expected);
79
80         if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
81             let cause = self.misc(expr.span);
82             let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
83             let mode = probe::Mode::MethodCall;
84             let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
85                                                          mode,
86                                                          expected,
87                                                          checked_ty,
88                                                          ast::DUMMY_NODE_ID);
89             let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
90             if suggestions.len() > 0 {
91                 err.help(&format!("here are some functions which \
92                                    might fulfill your needs:\n{}",
93                                   self.get_best_match(&suggestions).join("\n")));
94             };
95             err.emit();
96         }
97     }
98
99     fn format_method_suggestion(&self, method: &AssociatedItem) -> String {
100         format!("- .{}({})",
101                 method.name,
102                 if self.has_no_input_arg(method) {
103                     ""
104                 } else {
105                     "..."
106                 })
107     }
108
109     fn display_suggested_methods(&self, methods: &[AssociatedItem]) -> Vec<String> {
110         methods.iter()
111                .take(5)
112                .map(|method| self.format_method_suggestion(&*method))
113                .collect::<Vec<String>>()
114     }
115
116     fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec<String> {
117         let no_argument_methods: Vec<_> =
118             methods.iter()
119                    .filter(|ref x| self.has_no_input_arg(&*x))
120                    .map(|x| x.clone())
121                    .collect();
122         if no_argument_methods.len() > 0 {
123             self.display_suggested_methods(&no_argument_methods)
124         } else {
125             self.display_suggested_methods(&methods)
126         }
127     }
128
129     // This function checks if the method isn't static and takes other arguments than `self`.
130     fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
131         match method.def() {
132             Def::Method(def_id) => {
133                 match self.tcx.item_type(def_id).sty {
134                     ty::TypeVariants::TyFnDef(_, _, sig) => {
135                         sig.inputs().skip_binder().len() == 1
136                     }
137                     _ => false,
138                 }
139             }
140             _ => false,
141         }
142     }
143 }