about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/canonical/query_result.rs19
-rw-r--r--src/librustc/traits/query/type_op/custom.rs10
-rw-r--r--src/librustc/traits/query/type_op/implied_outlives_bounds.rs80
-rw-r--r--src/librustc/traits/query/type_op/mod.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs29
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs1
-rw-r--r--src/test/ui/issue-52992.rs37
-rw-r--r--src/test/ui/issue-53568.rs61
8 files changed, 211 insertions, 27 deletions
diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs
index 341089d8a81..65d42c0888d 100644
--- a/src/librustc/infer/canonical/query_result.rs
+++ b/src/librustc/infer/canonical/query_result.rs
@@ -24,19 +24,18 @@ use infer::canonical::{
 };
 use infer::region_constraints::{Constraint, RegionConstraintData};
 use infer::InferCtxtBuilder;
-use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
+use infer::{InferCtxt, InferOk, InferResult};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::sync::Lrc;
 use std::fmt::Debug;
-use syntax::ast;
 use syntax_pos::DUMMY_SP;
 use traits::query::{Fallible, NoSolution};
 use traits::{FulfillmentContext, TraitEngine};
 use traits::{Obligation, ObligationCause, PredicateObligation};
 use ty::fold::TypeFoldable;
 use ty::subst::{Kind, UnpackedKind};
-use ty::{self, CanonicalVar, Lift, TyCtxt};
+use ty::{self, CanonicalVar, Lift, Ty, TyCtxt};
 
 impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
     /// The "main method" for a canonicalized trait query. Given the
@@ -157,7 +156,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 
         let region_obligations = self.take_registered_region_obligations();
         let region_constraints = self.with_region_constraints(|region_constraints| {
-            make_query_outlives(tcx, region_obligations, region_constraints)
+            make_query_outlives(
+                tcx,
+                region_obligations
+                    .iter()
+                    .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
+                region_constraints)
         });
 
         let certainty = if ambig_errors.is_empty() {
@@ -567,7 +571,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 /// creates query region constraints.
 pub fn make_query_outlives<'tcx>(
     tcx: TyCtxt<'_, '_, 'tcx>,
-    region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
+    outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
     region_constraints: &RegionConstraintData<'tcx>,
 ) -> Vec<QueryRegionConstraint<'tcx>> {
     let RegionConstraintData {
@@ -600,9 +604,8 @@ pub fn make_query_outlives<'tcx>(
             .collect();
 
     outlives.extend(
-        region_obligations
-            .into_iter()
-            .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
+        outlives_obligations
+            .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
             .map(ty::Binder::dummy), // no bound regions in the code above
     );
 
diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs
index 737388ad411..6a5ef75a660 100644
--- a/src/librustc/traits/query/type_op/custom.rs
+++ b/src/librustc/traits/query/type_op/custom.rs
@@ -102,8 +102,14 @@ fn scrape_region_constraints<'gcx, 'tcx, R>(
 
     let region_constraint_data = infcx.take_and_reset_region_constraints();
 
-    let outlives =
-        query_result::make_query_outlives(infcx.tcx, region_obligations, &region_constraint_data);
+    let outlives = query_result::make_query_outlives(
+        infcx.tcx,
+        region_obligations
+            .iter()
+            .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
+            .map(|(ty, r)| (infcx.resolve_type_vars_if_possible(&ty), r)),
+        &region_constraint_data,
+    );
 
     if outlives.is_empty() {
         Ok((value, None))
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
index 00000000000..27534bc8c3c
--- /dev/null
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -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 }
+}
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 3b16dab22f2..8e4236d1754 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -21,6 +21,7 @@ use ty::{Lift, ParamEnvAnd, TyCtxt};
 
 pub mod custom;
 pub mod eq;
+pub mod implied_outlives_bounds;
 pub mod normalize;
 pub mod outlives;
 pub mod prove_predicate;
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
index e4b1aacd34f..e21c490622c 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
@@ -14,7 +14,7 @@ use borrow_check::nll::type_check::constraint_conversion;
 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::traits::query::type_op::{self, TypeOp};
 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 struct CreateResult<'tcx> {
 
 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>>,
@@ -75,11 +73,8 @@ crate fn create(
     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 @@ impl UniversalRegionRelations<'tcx> {
 
 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
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 5c14e552cfd..27417466c68 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -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
index 00000000000..2ece0ee9fee
--- /dev/null
+++ b/src/test/ui/issue-52992.rs
@@ -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
+}
diff --git a/src/test/ui/issue-53568.rs b/src/test/ui/issue-53568.rs
new file mode 100644
index 00000000000..6b479f75172
--- /dev/null
+++ b/src/test/ui/issue-53568.rs
@@ -0,0 +1,61 @@
+// 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 (#53568) -- we failed to
+// resolve inference variables in "custom type-ops".
+//
+// compile-pass
+
+#![feature(nll)]
+#![allow(dead_code)]
+
+trait Future {
+    type Item;
+}
+
+impl<F, T> Future for F
+where F: Fn() -> T
+{
+    type Item = T;
+}
+
+trait Connect {}
+
+struct Connector<H> {
+    handler: H,
+}
+
+impl<H, T> Connect for Connector<H>
+where
+    T: 'static,
+    H: Future<Item = T>
+{
+}
+
+struct Client<C> {
+    connector: C,
+}
+
+fn build<C>(_connector: C) -> Client<C> {
+    unimplemented!()
+}
+
+fn client<H>(handler: H) -> Client<impl Connect>
+where H: Fn() + Copy
+{
+    let connector = Connector {
+        handler,
+    };
+    let client = build(connector);
+    client
+}
+
+fn main() { }
+