Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generalize impl trait to permit multiple lifetime bounds #61775

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
aab48c9
opaque_types/mod.rs: rustfmt
nikomatsakis Jun 28, 2019
2eb3fcc
introduce `constrain_regions` helper
nikomatsakis May 28, 2019
14e23a5
introduce an "in" constraint instead of error
nikomatsakis May 30, 2019
979f566
lexical_region_resolve: rustfmt
nikomatsakis May 31, 2019
dfcd1c6
make `dup_vec` optional
nikomatsakis May 31, 2019
c36205b
add some tests, currently ICE-ing
nikomatsakis Jun 1, 2019
02609b8
rename from "in constraint" to "pick constraint"
nikomatsakis Jun 3, 2019
f0eebcd
integrate pick constraints into lexical solver more completely
nikomatsakis Jun 3, 2019
d6ec0ae
enforce and report pick-constraint errors
nikomatsakis Jun 3, 2019
fd5f767
rename `QueryRegionConstraint` to `QueryOutlivesConstraint`
nikomatsakis Jun 3, 2019
7e66a96
introduce `QueryRegionConstraints` struct (no-op)
nikomatsakis Jun 3, 2019
09bba9b
introduce `QueryRegionConstraints` struct
nikomatsakis Jun 3, 2019
f673b24
rename `ConstraintIndex` to `OutlivesConstraintIndex`
nikomatsakis Jun 4, 2019
ec560e2
remove deref impl and add an index impl
nikomatsakis Jun 4, 2019
f933e09
pass a `&mut QueryRegionConstraints` not just outlives constraints
nikomatsakis Jun 5, 2019
ddc63ce
propagate the pick-constraints through queries
nikomatsakis Jun 5, 2019
6ead1c8
rename `ConstraintSet` to `OutlivesConstraintSet`
nikomatsakis Jun 5, 2019
3aad20d
[WIP] fix `Lift` impl for `Rc`
nikomatsakis Jun 24, 2019
330cb76
pass more than outlives constraints to constraint conversion
nikomatsakis Jun 5, 2019
d959669
implement PickConstraintSet type
nikomatsakis Jun 5, 2019
3b5a727
construct pick-constraints and give them to region inference
nikomatsakis Jun 5, 2019
ec48b4e
preliminary integration of "pick constraints" into nll solver
nikomatsakis Jun 7, 2019
cc581bf
remove old error and add an explanation
nikomatsakis Jun 10, 2019
07ee532
improve tests with migration mode, mir mode
nikomatsakis Jun 10, 2019
4e85665
implement the graph traits for SCC
nikomatsakis Jun 11, 2019
4c91bb9
introduce a `VecGraph` abstraction that cheaply stores graphs
nikomatsakis Jun 11, 2019
7fd0db7
add a `depth_first_search` helper function
nikomatsakis Jun 11, 2019
8d39bdd
integrate reverse graph and upper-bound computation
nikomatsakis Jun 12, 2019
b5fb906
fix tests and remove outdated stderr files
nikomatsakis Jun 12, 2019
2057136
update the async-fn-multiple-lifetimes test
nikomatsakis Jun 12, 2019
4de9960
add a FIXME related to the non-free-region case
nikomatsakis Jun 12, 2019
2ea6094
explain why pick-constraints can be an empty vector
nikomatsakis Jun 12, 2019
4831146
remove outdated TODO markers
nikomatsakis Jun 12, 2019
a18c779
pacify the mercilous tidy
nikomatsakis Jun 12, 2019
b170c0f
add a preliminary existential test; not really enough
nikomatsakis Jun 12, 2019
e9de08a
test with explicit existential type
nikomatsakis Jun 12, 2019
89a205b
add a `VecMap` data structure
nikomatsakis Jun 17, 2019
3e01c74
just create a binary search slice helper fn
nikomatsakis Jun 17, 2019
0b15a66
account for the pick-constraint edges when reporting errors
nikomatsakis Jun 17, 2019
adba6a8
address nits by mattewjasper
nikomatsakis Jun 17, 2019
5d44beb
bless test output
nikomatsakis Jun 17, 2019
fb2c997
fix silly bugs in binary_search_util test
nikomatsakis Jun 17, 2019
e6b6873
switch to Lrc
nikomatsakis Jun 18, 2019
e39f66a
implement Lift for Arc
nikomatsakis Jun 18, 2019
eca55b5
rename to "member constraints"
nikomatsakis Jun 18, 2019
134fc4a
rename `pick_constraints.rs` to `member_constraints.rs`
nikomatsakis Jun 18, 2019
cbc75c6
implement `TypeFoldable` for `Arc`
nikomatsakis Jun 18, 2019
74a6efb
feature-gate member constraints outside of async-await
nikomatsakis Jun 20, 2019
cf721c5
Update src/doc/unstable-book/src/language-features/member-constraints.md
nikomatsakis Jun 24, 2019
56ae0bf
Update src/librustc/infer/lexical_region_resolve/mod.rs
nikomatsakis Jun 24, 2019
d2772e8
explain why the code is the way it is
nikomatsakis Jun 24, 2019
b4a3753
various centril nits
nikomatsakis Jun 24, 2019
9588f7f
rewrite `dup_vec` to use `IndexVec` instead of `u32`
nikomatsakis Jun 24, 2019
6cab003
cleanup formatting of comment and add attribution
nikomatsakis Jun 24, 2019
6234aed
opaque_types: various nits
nikomatsakis Jun 24, 2019
0c8ebea
s/abstract_type_generics/opaque_type_generics/
nikomatsakis Jun 24, 2019
3ba1e19
opaque_types: more nits
nikomatsakis Jun 24, 2019
d9f4d2a
region_constraints: nits
nikomatsakis Jun 24, 2019
0dd074e
more centril nits
nikomatsakis Jun 24, 2019
9217909
pass a parameter to enable impl Trait instead of a vec
nikomatsakis Jun 24, 2019
076b0d0
more nits + typos
nikomatsakis Jun 24, 2019
5bd423a
introduce more tests covering `async fn` surface
nikomatsakis Jun 25, 2019
8f9a3af
Update src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
nikomatsakis Jun 29, 2019
1d93e3c
Update src/test/ui/async-await/multiple-lifetimes/fn-ptr.rs
nikomatsakis Jun 29, 2019
f130e9a
Update src/test/ui/async-await/multiple-lifetimes/elided.rs
nikomatsakis Jul 1, 2019
7f319a7
Update src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-f…
nikomatsakis Jul 1, 2019
0c2c241
address nits
nikomatsakis Jul 1, 2019
f7e00a5
fix ICE with delay-span-bug
nikomatsakis Jul 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/doc/unstable-book/src/language-features/member-constraints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# `member_constraints`

