Skip to content

Commit 8785e34

Browse files
committed
Auto merge of #53580 - nikomatsakis:nll-issue-53568, r=pnkfelix
fix NLL ICEs Custom type-ops reuse some of the query machinery -- but while query results are canonicalized after they are constructed, custom type ops are not, and hence we have to resolve the type variables to avoid an ICE here. Also, use the type-op machinery for implied outlives bounds. Fixes #53568 Fixes #52992 Fixes #53680
2 parents b638d8c + a59584a commit 8785e34

File tree

8 files changed

+211
-27
lines changed

8 files changed

+211
-27
lines changed

src/librustc/infer/canonical/query_result.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,18 @@ use infer::canonical::{
2424
};
2525
use infer::region_constraints::{Constraint, RegionConstraintData};
2626
use infer::InferCtxtBuilder;
27-
use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
27+
use infer::{InferCtxt, InferOk, InferResult};
2828
use rustc_data_structures::indexed_vec::Idx;
2929
use rustc_data_structures::indexed_vec::IndexVec;
3030
use rustc_data_structures::sync::Lrc;
3131
use std::fmt::Debug;
32-
use syntax::ast;
3332
use syntax_pos::DUMMY_SP;
3433
use traits::query::{Fallible, NoSolution};
3534
use traits::{FulfillmentContext, TraitEngine};
3635
use traits::{Obligation, ObligationCause, PredicateObligation};
3736
use ty::fold::TypeFoldable;
3837
use ty::subst::{Kind, UnpackedKind};
39-
use ty::{self, CanonicalVar, Lift, TyCtxt};
38+
use ty::{self, CanonicalVar, Lift, Ty, TyCtxt};
4039

4140
impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
4241
/// The "main method" for a canonicalized trait query. Given the
@@ -157,7 +156,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
157156

158157
let region_obligations = self.take_registered_region_obligations();
159158
let region_constraints = self.with_region_constraints(|region_constraints| {
160-
make_query_outlives(tcx, region_obligations, region_constraints)
159+
make_query_outlives(
160+
tcx,
161+
region_obligations
162+
.iter()
163+
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
164+
region_constraints)
161165
});
162166

