diff --git a/compiler/rustc_hir_analysis/src/check/expectation.rs b/compiler/rustc_hir_analysis/src/check/expectation.rs index e9e810344776b..d017ded103f15 100644 --- a/compiler/rustc_hir_analysis/src/check/expectation.rs +++ b/compiler/rustc_hir_analysis/src/check/expectation.rs @@ -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`, 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 = &, this + /// hint would be given when type-checking . 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), } @@ -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, } } @@ -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), } } @@ -87,7 +91,7 @@ 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), } } @@ -95,7 +99,7 @@ impl<'a, 'tcx> Expectation<'tcx> { pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self.resolve(fcx) { NoExpectation | IsLast(_) => None, - ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), + ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueDeref(ty) => Some(ty), } } @@ -106,9 +110,7 @@ impl<'a, 'tcx> Expectation<'tcx> { pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self { ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => { - None - } + NoExpectation | ExpectCastableToType(_) | ExpectRvalueDeref(_) | IsLast(_) => None, } } diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs index 71c6da862c94b..30be33a6bbcf9 100644 --- a/compiler/rustc_hir_analysis/src/check/expr.rs +++ b/compiler/rustc_hir_analysis/src/check/expr.rs @@ -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, @@ -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, diff --git a/src/test/ui/coercion/coerce-block-tail-26978.rs b/src/test/ui/coercion/coerce-block-tail-26978.rs new file mode 100644 index 0000000000000..a9c19c78b1f29 --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail-26978.rs @@ -0,0 +1,10 @@ +// check-pass +fn f(_: &i32) {} + +fn main() { + let x = Box::new(1i32); + + f(&x); + f(&(x)); + f(&{x}); +} diff --git a/src/test/ui/coercion/coerce-block-tail-57749.rs b/src/test/ui/coercion/coerce-block-tail-57749.rs new file mode 100644 index 0000000000000..632dd2e3ca6db --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail-57749.rs @@ -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 }); +} diff --git a/src/test/ui/coercion/coerce-block-tail-83783.rs b/src/test/ui/coercion/coerce-block-tail-83783.rs new file mode 100644 index 0000000000000..d70dfd92fceab --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail-83783.rs @@ -0,0 +1,12 @@ +// check-pass +// edition:2018 +fn _consume_reference(_: &T) {} + +async fn _foo() { + _consume_reference::(&Box::new(7_i32)); + _consume_reference::(&async { Box::new(7_i32) }.await); + _consume_reference::<[i32]>(&vec![7_i32]); + _consume_reference::<[i32]>(&async { vec![7_i32] }.await); +} + +fn main() { } diff --git a/src/test/ui/coercion/coerce-block-tail-83850.rs b/src/test/ui/coercion/coerce-block-tail-83850.rs new file mode 100644 index 0000000000000..77fdf99983332 --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail-83850.rs @@ -0,0 +1,7 @@ +// check-fail +fn f(_: &[i32]) {} + +fn main() { + f(&Box::new([1, 2])); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/coercion/coerce-block-tail-83850.stderr b/src/test/ui/coercion/coerce-block-tail-83850.stderr new file mode 100644 index 0000000000000..bbf6075437043 --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail-83850.stderr @@ -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`. diff --git a/src/test/ui/coercion/coerce-block-tail.rs b/src/test/ui/coercion/coerce-block-tail.rs new file mode 100644 index 0000000000000..442660efe2606 --- /dev/null +++ b/src/test/ui/coercion/coerce-block-tail.rs @@ -0,0 +1,5 @@ +// check-pass +fn main() { + let _: &str = & { String::from("hahah")}; + let _: &i32 = & { Box::new(1i32) }; +} diff --git a/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr b/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr index 6ded03e45b55e..a06726c8b82e2 100644 --- a/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr +++ b/src/test/ui/did_you_mean/brackets-to-braces-single-element.stderr @@ -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 ];