The tracking issue for this feature is: [#61977]

[#61977]: https://github.com/rust-lang/rust/issues/61977

------------------------

The `member_constraints` feature gate lets you use `impl Trait` syntax with
multiple unrelated lifetime parameters.

A simple example is:

```rust
#![feature(member_constraints)]

trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T {}

fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
(x, y)
}

fn main() { }
```

Without the `member_constraints` feature gate, the above example is an
error because both `'a` and `'b` appear in the impl Trait bounds, but
neither outlives the other.
33 changes: 31 additions & 2 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
use crate::infer::region_constraints::MemberConstraint;
use crate::mir::interpret::ConstValue;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_macros::HashStable;
Expand Down Expand Up @@ -189,11 +190,25 @@ pub enum CanonicalTyVarKind {
#[derive(Clone, Debug, HashStable)]
pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
pub value: R,
}

#[derive(Clone, Debug, Default, HashStable)]
pub struct QueryRegionConstraints<'tcx> {
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
pub member_constraints: Vec<MemberConstraint<'tcx>>,
}

impl QueryRegionConstraints<'_> {
/// Represents an empty (trivially true) set of region
/// constraints.
pub fn is_empty(&self) -> bool {
self.outlives.is_empty() && self.member_constraints.is_empty()
}
}

pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;

pub type CanonicalizedQueryResponse<'tcx, T> =
Expand Down Expand Up @@ -292,7 +307,8 @@ impl<'tcx, V> Canonical<'tcx, V> {
}
}

pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
pub type QueryOutlivesConstraint<'tcx> =
ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// Creates a substitution S for the canonical value with fresh
Expand Down Expand Up @@ -540,6 +556,19 @@ BraceStructLiftImpl! {
} where R: Lift<'tcx>
}

BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
outlives, member_constraints
}
}

BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
type Lifted = QueryRegionConstraints<'tcx>;
outlives, member_constraints
}
}

impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = Kind<'tcx>;

