about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-10-17 11:10:08 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-10-19 09:34:27 -0400
commitbfb1d959c3cc64d54d1a1f3d586d90b6ce0d5357 (patch)
tree4c0a50fb6181e5a1f0a06e8170e2106cb6bdd3e0
parent121f3c8d19c3549ab0b51a14034ffb8b097faf42 (diff)
downloadrust-bfb1d959c3cc64d54d1a1f3d586d90b6ce0d5357.tar.gz
rust-bfb1d959c3cc64d54d1a1f3d586d90b6ce0d5357.zip
normalize and prove predicates
Also include a test that was not working previously.
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs51
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs16
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr10
3 files changed, 76 insertions, 1 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 d64643430c9..6783083c958 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts, UserSelfTy};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
@@ -1034,6 +1034,29 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     self.eq_types(self_ty, impl_self_ty, locations, category)?;
                 }
 
+                // Prove the predicates coming along with `def_id`.
+                //
+                // Also, normalize the `instantiated_predicates`
+                // because otherwise we wind up with duplicate "type
+                // outlives" error messages.
+                let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+                let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates);
+                self.normalize_and_prove_instantiated_predicates(
+                    instantiated_predicates,
+                    locations,
+                );
+
+                // In addition to proving the predicates, we have to
+                // prove that `ty` is well-formed -- this is because
+                // the WF of `ty` is predicated on the substs being
+                // well-formed, and we haven't proven *that*. We don't
+                // want to prove the WF of types from  `substs` directly because they
+                // haven't been normalized.
+                //
+                // FIXME(nmatsakis): Well, perhaps we should normalize
+                // them?  This would only be relevant if some input
+                // type were ill-formed but did not appear in `ty`,
+                // which...could happen with normalization...
                 self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
             }
         }
@@ -1041,6 +1064,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         Ok(())
     }
 
+    /// Replace all free regions in `value` with their NLL `RegionVid`
+    /// equivalents; if not in NLL, does nothing. This is never
+    /// particularly necessary -- we'll do it lazilly as we process
+    /// the value anyway -- but in some specific cases it is useful to
+    /// normalize so we can suppress duplicate error messages.
+    fn fold_to_region_vid<T>(
+        &self,
+        value: T
+    ) -> T
+    where T: TypeFoldable<'tcx>
+    {
+        if let Some(borrowck_context) = &self.borrowck_context {
+            self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
+                if r.has_free_regions() {
+                    self.tcx().mk_region(ty::RegionKind::ReVar(
+                        borrowck_context.universal_regions.to_region_vid(r),
+                    ))
+                } else {
+                    r
+                }
+            })
+        } else {
+            value
+        }
+    }
+
     fn eq_opaque_type_and_type(
         &mut self,
         revealed_ty: Ty<'tcx>,
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
new file mode 100644
index 00000000000..f83ae2438e6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
@@ -0,0 +1,16 @@
+#![feature(nll)]
+
+trait Foo<'a> {
+    const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+    T::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
new file mode 100644
index 00000000000..b373cebacb0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-trait-item-3.rs:12:5
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     T::C //~ ERROR
+   |     ^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+