about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-23 14:09:22 +0200
committerGitHub <noreply@github.com>2024-05-23 14:09:22 +0200
commitabcf400a2835e1db65d034128b25a276b61080a3 (patch)
tree6b14a27b23931535e457dd5fd7c4b28937021ff7 /tests
parent39d2f2affdd6b2856ab4b91359cc0d32b90bd26f (diff)
parentc24148ef7b1d4a280cca60e2001848da70ff07dc (diff)
downloadrust-abcf400a2835e1db65d034128b25a276b61080a3.tar.gz
rust-abcf400a2835e1db65d034128b25a276b61080a3.zip
Rollup merge of #124297 - oli-obk:define_opaque_types13, r=jackh726
Allow coercing functions whose signature differs in opaque types in their defining scope into a shared function pointer type

r? `@compiler-errors`

This accepts more code on stable. It is now possible to have match arms return a function item `foo` and a different function item `bar` in another, and that will constrain OpaqueTypeInDefiningScope to have the hidden type ConcreteType and make the type of the match arms a function pointer that matches the signature. So the following function will now compile, but on master it errors with a type mismatch on the second match arm

```rust
fn foo<T>(t: T) -> T {
    t
}

fn bar<T>(t: T) -> T {
    t
}

fn k() -> impl Sized {
    fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F {
        f
    }
    let x = match true {
        true => {
            let f = foo;
            bind(k(), f)
        }
        false => bar::<()>,
    };
    todo!()
}
```

cc https://github.com/rust-lang/rust/issues/116652

This is very similar to https://github.com/rust-lang/rust/pull/123794, and with the same rationale:

> this is for consistency with `-Znext-solver`. the new solver does not have the concept of "non-defining use of opaque" right now and we would like to ideally keep it that way. Moving to `DefineOpaqueTypes::Yes` in more cases removes subtlety from the type system. Right now we have to be careful when relating `Opaque` with another type as the behavior changes depending on whether we later use the `Opaque` or its hidden type directly (even though they are equal), if that later use is with `DefineOpaqueTypes::No`*
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs57
-rw-r--r--tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr38
2 files changed, 95 insertions, 0 deletions
diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs
new file mode 100644
index 00000000000..5250e3a3d93
--- /dev/null
+++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs
@@ -0,0 +1,57 @@
+//! Test that coercing between function items of different functions works,
+//! as long as their signatures match. The resulting value is a function pointer.
+
+#![feature(type_alias_impl_trait)]
+
+fn foo<T>(t: T) -> T {
+    t
+}
+
+fn bar<T>(t: T) -> T {
+    t
+}
+
+type F = impl Sized;
+
+fn f(a: F) {
+    let mut x = bar::<F>;
+    x = foo::<()>; //~ ERROR: mismatched types
+    x(a);
+    x(());
+}
+
+type I = impl Sized;
+
+fn i(a: I) {
+    let mut x = bar::<()>;
+    x = foo::<I>; //~ ERROR: mismatched types
+    x(a);
+    x(());
+}
+
+type J = impl Sized;
+
+fn j(a: J) {
+    let x = match true {
+        true => bar::<J>,
+        false => foo::<()>,
+    };
+    x(a);
+    x(());
+}
+
+fn k() -> impl Sized {
+    fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F {
+        f
+    }
+    let x = match true {
+        true => {
+            let f = foo;
+            bind(k(), f)
+        }
+        false => bar::<()>,
+    };
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
new file mode 100644
index 00000000000..0b3331b040d
--- /dev/null
+++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
@@ -0,0 +1,38 @@
+error[E0308]: mismatched types
+  --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:18:9
+   |
+LL | type F = impl Sized;
+   |          ---------- the expected opaque type
+...
+LL |     let mut x = bar::<F>;
+   |                 -------- expected due to this value
+LL |     x = foo::<()>;
+   |         ^^^^^^^^^ expected fn item, found a different fn item
+   |
+   = note: expected fn item `fn(F) -> F {bar::<F>}`
+              found fn item `fn(()) {foo::<()>}`
+
+error[E0308]: mismatched types
+  --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9
+   |
+LL | fn foo<T>(t: T) -> T {
+   | -------------------- function `foo` defined here
+...
+LL | type I = impl Sized;
+   |          ---------- the found opaque type
+...
+LL |     let mut x = bar::<()>;
+   |                 --------- expected due to this value
+LL |     x = foo::<I>;
+   |         ^^^^^^^^ expected fn item, found a different fn item
+   |
+   = note: expected fn item `fn(()) {bar::<()>}`
+              found fn item `fn(I) -> I {foo::<I>}`
+help: use parentheses to call this function
+   |
+LL |     x = foo::<I>(/* I */);
+   |                 +++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.