Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate deref coercion into block #83850

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions compiler/rustc_hir_analysis/src/check/expectation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ pub enum Expectation<'tcx> {
/// This expression will be cast to the `Ty`.
ExpectCastableToType(Ty<'tcx>),

/// This rvalue expression will be wrapped in `&` or `Box` and coerced
/// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
ExpectRvalueLikeUnsized(Ty<'tcx>),
/// This rvalue expression will be deref'd to the type Ty.
///
/// Given, for example, if you have let x: &Ty = &<foo>, this
/// hint would be given when type-checking <foo>. It is
/// not required that foo has the type Ty, but it must have some
/// type that derefs to Ty for the program to be legal.
ExpectRvalueDeref(Ty<'tcx>),

IsLast(Span),
}
Expand Down Expand Up @@ -48,7 +52,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
let ety = fcx.shallow_resolve(ety);
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
}
ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
ExpectRvalueDeref(ety) => ExpectRvalueDeref(ety),
_ => NoExpectation,
}
}
Expand All @@ -74,7 +78,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
/// for examples of where this comes up,.
pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
match fcx.tcx.struct_tail_without_normalization(ty).kind() {
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueDeref(ty),
_ => ExpectHasType(ty),
}
}
Expand All @@ -87,15 +91,15 @@ impl<'a, 'tcx> Expectation<'tcx> {
NoExpectation => NoExpectation,
ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)),
ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)),
ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)),
ExpectRvalueDeref(t) => ExpectRvalueDeref(fcx.resolve_vars_if_possible(t)),
IsLast(sp) => IsLast(sp),
}
}

pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self.resolve(fcx) {
NoExpectation | IsLast(_) => None,
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueDeref(ty) => Some(ty),
}
}

Expand All @@ -106,9 +110,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self {
ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
None
}
NoExpectation | ExpectCastableToType(_) | ExpectRvalueDeref(_) | IsLast(_) => None,
}
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_analysis/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::check::cast;
use crate::check::coercion::CoerceMany;
use crate::check::fatally_break_rust;
use crate::check::method::SelfSource;
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::check::Expectation::{
self, ExpectCastableToType, ExpectHasType, ExpectRvalueDeref, NoExpectation,
};
use crate::check::{
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
TupleArgumentsFlag::DontTupleArguments,
Expand Down Expand Up @@ -437,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// the last field of a struct can be unsized.
ExpectHasType(*ty)
} else {
Expectation::rvalue_hint(self, *ty)
ExpectRvalueDeref(*ty)
}
}
_ => NoExpectation,
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/coercion/coerce-block-tail-26978.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// check-pass
fn f(_: &i32) {}

fn main() {
let x = Box::new(1i32);

f(&x);
f(&(x));
f(&{x});
}
34 changes: 34 additions & 0 deletions src/test/ui/coercion/coerce-block-tail-57749.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// check-pass
use std::ops::Deref;

fn main() {
fn save(who: &str) {
println!("I'll save you, {}!", who);
}

struct Madoka;

impl Deref for Madoka {
type Target = str;
fn deref(&self) -> &Self::Target {
"Madoka"
}
}

save(&{ Madoka });

fn reset(how: &u32) {
println!("Reset {} times", how);
}

struct Homura;

impl Deref for Homura {
type Target = u32;
fn deref(&self) -> &Self::Target {
&42
}
}

reset(&{ Homura });
}
12 changes: 12 additions & 0 deletions src/test/ui/coercion/coerce-block-tail-83783.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// check-pass
// edition:2018
fn _consume_reference<T: ?Sized>(_: &T) {}

async fn _foo() {
_consume_reference::<i32>(&Box::new(7_i32));
_consume_reference::<i32>(&async { Box::new(7_i32) }.await);
_consume_reference::<[i32]>(&vec![7_i32]);
_consume_reference::<[i32]>(&async { vec![7_i32] }.await);
}

fn main() { }
7 changes: 7 additions & 0 deletions src/test/ui/coercion/coerce-block-tail-83850.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// check-fail
fn f(_: &[i32]) {}

fn main() {
f(&Box::new([1, 2]));
//~^ ERROR mismatched types
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do this test fail?

Copy link
Member

@pnkfelix pnkfelix May 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this the test encoding the case you asked for above?

Were expecting it to start passing (incorrectly) with this change, and then, after it didn't start passing, you want to understand why that expectation of incorrectness wasn't met?

  • Note that the PR author did post a hypothesis for why, here

Or am I misunderstanding this?

}
19 changes: 19 additions & 0 deletions src/test/ui/coercion/coerce-block-tail-83850.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/coerce-block-tail-83850.rs:5:7
|
LL | f(&Box::new([1, 2]));
| - ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found struct `Box`
| |
| arguments to this function are incorrect
|
= note: expected reference `&[i32]`
found reference `&Box<[{integer}; 2]>`
note: function defined here
--> $DIR/coerce-block-tail-83850.rs:2:4
|
LL | fn f(_: &[i32]) {}
| ^ ---------

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
5 changes: 5 additions & 0 deletions src/test/ui/coercion/coerce-block-tail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// check-pass
fn main() {
let _: &str = & { String::from("hahah")};
let _: &i32 = & { Box::new(1i32) };
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ LL | const B: &[u32] = &[ 1 ];
| ~ ~

error[E0308]: mismatched types
--> $DIR/brackets-to-braces-single-element.rs:7:27
--> $DIR/brackets-to-braces-single-element.rs:7:23
|
LL | const C: &&[u32; 1] = &&{ 1 };
| ^ expected array `[u32; 1]`, found integer
| ^^^^^^^ expected array `[u32; 1]`, found integer
|
= note: expected reference `&'static &'static [u32; 1]`
found reference `&&{integer}`
help: to create an array, use square brackets instead of curly braces
|
LL | const C: &&[u32; 1] = &&[ 1 ];
Expand Down