about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-12-09 03:07:31 +0100
committerDavid Wood <david@davidtw.co>2018-12-30 14:30:59 +0100
commit95c18382cb01480b99b55163c19f35907de80eb4 (patch)
treeb69ab6e7896afbe6a401be810530e3e4bc2c5965 /src
parent6092d92d70c81861ed46f2496e62dc74183857fd (diff)
downloadrust-95c18382cb01480b99b55163c19f35907de80eb4.tar.gz
rust-95c18382cb01480b99b55163c19f35907de80eb4.zip
Fix unresolved inference variable ICE.
This commit moves well-formedness check for the
`UserTypeAnnotation::Ty(..)` case from always running to only when the
code is reachable. This solves the ICE that resulted from
`src/test/ui/issue-54943-1.rs` (a minimal repro of `dropck-eyepatch`
run-pass tests that failed).

The main well-formedness check that was intended to be run despite
unreachable code still is, that being the
`UserTypeAnnotation::TypeOf(..)` case. Before this PR, the other case
wasn't being checked at all.

It is possible to fix this ICE while still always checking
well-formedness for the `UserTypeAnnotation::Ty(..)` case but that
solution will ICE in unreachable code for that case, the diff for
that change [can be found here](0).

[0]: https://gist.github.com/davidtwco/f9751ffd9c0508f7251c0f17adc3af53
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs58
-rw-r--r--src/test/incremental/hashes/let_expressions.rs2
-rw-r--r--src/test/ui/issue-54943-1.rs15
-rw-r--r--src/test/ui/issue-54943-2.rs18
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr2
5 files changed, 79 insertions, 16 deletions
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 2c49dbd969d..d0ca050f0df 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -933,19 +933,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         for index in self.mir.user_type_annotations.indices() {
             let (span, _) = &self.mir.user_type_annotations[index];
             let type_annotation = self.instantiated_type_annotations[&index];
-            if let Err(terr) = self.fully_perform_op(
-                Locations::All(*span),
-                ConstraintCategory::Assignment,
-                self.param_env.and(type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
-                    type_annotation,
-                )),
-            ) {
-                span_mirbug!(
-                    self,
-                    type_annotation,
-                    "bad user type annotation: {:?}",
-                    terr,
-                );
+            match type_annotation {
+                // We can't check the well-formedness of a `UserTypeAnnotation::Ty` here, it will
+                // cause ICEs (see comment in `relate_type_and_user_type`).
+                UserTypeAnnotation::TypeOf(..) => {
+                    if let Err(terr) = self.fully_perform_op(
+                        Locations::All(*span),
+                        ConstraintCategory::Assignment,
+                        self.param_env.and(
+                            type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
+                                type_annotation,
+                            )
+                        ),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            type_annotation,
+                            "bad user type annotation: {:?}",
+                            terr,
+                        );
+                    }
+                },
+                _ => {},
             }
         }
     }
@@ -1079,7 +1088,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             a, v, user_ty, locations,
         );
 
-        match self.instantiated_type_annotations[&user_ty.base] {
+        let type_annotation = self.instantiated_type_annotations[&user_ty.base];
+        match type_annotation {
             UserTypeAnnotation::Ty(ty) => {
                 // The `TypeRelating` code assumes that "unresolved inference
                 // variables" appear in the "a" side, so flip `Contravariant`
@@ -1117,7 +1127,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 if let Ok(projected_ty) = curr_projected_ty {
                     let ty = projected_ty.to_ty(tcx);
                     self.relate_types(ty, v1, a, locations, category)?;
+
+                    // We'll get an ICE if we check for well-formedness of a
+                    // `UserTypeAnnotation::Ty` that hasn't had types related.
+                    //
+                    // Doing this without the types having been related will result in
+                    // `probe_ty_var` failing in the canonicalizer - in practice, this
+                    // results in three run-pass tests failing. You can work around that
+                    // by keeping an vec of projections instead of annotations and performing
+                    // the projections before storing into `instantiated_type_annotations`
+                    // but that still fails in dead code.
+                    self.fully_perform_op(
+                        locations,
+                        category,
+                        self.param_env.and(
+                            type_op::ascribe_user_type::AscribeUserTypeWellFormed::new(
+                                UserTypeAnnotation::Ty(ty),
+                            )
+                        ),
+                    )?;
                 }
+
             }
             UserTypeAnnotation::TypeOf(def_id, user_substs) => {
                 let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 3aa66527ca7..b6050f059c2 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,TypeckTables,MirValidated")]
+    except="HirBody,TypeckTables,MirValidated,MirOptimized")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_reference_type() {
     let _x: &mut u64;
diff --git a/src/test/ui/issue-54943-1.rs b/src/test/ui/issue-54943-1.rs
new file mode 100644
index 00000000000..7750e340361
--- /dev/null
+++ b/src/test/ui/issue-54943-1.rs
@@ -0,0 +1,15 @@
+#![feature(nll)]
+
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943.
+
+// compile-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/issue-54943-2.rs b/src/test/ui/issue-54943-2.rs
new file mode 100644
index 00000000000..f829c38c35d
--- /dev/null
+++ b/src/test/ui/issue-54943-2.rs
@@ -0,0 +1,18 @@
+#![feature(nll)]
+
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943. In particular, this test is in unreachable
+// code as the initial fix for this ICE only worked if the code was reachable.
+
+// compile-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    return;
+
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
index abda7ec5e07..539343a6829 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
@@ -21,7 +21,7 @@ LL | fn call1<'a>(x: &'a usize) {
 LL |     let z: &'a & usize = &(&y);
    |            -----------    ^^^^ borrowed value does not live long enough
    |            |
-   |            assignment requires that `y` is borrowed for `'a`
+   |            type annotation requires that `y` is borrowed for `'a`
 ...
 LL | }
    | - `y` dropped here while still borrowed