Skip to content

Commit 74a6efb

Browse files
committed
feature-gate member constraints outside of async-await
Minimizes risk.
1 parent cbc75c6 commit 74a6efb

18 files changed

+147
-7
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# `member_constraints`
2+
3+
The tracking issue for this feature is: [#61977]
4+
5+
[#61977]: https://github.com/rust-lang/rust/issues/61977
6+
7+
------------------------
8+
9+
The `member_constraints` feature gate lets you use `impl Trait` syntax with
10+
multiple unrelated lifetime parameters.
11+
12+
A simple example is:
13+
14+
```rust
15+
#![feature(member_constraints)]
16+
17+
trait Trait { }
18+
impl<T> Trait<'_, '_> for T {}
19+
20+
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
21+
(x, y)
22+
}
23+
24+
fn main() { }
25+
```
26+
27+
Without the `member_constraints` feature gate, the above example is an
28+
error because both `'a` and `'b` appear in the impl Trait bounds, but
29+
neither outlives the other.

src/librustc/infer/opaque_types/mod.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
1010
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
1111
use crate::util::nodemap::DefIdMap;
1212
use errors::DiagnosticBuilder;
13+
use rustc::session::config::nightly_options;
1314
use rustc_data_structures::fx::FxHashMap;
1415
use rustc_data_structures::sync::Lrc;
1516
use syntax_pos::Span;
@@ -398,6 +399,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
398399
abstract_type_generics,
399400
opaque_defn,
400401
def_id,
402+
lr,
403+
subst_arg,
401404
);
402405
}
403406
}
@@ -418,13 +421,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
418421
/// related, we would generate a constraint `'r in ['a, 'b,
419422
/// 'static]` for each region `'r` that appears in the hidden type
420423
/// (i.e., it must be equal to `'a`, `'b`, or `'static`).
424+
///
425+
/// `conflict1` and `conflict2` are the two region bounds that we
426+
/// detected which were unrelated. They are used for diagnostics.
421427
fn generate_member_constraint(
422428
&self,
423429
concrete_ty: Ty<'tcx>,
424430
abstract_type_generics: &ty::Generics,
425431
opaque_defn: &OpaqueTypeDecl<'tcx>,
426432
opaque_type_def_id: DefId,
433+
conflict1: ty::Region<'tcx>,
434+
conflict2: ty::Region<'tcx>,
427435
) {
436+
// For now, enforce a feature gate outside of async functions.
437+
if self.member_constraint_feature_gate(
438+
opaque_defn,
439+
opaque_type_def_id,
440+
conflict1,
441+
conflict2,
442+
) {
443+
return;
444+
}
445+
428446
// Create the set of choice regions: each region in the hidden
429447
// type can be equal to any of the region parameters of the
430448
// opaque type definition.
@@ -453,6 +471,60 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
453471
});
454472
}
455473

474+
/// Member constraints are presently feature-gated except for
475+
/// async-await. We expect to lift this once we've had a bit more
476+
/// time.
477+
fn member_constraint_feature_gate(
478+
&self,
479+
opaque_defn: &OpaqueTypeDecl<'tcx>,
480+
opaque_type_def_id: DefId,
481+
conflict1: ty::Region<'tcx>,
482+
conflict2: ty::Region<'tcx>,
483+
) -> bool {
484+
// If we have `#![feature(member_constraints)]`, no problems.
485+
if self.tcx.features().member_constraints {
486+
return false;
487+
}
488+
489+
let span = self.tcx.def_span(opaque_type_def_id);
490+
491+
// Otherwise, we allow for async-await but not otherwise.
492+
let context_name = match opaque_defn.origin {
493+
hir::ExistTyOrigin::ExistentialType => "existential type",
494+
hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
495+
hir::ExistTyOrigin::AsyncFn => {
496+
// we permit
497+
return false;
498+
}
499+
};
500+
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
501+
let mut err = self.tcx.sess.struct_span_err(span, &msg);
502+
503+
let conflict1_name = conflict1.to_string();
504+
let conflict2_name = conflict2.to_string();
505+
let label_owned;
506+
let label = match (&*conflict1_name, &*conflict2_name) {
507+
("'_", "'_") => "the elided lifetimes here do not outlive one another",
508+
_ => {
509+
label_owned = format!(
510+
"neither `{}` nor `{}` outlives the other",
511+
conflict1_name, conflict2_name,
512+
);
513+
&label_owned
514+
}
515+
};
516+
err.span_label(span, label);
517+
518+
if nightly_options::is_nightly_build() {
519+
help!(err,
520+
"add #![feature(member_constraints)] to the crate attributes \
521+
to enable");
522+
}
523+
524+
err.emit();
525+
true
526+
}
527+
456528
/// Given the fully resolved, instantiated type for an opaque
457529
/// type, i.e., the value of an inference variable like C1 or C2
458530
/// (*), computes the "definition type" for an abstract type

src/libsyntax/feature_gate.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@ declare_features! (
570570
// Allows explicit discriminants on non-unit enum variants.
571571
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
572572

573+
// Allows impl trait with multiple unrelated lifetimes
574+
(active, member_constraints, "1.37.0", Some(61977), None),
575+
573576
// -------------------------------------------------------------------------
574577
// feature-group-end: actual feature gates
575578
// -------------------------------------------------------------------------

src/libsyntax_pos/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ symbols! {
389389
match_beginning_vert,
390390
match_default_bindings,
391391
may_dangle,
392+
member_constraints,
392393
message,
393394
meta,
394395
min_const_fn,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait Trait<'a, 'b> { }
2+
impl<T> Trait<'_, '_> for T {}
3+
4+
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
5+
//~^ ERROR ambiguous lifetime bound
6+
(x, y)
7+
}
8+
9+
fn main() { }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: ambiguous lifetime bound in `impl Trait`
2+
--> $DIR/feature-gate-member-constraints.rs:4:43
3+
|
4+
LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
5+
| ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
6+
|
7+
= help: add #![feature(member_constraints)] to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+

src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// compile-flags:-Zborrowck=mir
22

3+
#![feature(member_constraints)]
34
#![feature(existential_type)]
45

56
#[derive(Clone)]

src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/error-handling.rs:12:56
2+
--> $DIR/error-handling.rs:13:56
33
|
44
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
55
| -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`

src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// revisions: migrate mir
44
//[mir]compile-flags: -Z borrowck=mir
55

6+
#![feature(member_constraints)]
7+
68
trait Trait<'a, 'b> {}
79
impl<T> Trait<'_, '_> for T {}
810

src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// revisions: migrate mir
44
//[mir]compile-flags: -Z borrowck=mir
55

6+
#![feature(member_constraints)]
7+
68
trait Trait<'a, 'b> { }
79
impl<T> Trait<'_, '_> for T { }
810

0 commit comments

Comments
 (0)