1
Fork 0

feature-gate member constraints outside of async-await

Minimizes risk.
This commit is contained in:
Niko Matsakis 2019-06-20 10:44:20 -04:00
parent cbc75c699c
commit 74a6efbf00
18 changed files with 147 additions and 7 deletions

View file

@ -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 { }
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.

View file

@ -10,6 +10,7 @@ use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
use crate::util::nodemap::DefIdMap;
use errors::DiagnosticBuilder;
use rustc::session::config::nightly_options;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use syntax_pos::Span;
@ -398,6 +399,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
abstract_type_generics,
opaque_defn,
def_id,
lr,
subst_arg,
);
}
}
@ -418,13 +421,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// related, we would generate a constraint `'r in ['a, 'b,
/// 'static]` for each region `'r` that appears in the hidden type
/// (i.e., it must be equal to `'a`, `'b`, or `'static`).
///
/// `conflict1` and `conflict2` are the two region bounds that we
/// detected which were unrelated. They are used for diagnostics.
fn generate_member_constraint(
&self,
concrete_ty: Ty<'tcx>,
abstract_type_generics: &ty::Generics,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) {
// For now, enforce a feature gate outside of async functions.
if self.member_constraint_feature_gate(
opaque_defn,
opaque_type_def_id,
conflict1,
conflict2,
) {
return;
}
// Create the set of choice regions: each region in the hidden
// type can be equal to any of the region parameters of the
// opaque type definition.
@ -453,6 +471,60 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
});
}
/// Member constraints are presently feature-gated except for
/// async-await. We expect to lift this once we've had a bit more
/// time.
fn member_constraint_feature_gate(
&self,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) -> bool {
// If we have `#![feature(member_constraints)]`, no problems.
if self.tcx.features().member_constraints {
return false;
}
let span = self.tcx.def_span(opaque_type_def_id);
// Otherwise, we allow for async-await but not otherwise.
let context_name = match opaque_defn.origin {
hir::ExistTyOrigin::ExistentialType => "existential type",
hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
hir::ExistTyOrigin::AsyncFn => {
// we permit
return false;
}
};
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
let mut err = self.tcx.sess.struct_span_err(span, &msg);
let conflict1_name = conflict1.to_string();
let conflict2_name = conflict2.to_string();
let label_owned;
let label = match (&*conflict1_name, &*conflict2_name) {
("'_", "'_") => "the elided lifetimes here do not outlive one another",
_ => {
label_owned = format!(
"neither `{}` nor `{}` outlives the other",
conflict1_name, conflict2_name,
);
&label_owned
}
};
err.span_label(span, label);
if nightly_options::is_nightly_build() {
help!(err,
"add #![feature(member_constraints)] to the crate attributes \
to enable");
}
err.emit();
true
}
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an abstract type

View file

@ -570,6 +570,9 @@ declare_features! (
// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
// Allows impl trait with multiple unrelated lifetimes
(active, member_constraints, "1.37.0", Some(61977), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------

View file

@ -389,6 +389,7 @@ symbols! {
match_beginning_vert,
match_default_bindings,
may_dangle,
member_constraints,
message,
meta,
min_const_fn,

View file

@ -0,0 +1,9 @@
trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T {}
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
//~^ ERROR ambiguous lifetime bound
(x, y)
}
fn main() { }

View file

@ -0,0 +1,10 @@
error: ambiguous lifetime bound in `impl Trait`
--> $DIR/feature-gate-member-constraints.rs:4:43
|
LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
|
= help: add #![feature(member_constraints)] to the crate attributes to enable
error: aborting due to previous error

View file

@ -1,5 +1,6 @@
// compile-flags:-Zborrowck=mir
#![feature(member_constraints)]
#![feature(existential_type)]
#[derive(Clone)]

View file

@ -1,5 +1,5 @@
error: lifetime may not live long enough
--> $DIR/error-handling.rs:12:56
--> $DIR/error-handling.rs:13:56
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`

View file

@ -3,6 +3,8 @@
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
#![feature(member_constraints)]
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}

View file

@ -3,6 +3,8 @@
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
#![feature(member_constraints)]
trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }

View file

@ -3,6 +3,7 @@
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
#![feature(member_constraints)]
#![feature(existential_type)]
trait Trait<'a, 'b> { }

View file

@ -3,6 +3,8 @@
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
#![feature(member_constraints)]
trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }

View file

@ -3,6 +3,8 @@
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
#![feature(member_constraints)]
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}

View file

@ -1,5 +1,7 @@
// edition:2018
#![feature(member_constraints)]
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}

View file

@ -1,11 +1,11 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ordinary-bounds-unrelated.rs:16:74
--> $DIR/ordinary-bounds-unrelated.rs:18:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 21:1
--> $DIR/ordinary-bounds-unrelated.rs:21:1
note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 23:1
--> $DIR/ordinary-bounds-unrelated.rs:23:1
|
LL | / {
LL | | // Hidden type `Ordinary<'0>` with constraints:

View file

@ -1,5 +1,7 @@
// edition:2018
#![feature(member_constraints)]
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}

View file

@ -1,11 +1,11 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ordinary-bounds-unsuited.rs:18:62
--> $DIR/ordinary-bounds-unsuited.rs:20:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 20:1
--> $DIR/ordinary-bounds-unsuited.rs:20:1
note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 22:1
--> $DIR/ordinary-bounds-unsuited.rs:22:1
|
LL | / {
LL | | // We return a value:

View file

@ -1,5 +1,7 @@
// run-pass
#![feature(member_constraints)]
use std::fmt::Debug;
trait MultiRegionTrait<'a, 'b> {}