about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-10-24 12:08:34 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-10-24 15:12:50 -0400
commit62f0fc51126795848fff540e9776ee331753344d (patch)
tree26c14b71735b6ead1b31fedd0badaeb79ff38d00
parent7c8887ccbf7104e98ead7539f3cfbd42332b5e4d (diff)
downloadrust-62f0fc51126795848fff540e9776ee331753344d.tar.gz
rust-62f0fc51126795848fff540e9776ee331753344d.zip
port the relate-types code from NLL type-check into a type-op
Add regression tests for #55219 and #55241

Also another test where a duplicate-like error appears to have been
suppressed; I'm not 100% sure why this output changes, though I could
imagine that some duplicate suppression is enabled by this PR.
-rw-r--r--src/librustc/infer/at.rs22
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs17
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs114
-rw-r--r--src/librustc_traits/type_op.rs152
-rw-r--r--src/test/ui/nll/user-annotations/issue-55219.rs20
-rw-r--r--src/test/ui/nll/user-annotations/issue-55241.rs28
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr19
7 files changed, 244 insertions, 128 deletions
diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs
index 89dbc76c8a6..0e4c94aaaf3 100644
--- a/src/librustc/infer/at.rs
+++ b/src/librustc/infer/at.rs
@@ -142,6 +142,28 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
         self.trace(expected, actual).eq(&expected, &actual)
     }
 
+    pub fn relate<T>(
+        self,
+        expected: T,
+        variance: ty::Variance,
+        actual: T,
+    ) -> InferResult<'tcx, ()>
+        where T: ToTrace<'tcx>
+    {
+        match variance {
+            ty::Variance::Covariant => self.sub(expected, actual),
+            ty::Variance::Invariant => self.eq(expected, actual),
+            ty::Variance::Contravariant => self.sup(expected, actual),
+
+            // We could make this make sense but it's not readily
+            // exposed and I don't feel like dealing with it. Note
+            // that bivariance in general does a bit more than just
+            // *nothing*, it checks that the types are the same
+            // "modulo variance" basically.
+            ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"),
+        }
+    }
+
     /// Compute the least-upper-bound, or mutual supertype, of two
     /// values. The order of the arguments doesn't matter, but since
     /// this can result in an error (e.g., if asked to compute LUB of
diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs
index 607cfa0ec7a..b3955b8f864 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -9,24 +9,27 @@
 // except according to those terms.
 
 use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
-use mir::UserTypeAnnotation;
 use traits::query::Fallible;
+use hir::def_id::DefId;
 use ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use ty::subst::UserSubsts;
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct AscribeUserType<'tcx> {
     pub mir_ty: Ty<'tcx>,
     pub variance: ty::Variance,
-    pub user_ty: UserTypeAnnotation<'tcx>,
+    pub def_id: DefId,
+    pub user_substs: UserSubsts<'tcx>,
 }
 
 impl<'tcx> AscribeUserType<'tcx> {
     pub fn new(
         mir_ty: Ty<'tcx>,
         variance: ty::Variance,
-        user_ty: UserTypeAnnotation<'tcx>,
+        def_id: DefId,
+        user_substs: UserSubsts<'tcx>,
     ) -> Self {
-        AscribeUserType { mir_ty, variance, user_ty }
+        AscribeUserType { mir_ty, variance, def_id, user_substs }
     }
 }
 
@@ -56,19 +59,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx>
 
 BraceStructTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> {
-        mir_ty, variance, user_ty
+        mir_ty, variance, def_id, user_substs
     }
 }
 
 BraceStructLiftImpl! {
     impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
         type Lifted = AscribeUserType<'tcx>;
-        mir_ty, variance, user_ty
+        mir_ty, variance, def_id, user_substs
     }
 }
 
 impl_stable_hash_for! {
     struct AscribeUserType<'tcx> {
-        mir_ty, variance, user_ty
+        mir_ty, variance, def_id, user_substs
     }
 }
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 ace012777c7..bbbe02fda6a 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, UserSelfTy, UserSubsts};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
@@ -975,127 +975,43 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        let tcx = self.tcx();
-
         debug!(
-            "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
-            a, v, user_ty, locations
+            "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})",
+            a, v, user_ty, locations,
         );
 