Expand Down
46 changes: 28 additions & 18 deletions src/librustc/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::arena::ArenaAllocatable;
use crate::infer::canonical::substitute::substitute_value;
use crate::infer::canonical::{
Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
OriginalQueryValues, QueryRegionConstraint, QueryResponse,
OriginalQueryValues, QueryRegionConstraints, QueryOutlivesConstraint, QueryResponse,
};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxtBuilder;
Expand Down Expand Up @@ -132,7 +132,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
{
self.canonicalize_response(&QueryResponse {
var_values: inference_vars,
region_constraints: vec![],
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Proven, // Ambiguities are OK!
value: answer,
})
Expand Down Expand Up @@ -174,7 +174,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {

let region_obligations = self.take_registered_region_obligations();
let region_constraints = self.with_region_constraints(|region_constraints| {
make_query_outlives(
make_query_region_constraints(
tcx,
region_obligations
.iter()
Expand Down Expand Up @@ -222,10 +222,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
mut obligations,
} = self.query_response_substitution(cause, param_env, original_values, query_response)?;

obligations.extend(self.query_region_constraints_into_obligations(
obligations.extend(self.query_outlives_constraints_into_obligations(
cause,
param_env,
&query_response.value.region_constraints,
&query_response.value.region_constraints.outlives,
&result_subst,
));

Expand All @@ -248,9 +248,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// that come out of these queries, which it wants to convert into
/// MIR-based constraints and solve. Therefore, it is most
/// convenient for the NLL Type Checker to **directly consume**
/// the `QueryRegionConstraint` values that arise from doing a
/// the `QueryOutlivesConstraint` values that arise from doing a
/// query. This is contrast to other parts of the compiler, which
/// would prefer for those `QueryRegionConstraint` to be converted
/// would prefer for those `QueryOutlivesConstraint` to be converted
/// into the older infcx-style constraints (e.g., calls to
/// `sub_regions` or `register_region_obligation`).
///
Expand All @@ -263,7 +263,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// result. If any errors arise, they are propagated back as an
/// `Err` result.
/// - In the case of a successful substitution, we will append
/// `QueryRegionConstraint` values onto the
/// `QueryOutlivesConstraint` values onto the
/// `output_query_region_constraints` vector for the solver to
/// use (if an error arises, some values may also be pushed, but
/// they should be ignored).
Expand All @@ -279,15 +279,15 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> InferResult<'tcx, R>
where
R: Debug + TypeFoldable<'tcx>,
{
let result_subst =
self.query_response_substitution_guess(cause, original_values, query_response);

// Compute `QueryRegionConstraint` values that unify each of
// Compute `QueryOutlivesConstraint` values that unify each of
// the original values `v_o` that was canonicalized into a
// variable...
let mut obligations = vec![];
Expand All @@ -306,8 +306,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
output_query_region_constraints
.outlives
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
output_query_region_constraints
.outlives
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
}
}
Expand All @@ -333,12 +335,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
}

// ...also include the other query region constraints from the query.
output_query_region_constraints.extend(
query_response.value.region_constraints.iter().filter_map(|r_c| {
output_query_region_constraints.outlives.extend(
query_response.value.region_constraints.outlives.iter().filter_map(|r_c| {
let r_c = substitute_value(self.tcx, &result_subst, r_c);

// Screen out `'a: 'a` cases -- we skip the binder here but
// only care the inner values to one another, so they are still at
// only compare the inner values to one another, so they are still at
// consistent binding levels.
let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
if k1 != r2.into() {
Expand All @@ -349,6 +351,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
})
);

// ...also include the query member constraints.
output_query_region_constraints.member_constraints.extend(
query_response.value.region_constraints.member_constraints.iter().map(|p_c| {
substitute_value(self.tcx, &result_subst, p_c)
})
);

let user_result: R =
query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);

Expand Down Expand Up @@ -560,11 +569,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {

/// Converts the region constraints resulting from a query into an
/// iterator of obligations.
fn query_region_constraints_into_obligations<'a>(
fn query_outlives_constraints_into_obligations<'a>(
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
result_subst: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
unsubstituted_region_constraints
Expand Down Expand Up @@ -645,15 +654,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {

/// Given the region obligations and constraints scraped from the infcx,
/// creates query region constraints.
pub fn make_query_outlives<'tcx>(
pub fn make_query_region_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> Vec<QueryRegionConstraint<'tcx>> {
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData {
constraints,
verifys,
givens,
member_constraints,
} = region_constraints;

assert!(verifys.is_empty());
Expand Down Expand Up @@ -684,5 +694,5 @@ pub fn make_query_outlives<'tcx>(
)
.collect();

outlives
QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
}
22 changes: 21 additions & 1 deletion src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use crate::infer::{self, SuppressRegionErrors};
use crate::hir;
use crate::hir::def_id::DefId;
use crate::hir::Node;
use crate::infer::opaque_types;
use crate::middle::region;
use crate::traits::{ObligationCause, ObligationCauseCode};
use crate::ty::error::TypeError;
Expand Down Expand Up @@ -375,6 +376,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
}

RegionResolutionError::MemberConstraintFailure {
opaque_type_def_id,
hidden_ty,
member_region,
span: _,
choice_regions: _,
} => {
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
opaque_types::unexpected_hidden_region_diagnostic(
self.tcx,
Some(region_scope_tree),
opaque_type_def_id,
hidden_ty,
member_region,
).emit();
}
}
}
}
Expand Down Expand Up @@ -411,7 +429,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
RegionResolutionError::GenericBoundFailure(..) => true,
RegionResolutionError::ConcreteFailure(..)
| RegionResolutionError::SubSupConflict(..) => false,
| RegionResolutionError::SubSupConflict(..)
| RegionResolutionError::MemberConstraintFailure { .. } => false,
};

let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
Expand All @@ -429,6 +448,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
});
errors
}
Expand Down
Loading