Skip to content

Commit 29354ec

Browse files
Auto merge of #147565 - BoxyUwU:coercion_cleanup, r=<try>
coercions reviews/misc whatevers
2 parents d85276b + 345b41b commit 29354ec

30 files changed

+1132
-458
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
10621062

10631063
Rvalue::Cast(cast_kind, op, ty) => {
10641064
match *cast_kind {
1065-
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => {
1065+
CastKind::PointerCoercion(
1066+
PointerCoercion::ReifyFnPointer,
1067+
coercion_source,
1068+
) => {
10661069
let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
10671070
let src_ty = op.ty(self.body, tcx);
10681071
let mut src_sig = src_ty.fn_sig(tcx);

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 346 additions & 388 deletions
Large diffs are not rendered by default.

compiler/rustc_middle/src/ty/adjustment.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use crate::ty::{Ty, TyCtxt};
99

1010
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
1111
pub enum PointerCoercion {
12-
/// Go from a fn-item type to a fn-pointer type.
12+
/// Go from a fn-item type to a fn pointer or an unsafe fn pointer.
13+
/// It cannot convert an unsafe fn-item to a safe fn pointer.
1314
ReifyFnPointer,
1415

1516
/// Go from a safe fn pointer to an unsafe fn pointer.

compiler/rustc_middle/src/ty/context.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2834,14 +2834,29 @@ slice_interners!(
28342834
);
28352835

28362836
impl<'tcx> TyCtxt<'tcx> {
2837-
/// Given a `fn` type, returns an equivalent `unsafe fn` type;
2837+
/// Given a `fn` sig, returns an equivalent `unsafe fn` type;
28382838
/// that is, a `fn` type that is equivalent in every way for being
28392839
/// unsafe.
28402840
pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
28412841
assert!(sig.safety().is_safe());
28422842
Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig }))
28432843
}
28442844

2845+
/// Given a `fn` sig, returns an equivalent `unsafe fn` sig;
2846+
/// that is, a `fn` sig that is equivalent in every way for being
2847+
/// unsafe.
2848+
pub fn safe_to_unsafe_sig(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> {
2849+
assert!(sig.safety().is_safe());
2850+
sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig })
2851+
}
2852+
2853+
/// Given a `unsafe fn` sig, returns an equivalent `fn` sig;
2854+
/// that is, a `fn` sig that is equivalent in every way for being
2855+
/// safe.
2856+
pub fn unsafe_to_safe_sig(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> {
2857+
sig.map_bound(|sig| ty::FnSig{ safety: hir::Safety::Safe, ..sig })
2858+
}
2859+
28452860
/// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
28462861
/// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
28472862
pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool {

tests/crashes/132765.rs

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// We have two function parameters with types:
2+
// - `&?0`
3+
// - `Box<for<'a> fn(<?0 as Trait<'a>>::Item)>`
4+
//
5+
// As the alias in the second parameter has a `?0` it is an ambig
6+
// alias, and as it references bound vars it can't be normalized to
7+
// an infer var.
8+
//
9+
// When checking function arguments we try to coerce both:
10+
// - `&()` to `&?0`
11+
// - `FnDef(f)` to `Box<for<'a> fn(<?0 as Trait<'a>>::Item)>`
12+
//
13+
// The first coercion infers `?0=()`. Previously when handling
14+
// the second coercion we wound *re-normalize* the alias, which
15+
// now that `?0` has been inferred allowed us to determine this
16+
// alias is not wellformed and normalize it to some infer var `?1`.
17+
//
18+
// We would then see that `FnDef(f)` can't be coerced to `Box<fn(?1)>`
19+
// and return a `TypeError` referencing this new variable `?1`. This
20+
// then caused ICEs as diagnostics would encounter inferences variables
21+
// from the result of normalization inside of the probe used be coercion.
22+
23+
24+
trait LendingIterator {
25+
type Item<'q>;
26+
fn for_each(&self, _f: Box<fn(Self::Item<'_>)>) {}
27+
}
28+
29+
fn f(_: ()) {}
30+
31+
fn main() {
32+
LendingIterator::for_each(&(), f);
33+
//~^ ERROR: the trait bound `(): LendingIterator` is not satisfied
34+
//~| ERROR: the trait bound `(): LendingIterator` is not satisfied
35+
//~| ERROR: mismatched types
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error[E0277]: the trait bound `(): LendingIterator` is not satisfied
2+
--> $DIR/hr_alias_normalization_leaking_vars.rs:32:31
3+
|
4+
LL | LendingIterator::for_each(&(), f);
5+
| ------------------------- ^^^ the trait `LendingIterator` is not implemented for `()`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
help: this trait has no implementations, consider adding one
10+
--> $DIR/hr_alias_normalization_leaking_vars.rs:24:1
11+
|
12+
LL | trait LendingIterator {
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error[E0308]: mismatched types
16+
--> $DIR/hr_alias_normalization_leaking_vars.rs:32:36
17+
|
18+
LL | LendingIterator::for_each(&(), f);
19+
| ------------------------- ^ expected `Box<fn(...)>`, found fn item
20+
| |
21+
| arguments to this function are incorrect
22+
|
23+
= note: expected struct `Box<for<'a> fn(<() as LendingIterator>::Item<'a>)>`
24+
found fn item `fn(()) {f}`
25+
note: method defined here
26+
--> $DIR/hr_alias_normalization_leaking_vars.rs:26:8
27+
|
28+
LL | fn for_each(&self, _f: Box<fn(Self::Item<'_>)>) {}
29+
| ^^^^^^^^ ---------------------------
30+
31+
error[E0277]: the trait bound `(): LendingIterator` is not satisfied
32+
--> $DIR/hr_alias_normalization_leaking_vars.rs:32:36
33+
|
34+
LL | LendingIterator::for_each(&(), f);
35+
| ^ the trait `LendingIterator` is not implemented for `()`
36+
|
37+
help: this trait has no implementations, consider adding one
38+
--> $DIR/hr_alias_normalization_leaking_vars.rs:24:1
39+
|
40+
LL | trait LendingIterator {
41+
| ^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: aborting due to 3 previous errors
44+
45+
Some errors have detailed explanations: E0277, E0308.
46+
For more information about an error, try `rustc --explain E0277`.

tests/ui/coercion/issue-88097.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// behavior has been fixed.
44

55
//@ check-pass
6+
//@ revisions: current next
7+
//@ ignore-compare-mode-next-solver (explicit revisions)
8+
//@[next] compile-flags: -Znext-solver
69

710
fn peculiar() -> impl Fn(u8) -> u8 {
811
return |x| x + 1
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
macro_rules! lub {
2+
($lhs:expr, $rhs:expr) => {
3+
if true { $lhs } else { $rhs }
4+
};
5+
}
6+
7+
struct Foo<T>(T);
8+
9+
fn mk<T>() -> T {
10+
loop {}
11+
}
12+
13+
fn lub_deep_binder() {
14+
loop {}
15+
16+
let a: Foo<for<'a> fn(&'a ())> = mk::<Foo<fn(&'static ())>>();
17+
//~^ ERROR: mismatched types
18+
19+
let lhs = mk::<Foo<for<'a> fn(&'static (), &'a ())>>();
20+
let rhs = mk::<Foo<for<'a> fn(&'a (), &'static ())>>();
21+
lub!(lhs, rhs);
22+
//~^ ERROR: `if` and `else` have incompatible types
23+
}
24+
25+
fn main() {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/leak_check_failed_coercion_ops.rs:16:38
3+
|
4+
LL | let a: Foo<for<'a> fn(&'a ())> = mk::<Foo<fn(&'static ())>>();
5+
| ----------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
6+
| |
7+
| expected due to this
8+
|
9+
= note: expected struct `Foo<for<'a> fn(&'a ())>`
10+
found struct `Foo<fn(&'static ())>`
11+
12+
error[E0308]: `if` and `else` have incompatible types
13+
--> $DIR/leak_check_failed_coercion_ops.rs:21:15
14+
|
15+
LL | lub!(lhs, rhs);
16+
| --- ^^^ one type is more general than the other
17+
| |
18+
| expected because of this
19+
|
20+
= note: expected struct `Foo<for<'a> fn(&(), &'a ())>`
21+
found struct `Foo<for<'a> fn(&'a (), &())>`
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)