-        // The `TypeRelating` code assumes that "unresolved inference
-        // variables" appear in the "a" side, so flip `Contravariant`
-        // ambient variance to get the right relationship.
-        let v1 = ty::Contravariant.xform(v);
-
         match user_ty {
             UserTypeAnnotation::Ty(canonical_ty) => {
                 let (ty, _) = self.infcx
                     .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
 
-                self.relate_types(ty, v1, a, locations, category)?;
+                // The `TypeRelating` code assumes that "unresolved inference
+                // variables" appear in the "a" side, so flip `Contravariant`
+                // ambient variance to get the right relationship.
+                let v1 = ty::Contravariant.xform(v);
 
-                self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
+                self.relate_types(ty, v1, a, locations, category)?;
             }
             UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
                 let (
-                    UserSubsts {
-                        substs,
-                        user_self_ty,
-                    },
+                    user_substs,
                     _,
                 ) = self.infcx
                     .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
 
-                let ty = self.tcx().type_of(def_id);
-                let ty = ty.subst(tcx, substs);
-                debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
-                let ty = self.normalize(ty, locations);
-
-                self.relate_types(ty, v1, a, locations, category)?;
-
-                if let Some(UserSelfTy {
-                    impl_def_id,
-                    self_ty,
-                }) = user_self_ty
-                {
-                    let impl_self_ty = tcx.type_of(impl_def_id);
-                    let impl_self_ty = impl_self_ty.subst(tcx, &substs);
-                    let impl_self_ty = self.normalize(impl_self_ty, locations);
-
-                    // There may be type variables in `substs` and hence
-                    // in `impl_self_ty`, but they should all have been
-                    // resolved to some fixed value during the first call
-                    // to `relate`, above. Therefore, if we use
-                    // `resolve_type_vars_if_possible` we should get to
-                    // something without type variables. This is important
-                    // because the `b` type in `relate_with_variance`
-                    // below is not permitted to have inference variables.
-                    let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty);
-                    assert!(!impl_self_ty.has_infer_types());
-
-                    self.eq_types(self_ty, impl_self_ty, locations, category)?;
-
-                    self.prove_predicate(
-                        ty::Predicate::WellFormed(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,
+                self.fully_perform_op(
                     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);
+                    category,
+                    self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                        a, v, def_id, user_substs,
+                    )),
+                )?;
             }
         }
 
         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/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index bf4e5bda4eb..cf274a9c851 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -8,20 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::infer::at::ToTrace;
 use rustc::infer::canonical::{Canonical, QueryResponse};
 use rustc::infer::InferCtxt;
+use rustc::hir::def_id::DefId;
 use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
 use rustc::traits::query::type_op::eq::Eq;
 use rustc::traits::query::type_op::normalize::Normalize;
 use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
 use rustc::traits::query::type_op::subtype::Subtype;
 use rustc::traits::query::{Fallible, NoSolution};
-use rustc::traits::{FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine,
-                    TraitEngineExt};
+use rustc::traits::{
+    FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
+};
 use rustc::ty::query::Providers;
-use rustc::ty::{FnSig, Lift, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
+use rustc::ty::{
+    FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
+};
 use rustc_data_structures::sync::Lrc;
 use std::fmt;
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
 
 crate fn provide(p: &mut Providers) {
     *p = Providers {
@@ -43,12 +51,146 @@ fn type_op_ascribe_user_type<'tcx>(
 ) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
-            let (param_env, AscribeUserType { mir_ty, variance, user_ty }) = key.into_parts();
-            drop((infcx, fulfill_cx, param_env, mir_ty, variance, user_ty));
+            let (
+                param_env,
+                AscribeUserType {
+                    mir_ty,
+                    variance,
+                    def_id,
+                    user_substs,
+                },
+            ) = key.into_parts();
+
+            debug!(
+                "type_op_ascribe_user_type(\
+                 mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\
+                 )",
+                mir_ty, variance, def_id, user_substs,
+            );
+
+            let mut cx = AscribeUserTypeCx {
+                infcx,
+                param_env,
+                fulfill_cx,
+            };
+            cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?;
+
             Ok(())
         })
 }
 
+struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> {
+    infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+    param_env: ParamEnv<'tcx>,
+    fulfill_cx: &'me mut FulfillmentContext<'tcx>,
+}
+
+impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
+    fn normalize<T>(&mut self, value: T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.infcx
+            .partially_normalize_associated_types_in(
+                DUMMY_SP,
+                ast::CRATE_NODE_ID,
+                self.param_env,
+                &value,
+            )
+            .into_value_registering_obligations(self.infcx, self.fulfill_cx)
+    }
+
+    fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution>
+    where
+        T: ToTrace<'tcx>,
+    {
+        Ok(self.infcx
+            .at(&ObligationCause::dummy(), self.param_env)
+           .relate(a, variance, b)?
+           .into_value_registering_obligations(self.infcx, self.fulfill_cx))
+    }
+
+    fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
+        self.fulfill_cx.register_predicate_obligation(
+            self.infcx,
+            Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
+        );
+    }
+
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.infcx.tcx
+    }
+
+    fn subst<T>(&self, value: T, substs: &[Kind<'tcx>]) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        value.subst(self.tcx(), substs)
+    }
+
+    fn relate_mir_and_user_ty(
+        &mut self,
+        mir_ty: Ty<'tcx>,
+        variance: Variance,
+        def_id: DefId,
+        user_substs: UserSubsts<'tcx>,
+    ) -> Result<(), NoSolution> {
+        let UserSubsts {
+            substs,
+            user_self_ty,
+        } = user_substs;
+
+        let ty = self.tcx().type_of(def_id);
+        let ty = self.subst(ty, substs);
+        debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
+        let ty = self.normalize(ty);
+
+        self.relate(mir_ty, variance, ty)?;
+
+        if let Some(UserSelfTy {
+            impl_def_id,
+            self_ty,
+        }) = user_self_ty
+        {
+            let impl_self_ty = self.tcx().type_of(impl_def_id);
+            let impl_self_ty = self.subst(impl_self_ty, &substs);
+            let impl_self_ty = self.normalize(impl_self_ty);
+
+            self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
+
+            self.prove_predicate(Predicate::WellFormed(impl_self_ty));
+        }
+
+        // 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 = self.tcx()
+            .predicates_of(def_id)
+            .instantiate(self.tcx(), substs);
+        for instantiated_predicate in instantiated_predicates.predicates {
+            let instantiated_predicate = self.normalize(instantiated_predicate);
+            self.prove_predicate(instantiated_predicate);
+        }
+
+        // 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(Predicate::WellFormed(ty));
+
+        Ok(())
+    }
+}
+
 fn type_op_eq<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs
new file mode 100644
index 00000000000..7daa5a59b99
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-55219.rs
@@ -0,0 +1,20 @@
+// Regression test for #55219:
+//
+// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
+// known. This unbound inference variable was causing an ICE.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    const HASH_LEN: usize = 20;
+
+    fn stuff() {
+        let _ = Self::HASH_LEN;
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/issue-55241.rs b/src/test/ui/nll/user-annotations/issue-55241.rs
new file mode 100644
index 00000000000..e5600803df8
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-55241.rs
@@ -0,0 +1,28 @@
+// Regression test for #55241:
+//
+// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
+// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
+// value of `_`; solving that requires having normalized, so we can
+// test against `C: NodeCodec<H>` in the environment.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub trait Hasher {
+    type Out: Eq;
+}
+
+pub trait NodeCodec<H: Hasher> {
+    const HASHED_NULL_NODE: H::Out;
+}
+
+pub trait Trie<H: Hasher, C: NodeCodec<H>> {
+    /// Return the root of the trie.
+    fn root(&self) -> &H::Out;
+
+    /// Is the trie empty?
+    fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE }
+}
+
+fn main() { }
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 c6bd5b7fa0d..39f193c55f7 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
@@ -12,21 +12,6 @@ LL |     let z: &'a & usize = &(&y);
 LL | }
    | - temporary value is freed at the end of this statement
 
-error[E0597]: `y` does not live long enough
-  --> $DIR/regions-free-region-ordering-caller1.rs:19:27
-   |
-LL | fn call1<'a>(x: &'a usize) {
-   |          -- lifetime `'a` defined here
-...
-LL |     let z: &'a & usize = &(&y);
-   |            -----------    ^^^^ borrowed value does not live long enough
-   |            |
-   |            type annotation requires that `y` is borrowed for `'a`
-...
-LL | }
-   | - `y` dropped here while still borrowed
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors occurred: E0597, E0716.
-For more information about an error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0716`.