]> git.lizzy.rs Git - rust.git/commitdiff
use `TypeOp` machinery for `outlives_bounds`
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 22 Aug 2018 00:15:01 +0000 (20:15 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Thu, 23 Aug 2018 11:38:47 +0000 (07:38 -0400)
Fixes #52992

src/librustc/traits/query/type_op/implied_outlives_bounds.rs [new file with mode: 0644]
src/librustc/traits/query/type_op/mod.rs
src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/test/ui/issue-52992.rs [new file with mode: 0644]

diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
new file mode 100644 (file)
index 0000000..27534bc
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
+use traits::query::outlives_bounds::OutlivesBound;
+use traits::query::Fallible;
+use ty::{ParamEnvAnd, Ty, TyCtxt};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ImpliedOutlivesBounds<'tcx> {
+    pub ty: Ty<'tcx>,
+}
+
+impl<'tcx> ImpliedOutlivesBounds<'tcx> {
+    pub fn new(ty: Ty<'tcx>) -> Self {
+        ImpliedOutlivesBounds { ty }
+    }
+}
+
+impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<'tcx> {
+    type QueryResult = Vec<OutlivesBound<'tcx>>;
+
+    fn try_fast_path(
+        _tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        _key: &ParamEnvAnd<'tcx, Self>,
+    ) -> Option<Self::QueryResult> {
+        None
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
+        // FIXME the query should take a `ImpliedOutlivesBounds`
+        let Canonical {
+            variables,
+            value:
+                ParamEnvAnd {
+                    param_env,
+                    value: ImpliedOutlivesBounds { ty },
+                },
+        } = canonicalized;
+        let canonicalized = Canonical {
+            variables,
+            value: param_env.and(ty),
+        };
+
+        tcx.implied_outlives_bounds(canonicalized)
+    }
+
+    fn shrink_to_tcx_lifetime(
+        v: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
+    ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> {
+        v
+    }
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for ImpliedOutlivesBounds<'tcx> {
+        ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for ImpliedOutlivesBounds<'a> {
+        type Lifted = ImpliedOutlivesBounds<'tcx>;
+        ty,
+    }
+}
+
+impl_stable_hash_for! {
+    struct ImpliedOutlivesBounds<'tcx> { ty }
+}
index be5e2838963ee2c906cd448b8f245ef8a8714a85..2f57981e7e1fefe2f96a626a9e85a9f5d167736e 100644 (file)
@@ -21,6 +21,7 @@
 
 pub mod custom;
 pub mod eq;
+pub mod implied_outlives_bounds;
 pub mod normalize;
 pub mod outlives;
 pub mod prove_predicate;
index e4b1aacd34f71fad8306bf6e1efa98696d147a66..e21c490622c089638b71eab8e2d63abb14ce4744 100644 (file)
@@ -14,7 +14,7 @@
 use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
 use borrow_check::nll::universal_regions::UniversalRegions;
 use borrow_check::nll::ToRegionVid;
-use rustc::hir::def_id::DefId;
+use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 use rustc::infer::region_constraints::GenericKind;
 use rustc::infer::InferCtxt;
@@ -23,7 +23,6 @@
 use rustc::ty::{self, RegionVid, Ty};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use std::rc::Rc;
-use syntax::ast;
 
 #[derive(Debug)]
 crate struct UniversalRegionRelations<'tcx> {
@@ -67,7 +66,6 @@
 
 crate fn create(
     infcx: &InferCtxt<'_, '_, 'tcx>,
-    mir_def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     location_table: &LocationTable,
     implicit_region_bound: Option<ty::Region<'tcx>>,
     constraints: &mut MirTypeckRegionConstraints<'tcx>,
     all_facts: &mut Option<AllFacts>,
 ) -> CreateResult<'tcx> {
-    let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
     UniversalRegionRelationsBuilder {
         infcx,
-        mir_def_id,
-        mir_node_id,
         param_env,
         implicit_region_bound,
         constraints,
@@ -212,8 +207,6 @@ fn non_local_bound(
 
 struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
     infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
-    mir_def_id: DefId,
-    mir_node_id: ast::NodeId,
     param_env: ty::ParamEnv<'tcx>,
     location_table: &'this LocationTable,
     universal_regions: Rc<UniversalRegions<'tcx>>,
@@ -248,14 +241,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                let (ty, constraints) = self
+                let (ty, constraints1) = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx)
                     .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
-                self.add_implied_bounds(ty);
+                let constraints2 = self.add_implied_bounds(ty);
                 normalized_inputs_and_output.push(ty);
-                constraints
+                constraints1
+                    .into_iter()
+                    .chain(constraints2)
             })
             .collect();
 
@@ -306,13 +301,15 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
     /// from this local.
-    fn add_implied_bounds(&mut self, ty: Ty<'tcx>) {
+    fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<Vec<QueryRegionConstraint<'tcx>>>> {
         debug!("add_implied_bounds(ty={:?})", ty);
-        let span = self.infcx.tcx.def_span(self.mir_def_id);
-        let bounds = self
-            .infcx
-            .implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span);
+        let (bounds, constraints) =
+            self.param_env
+            .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
+            .fully_perform(self.infcx)
+            .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
         self.add_outlives_bounds(bounds);
+        constraints
     }
 
     /// Registers the `OutlivesBound` items from `outlives_bounds` in
index ab83cfe25b590b92a1f9c7b42566905be70e5015..69b2cfea1bd0c471df380e0d268fcdd53fa50b69 100644 (file)
@@ -135,7 +135,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         normalized_inputs_and_output,
     } = free_region_relations::create(
         infcx,
-        mir_def_id,
         param_env,
         location_table,
         Some(implicit_region_bound),
diff --git a/src/test/ui/issue-52992.rs b/src/test/ui/issue-52992.rs
new file mode 100644 (file)
index 0000000..2ece0ee
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for an NLL-related ICE (#52992) -- computing
+// implied bounds was causing outlives relations that were not
+// properly handled.
+//
+// compile-pass
+
+#![feature(nll)]
+
+fn main() {}
+
+fn fail<'a>() -> Struct<'a, Generic<()>> {
+    Struct(&Generic(()))
+}
+
+struct Struct<'a, T>(&'a T) where
+    T: Trait + 'a,
+    T::AT: 'a; // only fails with this bound
+
+struct Generic<T>(T);
+
+trait Trait {
+    type AT;
+}
+
+impl<T> Trait for Generic<T> {
+    type AT = T; // only fails with a generic AT
+}