From a59584a6ff381ad701e80723db743ed0771ddad8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Aug 2018 20:15:01 -0400 Subject: [PATCH] use `TypeOp` machinery for `outlives_bounds` Fixes #52992 --- .../query/type_op/implied_outlives_bounds.rs | 80 +++++++++++++++++++ src/librustc/traits/query/type_op/mod.rs | 1 + .../nll/type_check/free_region_relations.rs | 29 +++---- .../borrow_check/nll/type_check/mod.rs | 1 - src/test/ui/issue-52992.rs | 37 +++++++++ 5 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 src/librustc/traits/query/type_op/implied_outlives_bounds.rs create mode 100644 src/test/ui/issue-52992.rs 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 0000000000000..27534bc8c3cf7 --- /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 or the MIT license +// , 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>; + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + None + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + // 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 be5e2838963ee..2f57981e7e1fe 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 e4b1aacd34f71..e21c490622c08 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>, @@ -75,11 +73,8 @@ crate fn create( constraints: &mut MirTypeckRegionConstraints<'tcx>, all_facts: &mut Option, ) -> 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>, @@ -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>>> { 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 ab83cfe25b590..69b2cfea1bd0c 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 0000000000000..2ece0ee9feeaf --- /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 or the MIT license +// , 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); + +trait Trait { + type AT; +} + +impl Trait for Generic { + type AT = T; // only fails with a generic AT +}