163167
let certainty = if ambig_errors.is_empty() {
@@ -567,7 +571,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
567571
/// creates query region constraints.
568572
pub fn make_query_outlives<'tcx>(
569573
tcx: TyCtxt<'_, '_, 'tcx>,
570-
region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
574+
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
571575
region_constraints: &RegionConstraintData<'tcx>,
572576
) -> Vec<QueryRegionConstraint<'tcx>> {
573577
let RegionConstraintData {
@@ -600,9 +604,8 @@ pub fn make_query_outlives<'tcx>(
600604
.collect();
601605

602606
outlives.extend(
603-
region_obligations
604-
.into_iter()
605-
.map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
607+
outlives_obligations
608+
.map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
606609
.map(ty::Binder::dummy), // no bound regions in the code above
607610
);
608611

src/librustc/traits/query/type_op/custom.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ fn scrape_region_constraints<'gcx, 'tcx, R>(
102102

103103
let region_constraint_data = infcx.take_and_reset_region_constraints();
104104

105-
let outlives =
106-
query_result::make_query_outlives(infcx.tcx, region_obligations, &region_constraint_data);
105+
let outlives = query_result::make_query_outlives(
106+
infcx.tcx,
107+
region_obligations
108+
.iter()
109+
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
110+
.map(|(ty, r)| (infcx.resolve_type_vars_if_possible(&ty), r)),
111+
&region_constraint_data,
112+
);
107113

108114
if outlives.is_empty() {
109115
Ok((value, None))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult};
12+
use traits::query::outlives_bounds::OutlivesBound;
13+
use traits::query::Fallible;
14+
use ty::{ParamEnvAnd, Ty, TyCtxt};
15+
16+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
17+
pub struct ImpliedOutlivesBounds<'tcx> {
18+
pub ty: Ty<'tcx>,
19+
}
20+
21+
impl<'tcx> ImpliedOutlivesBounds<'tcx> {
22+
pub fn new(ty: Ty<'tcx>) -> Self {
23+
ImpliedOutlivesBounds { ty }
24+
}
25+
}
26+
27+
impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<'tcx> {
28+
type QueryResult = Vec<OutlivesBound<'tcx>>;
29+
30+
fn try_fast_path(
31+
_tcx: TyCtxt<'_, 'gcx, 'tcx>,
32+
_key: &ParamEnvAnd<'tcx, Self>,
33+
) -> Option<Self::QueryResult> {
34+
None
35+
}
36+
37+
fn perform_query(
38+
tcx: TyCtxt<'_, 'gcx, 'tcx>,
39+
canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
40+
) -> Fallible<CanonicalizedQueryResult<'gcx, Self::QueryResult>> {
41+
// FIXME the query should take a `ImpliedOutlivesBounds`
42+
let Canonical {
43+
variables,
44+
value:
45+
ParamEnvAnd {
46+
param_env,
47+
value: ImpliedOutlivesBounds { ty },
48+
},
49+
} = canonicalized;
50+
let canonicalized = Canonical {
51+
variables,
52+
value: param_env.and(ty),
53+
};
54+
55+
tcx.implied_outlives_bounds(canonicalized)
56+
}
57+
58+
fn shrink_to_tcx_lifetime(
59+
v: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>,
60+
) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> {
61+
v
62+
}
63+
}
64+
65+
BraceStructTypeFoldableImpl! {
66+
impl<'tcx> TypeFoldable<'tcx> for ImpliedOutlivesBounds<'tcx> {
67+
ty,
68+
}
69+
}
70+
71+
BraceStructLiftImpl! {
72+
impl<'a, 'tcx> Lift<'tcx> for ImpliedOutlivesBounds<'a> {
73+
type Lifted = ImpliedOutlivesBounds<'tcx>;
74+
ty,
75+
}
76+
}
77+
78+
impl_stable_hash_for! {
79+
struct ImpliedOutlivesBounds<'tcx> { ty }
80+
}

src/librustc/traits/query/type_op/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use ty::{Lift, ParamEnvAnd, TyCtxt};
2121

2222
pub mod custom;
2323
pub mod eq;
24+
pub mod implied_outlives_bounds;
2425
pub mod normalize;
2526
pub mod outlives;
2627
pub mod prove_predicate;

src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use borrow_check::nll::type_check::constraint_conversion;
1414
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
1515
use borrow_check::nll::universal_regions::UniversalRegions;
1616
use borrow_check::nll::ToRegionVid;
17-
use rustc::hir::def_id::DefId;
17+
use rustc::infer::canonical::QueryRegionConstraint;
1818
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
1919
use rustc::infer::region_constraints::GenericKind;
2020
use rustc::infer::InferCtxt;
@@ -23,7 +23,6 @@ use rustc::traits::query::type_op::{self, TypeOp};
2323
use rustc::ty::{self, RegionVid, Ty};
2424
use rustc_data_structures::transitive_relation::TransitiveRelation;
2525
use std::rc::Rc;
26-
use syntax::ast;
2726

2827
#[derive(Debug)]
2928
crate struct UniversalRegionRelations<'tcx> {
@@ -67,19 +66,15 @@ crate struct CreateResult<'tcx> {
6766

