]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_typeck/check/demand.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc_typeck / check / demand.rs
index 7110a1ba81d8f4888891ca60ef464136e54e662c..08cf6d3a59ec573a911c39a7a0596dfecdb25226 100644 (file)
@@ -74,10 +74,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
-        if let Some(mut err) = self.demand_coerce_diag(expr, checked_ty, expected) {
+    pub fn demand_coerce(&self,
+                         expr: &hir::Expr,
+                         checked_ty: Ty<'tcx>,
+                         expected: Ty<'tcx>)
+                         -> Ty<'tcx> {
+        let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected);
+        if let Some(mut err) = err {
             err.emit();
         }
+        ty
     }
 
     // Checks that the type of `expr` can be coerced to `expected`.
@@ -88,61 +94,64 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn demand_coerce_diag(&self,
                               expr: &hir::Expr,
                               checked_ty: Ty<'tcx>,
-                              expected: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
+                              expected: Ty<'tcx>)
+                              -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
         let expected = self.resolve_type_vars_with_obligations(expected);
 
-        if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
-            let cause = self.misc(expr.span);
-            let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
-            let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+        let e = match self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
+            Ok(ty) => return (ty, None),
+            Err(e) => e
+        };
 
-            // If the expected type is an enum with any variants whose sole
-            // field is of the found type, suggest such variants. See Issue
-            // #42764.
-            if let ty::TyAdt(expected_adt, substs) = expected.sty {
-                let mut compatible_variants = vec![];
-                for variant in &expected_adt.variants {
-                    if variant.fields.len() == 1 {
-                        let sole_field = &variant.fields[0];
-                        let sole_field_ty = sole_field.ty(self.tcx, substs);
-                        if self.can_coerce(expr_ty, sole_field_ty) {
-                            let mut variant_path = self.tcx.item_path_str(variant.did);
-                            variant_path = variant_path.trim_left_matches("std::prelude::v1::")
-                                .to_string();
-                            compatible_variants.push(variant_path);
-                        }
+        let cause = self.misc(expr.span);
+        let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
+        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+
+        // If the expected type is an enum with any variants whose sole
+        // field is of the found type, suggest such variants. See Issue
+        // #42764.
+        if let ty::TyAdt(expected_adt, substs) = expected.sty {
+            let mut compatible_variants = vec![];
+            for variant in &expected_adt.variants {
+                if variant.fields.len() == 1 {
+                    let sole_field = &variant.fields[0];
+                    let sole_field_ty = sole_field.ty(self.tcx, substs);
+                    if self.can_coerce(expr_ty, sole_field_ty) {
+                        let mut variant_path = self.tcx.item_path_str(variant.did);
+                        variant_path = variant_path.trim_left_matches("std::prelude::v1::")
+                            .to_string();
+                        compatible_variants.push(variant_path);
                     }
                 }
-                if !compatible_variants.is_empty() {
-                    let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
-                    let suggestions = compatible_variants.iter()
-                        .map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
-                    err.span_suggestions(expr.span,
-                                         "try using a variant of the expected type",
-                                         suggestions);
-                }
             }
+            if !compatible_variants.is_empty() {
+                let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
+                let suggestions = compatible_variants.iter()
+                    .map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
+                err.span_suggestions(expr.span,
+                                     "try using a variant of the expected type",
+                                     suggestions);
+            }
+        }
 
-            if let Some(suggestion) = self.check_ref(expr,
-                                                     checked_ty,
-                                                     expected) {
-                err.help(&suggestion);
-            } else {
-                let mode = probe::Mode::MethodCall;
-                let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
-                                                             mode,
-                                                             expected,
-                                                             checked_ty,
-                                                             ast::DUMMY_NODE_ID);
-                if suggestions.len() > 0 {
-                    err.help(&format!("here are some functions which \
-                                       might fulfill your needs:\n{}",
-                                      self.get_best_match(&suggestions).join("\n")));
-                }
+        if let Some(suggestion) = self.check_ref(expr,
+                                                 checked_ty,
+                                                 expected) {
+            err.help(&suggestion);
+        } else {
+            let mode = probe::Mode::MethodCall;
+            let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP,
+                                                         mode,
+                                                         expected,
+                                                         checked_ty,
+                                                         ast::DUMMY_NODE_ID);
+            if suggestions.len() > 0 {
+                err.help(&format!("here are some functions which \
+                                   might fulfill your needs:\n{}",
+                                  self.get_best_match(&suggestions).join("\n")));
             }
-            return Some(err);
         }
-        None
+        (expected, Some(err))
     }
 
     fn format_method_suggestion(&self, method: &AssociatedItem) -> String {