about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-24 20:49:55 +0000
committerbors <bors@rust-lang.org>2021-08-24 20:49:55 +0000
commitb03ccace573bb91e27625c190a0f7807045a1012 (patch)
treeadc092773653dca60719e5f20a09d258c3d7a8db
parent0599f3403366d9c57f0625e6de3af214b5042a90 (diff)
parentec9531bcb09e52c5fbbabbedc8927b99f7e6fd9c (diff)
downloadrust-b03ccace573bb91e27625c190a0f7807045a1012.tar.gz
rust-b03ccace573bb91e27625c190a0f7807045a1012.zip
Auto merge of #88266 - nikomatsakis:issue-87879, r=jackh726
resolve type variables after checking casts

r? `@jackh726`

Fixes #87814
Fixes #88118

Supercedes #87879 (cc `@ldm0)`
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs2
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs4
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs1
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs23
-rw-r--r--compiler/rustc_typeck/src/check/fallback.rs6
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs1
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs3
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue_88118.rs15
-rw-r--r--src/test/ui/closures/issue-87814-1.rs8
-rw-r--r--src/test/ui/closures/issue-87814-2.rs11
11 files changed, 69 insertions, 8 deletions
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 87fd8f1e03b..01227cad334 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -14,6 +14,7 @@ use rustc_trait_selection::traits::{
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
     pub fn check_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -26,6 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let acrb = arms_contain_ref_bindings(arms);
         let scrutinee_ty = self.demand_scrutinee_type(scrut, acrb, arms.is_empty());
+        debug!(?scrutinee_ty);
 
         // If there are no arms, that is a diverging match; a special case.
         if arms.is_empty() {
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 181972e3e7b..14550690e63 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -51,6 +51,7 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
+#[derive(Debug)]
 pub struct CastCheck<'tcx> {
     expr: &'tcx hir::Expr<'tcx>,
     expr_ty: Ty<'tcx>,
@@ -603,12 +604,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         });
     }
 
+    #[instrument(skip(fcx), level = "debug")]
     pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
         self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
         self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
 
-        debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
-
         if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
             self.report_cast_to_unsized_type(fcx);
         } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 0b4df8e6d3c..17a81486048 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1328,6 +1328,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
     /// The inner coercion "engine". If `expression` is `None`, this
     /// is a forced-unit case, and hence `expression_ty` must be
     /// `Nil`.
+    #[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")]
     crate fn coerce_inner<'a>(
         &mut self,
         fcx: &FnCtxt<'a, 'tcx>,
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 9cbd3f7bb33..eaf24552355 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -156,12 +156,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Note that inspecting a type's structure *directly* may expose the fact
     /// that there are actually multiple representations for `Error`, so avoid
     /// that when err needs to be handled differently.
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        debug!(">> type-checking: expected={:?}, expr={:?} ", expected, expr);
+        if self.tcx().sess.verbose() {
+            // make this code only run with -Zverbose because it is probably slow
+            if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
+                if !lint_str.contains("\n") {
+                    debug!("expr text: {}", lint_str);
+                } else {
+                    let mut lines = lint_str.lines();
+                    if let Some(line0) = lines.next() {
+                        let remaining_lines = lines.count();
+                        debug!("expr text: {}", line0);
+                        debug!("expr text: ...(and {} more lines)", remaining_lines);
+                    }
+                }
+            }
+        }
 
         // True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block
         // without the final expr (e.g. `try { return; }`). We don't want to generate an
@@ -1039,7 +1054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let t_cast = self.to_ty_saving_user_provided_ty(t);
         let t_cast = self.resolve_vars_if_possible(t_cast);
         let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-        let t_cast = self.resolve_vars_if_possible(t_cast);
+        let t_expr = self.resolve_vars_if_possible(t_expr);
 
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
@@ -1049,6 +1064,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
             match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                 Ok(cast_check) => {
+                    debug!(
+                        "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
+                        t_cast, t_expr, cast_check,
+                    );
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index 69a8970ae09..8f6cdc7bb12 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -3,7 +3,9 @@ use rustc_infer::infer::type_variable::Diverging;
 use rustc_middle::ty::{self, Ty};
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
-    pub(super) fn type_inference_fallback(&self) {
+    /// Performs type inference fallback, returning true if any fallback
+    /// occurs.
+    pub(super) fn type_inference_fallback(&self) -> bool {
         // All type checking constraints were added, try to fallback unsolved variables.
         self.select_obligations_where_possible(false, |_| {});
         let mut fallback_has_occurred = false;
@@ -50,6 +52,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
 
         // See if we can make any more progress.
         self.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+        fallback_has_occurred
     }
 
     // Tries to apply a fallback to `ty` if it is an unsolved variable.
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 9952413353f..b624e07374e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -29,6 +29,7 @@ use std::slice;
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&self) {
         let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+        debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
         for cast in deferred_cast_checks.drain(..) {
             cast.check(self);
         }
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 2a196644dac..a88b1c7af5a 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -446,11 +446,12 @@ fn typeck_with_fallback<'tcx>(
             fcx
         };
 
-        fcx.type_inference_fallback();
+        let fallback_has_occurred = fcx.type_inference_fallback();
 
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
         fcx.check_casts();
+        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
 
         // Closure and generator analysis may run after fallback
         // because they don't constrain other type variables.
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 77834feb9ad..cd00d181ed0 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -120,9 +120,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn consume_body(&mut self, body: &hir::Body<'_>) {
-        debug!("consume_body(body={:?})", body);
-
         for param in body.params {
             let param_ty = return_if_err!(self.mc.pat_ty_adjusted(&param.pat));
             debug!("consume_body: param_ty = {:?}", param_ty);
diff --git a/src/test/ui/closures/2229_closure_analysis/issue_88118.rs b/src/test/ui/closures/2229_closure_analysis/issue_88118.rs
new file mode 100644
index 00000000000..453b7e04a36
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/issue_88118.rs
@@ -0,0 +1,15 @@
+// Regression test for #88118. Used to ICE.
+//
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(capture_disjoint_fields)]
+
+fn foo<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) {
+    Box::new(move |value| {
+        (|_| handler.clone()())(value);
+        None
+    }) as Box<dyn Fn(i32) -> Option<i32>>;
+}
+
+fn main() {}
diff --git a/src/test/ui/closures/issue-87814-1.rs b/src/test/ui/closures/issue-87814-1.rs
new file mode 100644
index 00000000000..5cf01ddf5d7
--- /dev/null
+++ b/src/test/ui/closures/issue-87814-1.rs
@@ -0,0 +1,8 @@
+// check-pass
+fn main() {
+    let mut schema_all = vec![];
+    (0..42).for_each(|_x| match Err(()) as Result<(), _> {
+        Ok(()) => schema_all.push(()),
+        Err(_) => (),
+    });
+}
diff --git a/src/test/ui/closures/issue-87814-2.rs b/src/test/ui/closures/issue-87814-2.rs
new file mode 100644
index 00000000000..7a5facdac58
--- /dev/null
+++ b/src/test/ui/closures/issue-87814-2.rs
@@ -0,0 +1,11 @@
+// check-pass
+#![feature(try_reserve)]
+
+fn main() {
+    let mut schema_all: (Vec<String>, Vec<String>) = (vec![], vec![]);
+
+    let _c = || match schema_all.0.try_reserve(1) as Result<(), _> {
+        Ok(()) => (),
+        Err(_) => (),
+    };
+}