Skip to content

Commit

Permalink
use TypeOp machinery for outlives_bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis committed Aug 23, 2018
1 parent 89574a6 commit a59584a
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 17 deletions.
80 changes: 80 additions & 0 deletions src/librustc/traits/query/type_op/implied_outlives_bounds.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
1 change: 1 addition & 0 deletions src/librustc/traits/query/type_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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> {
Expand Down Expand Up @@ -67,19 +66,15 @@ 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>>,
universal_regions: &Rc<UniversalRegions<'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,
Expand Down Expand Up @@ -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>>,
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
37 changes: 37 additions & 0 deletions src/test/ui/issue-52992.rs
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit a59584a

Please sign in to comment.