6867
crate fn create(
6968
infcx: &InferCtxt<'_, '_, 'tcx>,
70-
mir_def_id: DefId,
7169
param_env: ty::ParamEnv<'tcx>,
7270
location_table: &LocationTable,
7371
implicit_region_bound: Option<ty::Region<'tcx>>,
7472
universal_regions: &Rc<UniversalRegions<'tcx>>,
7573
constraints: &mut MirTypeckRegionConstraints<'tcx>,
7674
all_facts: &mut Option<AllFacts>,
7775
) -> CreateResult<'tcx> {
78-
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
7976
UniversalRegionRelationsBuilder {
8077
infcx,
81-
mir_def_id,
82-
mir_node_id,
8378
param_env,
8479
implicit_region_bound,
8580
constraints,
@@ -212,8 +207,6 @@ impl UniversalRegionRelations<'tcx> {
212207

213208
struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
214209
infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
215-
mir_def_id: DefId,
216-
mir_node_id: ast::NodeId,
217210
param_env: ty::ParamEnv<'tcx>,
218211
location_table: &'this LocationTable,
219212
universal_regions: Rc<UniversalRegions<'tcx>>,
@@ -248,14 +241,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
248241
let constraint_sets: Vec<_> = unnormalized_input_output_tys
249242
.flat_map(|ty| {
250243
debug!("build: input_or_output={:?}", ty);
251-
let (ty, constraints) = self
244+
let (ty, constraints1) = self
252245
.param_env
253246
.and(type_op::normalize::Normalize::new(ty))
254247
.fully_perform(self.infcx)
255248
.unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
256-
self.add_implied_bounds(ty);
249+
let constraints2 = self.add_implied_bounds(ty);
257250
normalized_inputs_and_output.push(ty);
258-
constraints
251+
constraints1
252+
.into_iter()
253+
.chain(constraints2)
259254
})
260255
.collect();
261256

@@ -306,13 +301,15 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
306301
/// either the return type of the MIR or one of its arguments. At
307302
/// the same time, compute and add any implied bounds that come
308303
/// from this local.
309-
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) {
304+
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<Vec<QueryRegionConstraint<'tcx>>>> {
310305
debug!("add_implied_bounds(ty={:?})", ty);
311-
let span = self.infcx.tcx.def_span(self.mir_def_id);
312-
let bounds = self
313-
.infcx
314-
.implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span);
306+
let (bounds, constraints) =
307+
self.param_env
308+
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
309+
.fully_perform(self.infcx)
310+
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
315311
self.add_outlives_bounds(bounds);
312+
constraints
316313
}
317314

318315
/// Registers the `OutlivesBound` items from `outlives_bounds` in

src/librustc_mir/borrow_check/nll/type_check/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
135135
normalized_inputs_and_output,
136136
} = free_region_relations::create(
137137
infcx,
138-
mir_def_id,
139138
param_env,
140139
location_table,
141140
Some(implicit_region_bound),

src/test/ui/issue-52992.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Regression test for an NLL-related ICE (#52992) -- computing
12+
// implied bounds was causing outlives relations that were not
13+
// properly handled.
14+
//
15+
// compile-pass
16+
17+
#![feature(nll)]
18+
19+
fn main() {}
20+
21+
fn fail<'a>() -> Struct<'a, Generic<()>> {
22+
Struct(&Generic(()))
23+
}
24+
25+
struct Struct<'a, T>(&'a T) where
26+
T: Trait + 'a,
27+
T::AT: 'a; // only fails with this bound
28+
29+
struct Generic<T>(T);
30+
31+
trait Trait {
32+
type AT;
33+
}
34+
35+
impl<T> Trait for Generic<T> {
36+
type AT = T; // only fails with a generic AT
37+
}

src/test/ui/issue-53568.rs

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Regression test for an NLL-related ICE (#53568) -- we failed to
12+
// resolve inference variables in "custom type-ops".
13+
//
14+
// compile-pass
15+
16+
#![feature(nll)]
17+
#![allow(dead_code)]
18+
19+
trait Future {
20+
type Item;
21+
}
22+
23+
impl<F, T> Future for F
24+
where F: Fn() -> T
25+
{
26+
type Item = T;
27+
}
28+
29+
trait Connect {}
30+
31+
struct Connector<H> {
32+
handler: H,
33+
}
34+
35+
impl<H, T> Connect for Connector<H>
36+
where
37+
T: 'static,
38+
H: Future<Item = T>
39+
{
40+
}
41+
42+
struct Client<C> {
43+
connector: C,
44+
}
45+
46+
fn build<C>(_connector: C) -> Client<C> {
47+
unimplemented!()
48+
}
49+
50+
fn client<H>(handler: H) -> Client<impl Connect>
51+
where H: Fn() + Copy
52+
{
53+
let connector = Connector {
54+
handler,
55+
};
56+
let client = build(connector);
57+
client
58+
}
59+
60+
fn main() { }
61+

0 commit comments

Comments
 (0)