about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-02-01 17:28:46 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-02-02 15:40:12 +0000
commit7f608eb9edb38ff271ff5be50dbbbb424cbf348f (patch)
tree012aa765a63266fb522e081eb5c4e62fb7842b2e
parentbae04fb3ded72c71a660d34749d83d2752580052 (diff)
downloadrust-7f608eb9edb38ff271ff5be50dbbbb424cbf348f.tar.gz
rust-7f608eb9edb38ff271ff5be50dbbbb424cbf348f.zip
Prevent two opaque types in their defining scopes from being defined via the other
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs104
-rw-r--r--src/test/ui/impl-trait/example-calendar.rs3
-rw-r--r--src/test/ui/impl-trait/example-calendar.stderr19
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.rs4
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.stderr19
-rw-r--r--src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr39
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other.rs3
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other.stderr19
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other2.rs2
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other2.stderr15
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other3.rs3
-rw-r--r--src/test/ui/impl-trait/two_tait_defining_each_other3.stderr19
-rw-r--r--src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr19
14 files changed, 216 insertions, 56 deletions
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index e704ac6dc78..35104c71bfc 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -80,47 +80,69 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
         if self.defining_use_anchor.is_some() {
             let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
-                ty::Opaque(def_id, substs) => Some(self.register_hidden_type(
-                    OpaqueTypeKey { def_id, substs },
-                    cause.clone(),
-                    param_env,
-                    b,
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    self.opaque_type_origin(def_id, cause.span)?,
-                )),
+                ty::Opaque(def_id, substs) => {
+                    if let ty::Opaque(did2, _) = *b.kind() {
+                        if self.opaque_type_origin(did2, cause.span).is_some() {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    cause.span,
+                                    "opaque type's hidden type cannot be another opaque type from the same scope",
+                                )
+                                .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
+                                .span_note(
+                                    self.tcx.def_span(def_id),
+                                    "opaque type whose hidden type is being assigned",
+                                )
+                                .span_note(
+                                    self.tcx.def_span(did2),
+                                    "opaque type being used as hidden type",
+                                )
+                                .emit();
+                        }
+                    }
+                    Some(self.register_hidden_type(
+                        OpaqueTypeKey { def_id, substs },
+                        cause.clone(),
+                        param_env,
+                        b,
+                        // Check that this is `impl Trait` type is
+                        // declared by `parent_def_id` -- i.e., one whose
+                        // value we are inferring.  At present, this is
+                        // always true during the first phase of
+                        // type-check, but not always true later on during
+                        // NLL. Once we support named opaque types more fully,
+                        // this same scenario will be able to arise during all phases.
+                        //
+                        // Here is an example using type alias `impl Trait`
+                        // that indicates the distinction we are checking for:
+                        //
+                        // ```rust
+                        // mod a {
+                        //   pub type Foo = impl Iterator;
+                        //   pub fn make_foo() -> Foo { .. }
+                        // }
+                        //
+                        // mod b {
+                        //   fn foo() -> a::Foo { a::make_foo() }
+                        // }
+                        // ```
+                        //
+                        // Here, the return type of `foo` references an
+                        // `Opaque` indeed, but not one whose value is
+                        // presently being inferred. You can get into a
+                        // similar situation with closure return types
+                        // today:
+                        //
+                        // ```rust
+                        // fn foo() -> impl Iterator { .. }
+                        // fn bar() {
+                        //     let x = || foo(); // returns the Opaque assoc with `foo`
+                        // }
+                        // ```
+                        self.opaque_type_origin(def_id, cause.span)?,
+                    ))
+                }
                 _ => None,
             };
             if let Some(res) = process(a, b) {
diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs
index 45dcb74a6e0..26618eec1d7 100644
--- a/src/test/ui/impl-trait/example-calendar.rs
+++ b/src/test/ui/impl-trait/example-calendar.rs
@@ -1,4 +1,3 @@
-// run-pass
 // ignore-compare-mode-chalk
 
 #![feature(fn_traits,
@@ -590,7 +589,7 @@ fn test_format_month() {
 fn format_months(it: impl Iterator<Item = impl DateIterator>)
                 -> impl Iterator<Item=impl Iterator<Item=String>>
 {
-    it.map(format_month)
+    it.map(format_month) //~ ERROR opaque type's hidden type cannot be another opaque type
 }
 
 /// Takes an iterator of iterators of strings; the sub-iterators are consumed
diff --git a/src/test/ui/impl-trait/example-calendar.stderr b/src/test/ui/impl-trait/example-calendar.stderr
new file mode 100644
index 00000000000..3894285947f
--- /dev/null
+++ b/src/test/ui/impl-trait/example-calendar.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/example-calendar.rs:592:5
+   |
+LL |     it.map(format_month)
+   |     ^^^^^^^^^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/example-calendar.rs:560:43
+   |
+LL | fn format_month(it: impl DateIterator) -> impl Iterator<Item=String> {
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/example-calendar.rs:590:39
+   |
+LL |                 -> impl Iterator<Item=impl Iterator<Item=String>>
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs
index 42e5436390c..8169cfafac7 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.rs
+++ b/src/test/ui/impl-trait/issues/issue-70877.rs
@@ -1,7 +1,5 @@
 #![feature(type_alias_impl_trait)]
 
-// check-pass
-
 type FooArg<'a> = &'a dyn ToString;
 type FooRet = impl std::fmt::Debug;
 
@@ -30,7 +28,7 @@ fn ham() -> Foo {
 fn oof() -> impl std::fmt::Debug {
     let mut bar = ham();
     let func = bar.next().unwrap();
-    return func(&"oof");
+    return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
 }
 
 fn main() {
diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr
new file mode 100644
index 00000000000..8813bff3c35
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-70877.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/issue-70877.rs:31:12
+   |
+LL |     return func(&"oof");
+   |            ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/issue-70877.rs:28:13
+   |
+LL | fn oof() -> impl std::fmt::Debug {
+   |             ^^^^^^^^^^^^^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/issue-70877.rs:4:15
+   |
+LL | type FooRet = impl std::fmt::Debug;
+   |               ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
new file mode 100644
index 00000000000..86323add779
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
@@ -0,0 +1,39 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-88236-2.rs:17:5
+   |
+LL |     &()
+   |     ^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-88236-2.rs:17:5
+   |
+LL |     &()
+   |     ^^^
+
+error: lifetime may not live long enough
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                  -- lifetime `'b` defined here
+LL |     x
+   |     ^ returning this value requires that `'b` must outlive `'static`
+   |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
+   |                                                                                  ++++
+
+error: higher-ranked subtype error
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL |     x
+   |     ^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-88236-2.rs:20:5
+   |
+LL |     x
+   |     ^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other.rs b/src/test/ui/impl-trait/two_tait_defining_each_other.rs
index eb8d24832eb..6eb2a11b22c 100644
--- a/src/test/ui/impl-trait/two_tait_defining_each_other.rs
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other.rs
@@ -1,7 +1,5 @@
 #![feature(type_alias_impl_trait)]
 
-// check-pass
-
 type A = impl Foo;
 type B = impl Foo;
 
@@ -12,6 +10,7 @@ fn muh(x: A) -> B {
         return Bar; // B's hidden type is Bar
     }
     x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+    //~^ ERROR opaque type's hidden type cannot be another opaque type
 }
 
 struct Bar;
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other.stderr
new file mode 100644
index 00000000000..1a42ac525a6
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other.rs:12:5
+   |
+LL |     x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
+   |     ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/two_tait_defining_each_other.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other2.rs b/src/test/ui/impl-trait/two_tait_defining_each_other2.rs
index 295e2375428..3b16d0f5e04 100644
--- a/src/test/ui/impl-trait/two_tait_defining_each_other2.rs
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other2.rs
@@ -1,13 +1,13 @@
 #![feature(type_alias_impl_trait)]
 
 type A = impl Foo;
-//~^ ERROR unconstrained opaque type
 type B = impl Foo;
 
 trait Foo {}
 
 fn muh(x: A) -> B {
     x // B's hidden type is A (opaquely)
+    //~^ ERROR opaque type's hidden type cannot be another opaque type
 }
 
 struct Bar;
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr
index e48a5724a7f..ef2089a6c5b 100644
--- a/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other2.stderr
@@ -1,10 +1,19 @@
-error: unconstrained opaque type
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other2.rs:9:5
+   |
+LL |     x // B's hidden type is A (opaquely)
+   |     ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other2.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
   --> $DIR/two_tait_defining_each_other2.rs:3:10
    |
 LL | type A = impl Foo;
    |          ^^^^^^^^
-   |
-   = note: `A` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other3.rs b/src/test/ui/impl-trait/two_tait_defining_each_other3.rs
index c289b43c425..37f8ae1b84b 100644
--- a/src/test/ui/impl-trait/two_tait_defining_each_other3.rs
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other3.rs
@@ -1,7 +1,5 @@
 #![feature(type_alias_impl_trait)]
 
-// check-pass
-
 type A = impl Foo;
 type B = impl Foo;
 
@@ -10,6 +8,7 @@ trait Foo {}
 fn muh(x: A) -> B {
     if false {
         return x;  // B's hidden type is A (opaquely)
+        //~^ ERROR opaque type's hidden type cannot be another opaque type
     }
     Bar // A's hidden type is `Bar`, because all the return types are compared with each other
 }
diff --git a/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr b/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
new file mode 100644
index 00000000000..b06dc16d5e7
--- /dev/null
+++ b/src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/two_tait_defining_each_other3.rs:10:16
+   |
+LL |         return x;  // B's hidden type is A (opaquely)
+   |                ^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/two_tait_defining_each_other3.rs:4:10
+   |
+LL | type B = impl Foo;
+   |          ^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/two_tait_defining_each_other3.rs:3:10
+   |
+LL | type A = impl Foo;
+   |          ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
index 6282264d8fe..60b6e1aac62 100644
--- a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
+++ b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs
@@ -1,5 +1,5 @@
 #![feature(type_alias_impl_trait)]
-// build-pass (FIXME(62277): could be check-pass?)
+
 mod my_mod {
     use std::fmt::Debug;
 
@@ -11,7 +11,7 @@ mod my_mod {
     }
 
     pub fn get_foot() -> Foot {
-        get_foo()
+        get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr
new file mode 100644
index 00000000000..fa6ecf68d28
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.stderr
@@ -0,0 +1,19 @@
+error: opaque type's hidden type cannot be another opaque type from the same scope
+  --> $DIR/nested_type_alias_impl_trait.rs:14:9
+   |
+LL |         get_foo()
+   |         ^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
+   |
+note: opaque type whose hidden type is being assigned
+  --> $DIR/nested_type_alias_impl_trait.rs:7:21
+   |
+LL |     pub type Foot = impl Debug;
+   |                     ^^^^^^^^^^
+note: opaque type being used as hidden type
+  --> $DIR/nested_type_alias_impl_trait.rs:6:20
+   |
+LL |     pub type Foo = impl Debug;
+   |                    ^^^^^^^^^^
+
+error: aborting due to previous error
+