about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2019-06-20 10:44:20 -0400
committerNiko Matsakis <niko@alum.mit.edu>2019-07-02 12:25:22 -0400
commit74a6efbf00e2fff08afe623a0a01155b4bebd0a3 (patch)
treeb9df1ba746aff4561a2414e91f77d3a78f2ab48a /src
parentcbc75c699c1be9bf6c735351b7b07ab7d0569cdf (diff)
downloadrust-74a6efbf00e2fff08afe623a0a01155b4bebd0a3.tar.gz
rust-74a6efbf00e2fff08afe623a0a01155b4bebd0a3.zip
feature-gate member constraints outside of async-await
Minimizes risk.
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/member-constraints.md29
-rw-r--r--src/librustc/infer/opaque_types/mod.rs72
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/feature-gates/feature-gate-member-constraints.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-member-constraints.stderr10
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs1
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs1
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr6
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr6
-rw-r--r--src/test/ui/impl-trait/needs_least_region_or_bound.rs2
18 files changed, 147 insertions, 7 deletions
diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md
new file mode 100644
index 00000000000..71f2a10d092
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/member-constraints.md
@@ -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.
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 2e35aefa88a..9c2cc5815de 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -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
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index f97e9d43854..1223c069d65 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -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
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 266bd2a04a2..aee988d5148 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -389,6 +389,7 @@ symbols! {
         match_beginning_vert,
         match_default_bindings,
         may_dangle,
+        member_constraints,
         message,
         meta,
         min_const_fn,
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs
new file mode 100644
index 00000000000..293a93352e6
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-member-constraints.rs
@@ -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() { }
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr
new file mode 100644
index 00000000000..3745d5e1c59
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr
@@ -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
+
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
index 06122184634..61e858ee02d 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
@@ -1,5 +1,6 @@
 // compile-flags:-Zborrowck=mir
 
+#![feature(member_constraints)]
 #![feature(existential_type)]
 
 #[derive(Clone)]
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr
index 8355399506d..b59dfbe9f2a 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr
@@ -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`
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
index 53d2bc19089..2da3886bb55 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
@@ -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 {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
index 23981d92562..e2cb574fac0 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
@@ -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 { }
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs
index be249eeb9ea..a1ec89e8fbd 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-existential.rs
@@ -3,6 +3,7 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
+#![feature(member_constraints)]
 #![feature(existential_type)]
 
 trait Trait<'a, 'b> { }
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
index 0d04980d37a..21979b00179 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
@@ -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 { }
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
index 6555bacba67..0dfc118d78c 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
@@ -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 {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
index 3a97624647e..db1641b0140 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
@@ -1,5 +1,7 @@
 // edition:2018
 
+#![feature(member_constraints)]
+
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index c807048ce54..cd2d46ac182 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -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:
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
index 85c478d8d31..8f85b444d08 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
@@ -1,5 +1,7 @@
 // edition:2018
 
+#![feature(member_constraints)]
+
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 6687c40f957..59ce93fa78b 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -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:
diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
index 8475122cfae..52475f65a83 100644
--- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(member_constraints)]
+
 use std::fmt::Debug;
 
 trait MultiRegionTrait<'a, 'b> {}