Skip to content

Propagate coercion cause into try_coerce #89028

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

Merged
merged 1 commit into from
Sep 19, 2021
Merged
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
9 changes: 7 additions & 2 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
),
self.cast_ty,
AllowTwoPhase::No,
None,
)
.is_ok()
{
Expand All @@ -379,6 +380,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
),
self.cast_ty,
AllowTwoPhase::No,
None,
)
.is_ok()
{
Expand All @@ -394,6 +396,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
self.cast_ty,
AllowTwoPhase::No,
None,
)
.is_ok()
{
Expand All @@ -409,6 +412,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
),
self.cast_ty,
AllowTwoPhase::No,
None,
)
.is_ok()
{
Expand Down Expand Up @@ -666,6 +670,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.expr_ty,
fcx.tcx.mk_fn_ptr(f),
AllowTwoPhase::No,
None,
);
if let Err(TypeError::IntrinsicCast) = res {
return Err(CastError::IllegalCast);
Expand Down Expand Up @@ -829,7 +834,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {

// Coerce to a raw pointer so that we generate AddressOf in MIR.
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
.unwrap_or_else(|_| {
bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
Expand Down Expand Up @@ -861,7 +866,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}

fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
} else {
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value);
fcx.check_return_expr(&body.value, false);
}
fcx.in_tail_expr = false;

Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -941,11 +941,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_ty: Ty<'tcx>,
target: Ty<'tcx>,
allow_two_phase: AllowTwoPhase,
cause: Option<ObligationCause<'tcx>>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let source = self.resolve_vars_with_obligations(expr_ty);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);

let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
let cause =
cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable));
let coerce = Coerce::new(self, cause, allow_two_phase);
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;

Expand Down Expand Up @@ -1369,7 +1371,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// Special-case the first expression we are coercing.
// To be honest, I'm not entirely sure why we do this.
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
fcx.try_coerce(
expression,
expression_ty,
self.expected_ty,
AllowTwoPhase::No,
Some(cause.clone()),
)
} else {
match self.expressions {
Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
let expected = self.resolve_vars_with_obligations(expected);

let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
Ok(ty) => return (ty, None),
Err(e) => e,
};
Expand Down
22 changes: 19 additions & 3 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.ret_coercion_span.get().is_none() {
self.ret_coercion_span.set(Some(e.span));
}
self.check_return_expr(e);
self.check_return_expr(e, true);
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
if self.ret_coercion_span.get().is_none() {
Expand Down Expand Up @@ -776,16 +776,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.types.never
}

pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr<'tcx>) {
/// `explicit_return` is `true` if we're checkng an explicit `return expr`,
/// and `false` if we're checking a trailing expression.
pub(super) fn check_return_expr(
&self,
return_expr: &'tcx hir::Expr<'tcx>,
explicit_return: bool,
) {
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
span_bug!(return_expr.span, "check_return_expr called outside fn body")
});

let ret_ty = ret_coercion.borrow().expected_ty();
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
let mut span = return_expr.span;
// Use the span of the trailing expression for our cause,
// not the span of the entire function
if !explicit_return {
Copy link
Member

Choose a reason for hiding this comment

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

Is it actually necessary to have the boolean flag here? I imagine it is trying to account for something like

return { foo; bar; baz };

so that rustc would span the entire block and not just baz here? It seems to me that it would be actually better, and more consistent if we spanned the last expression of the block in these situations.

if let ExprKind::Block(body, _) = return_expr.kind {
if let Some(last_expr) = body.expr {
span = last_expr.span;
}
}
}
ret_coercion.borrow_mut().coerce(
self,
&self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
&self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
return_expr,
return_expr_ty,
);
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-55796.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/iss
LL | Box::new(self.out_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/issue-55796.rs:18:9
|
LL | Box::new(self.out_edges(u).map(|e| e.target()))
Expand All @@ -40,7 +40,7 @@ note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/iss
LL | Box::new(self.in_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/issue-55796.rs:23:9
|
LL | Box::new(self.in_edges(u).map(|e| e.target()))
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-75777.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ LL | Box::new(move |_| fut)
= note: expected `(Pin<Box<dyn Future<Output = A> + Send>>,)`
found `(Pin<Box<(dyn Future<Output = A> + Send + 'a)>>,)`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/issue-75777.rs:13:5
|
LL | Box::new(move |_| fut)
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/nll/issue-55394.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'_` as defined on the im
|
LL | impl Foo<'_> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/issue-55394.rs:9:9
|
LL | Foo { bar }
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nll/type-alias-free-regions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the im
|
LL | impl<'a> FromBox<'a> for C<'a> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/type-alias-free-regions.rs:17:9
|
LL | C { f: b }
Expand Down Expand Up @@ -52,7 +52,7 @@ note: but, the lifetime must be valid for the lifetime `'a` as defined on the im
|
LL | impl<'a> FromTuple<'a> for C<'a> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/type-alias-free-regions.rs:27:9
|
LL | C { f: Box::new(b.0) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
|
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/object-lifetime-default-elision.rs:71:5
|
LL | ss
Expand Down Expand Up @@ -48,7 +48,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
|
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/object-lifetime-default-elision.rs:71:5
|
LL | ss
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
LL | Box::new(v)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'c` as defined on the fu
|
LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
|
LL | box v as Box<dyn SomeTrait + 'a>
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/regions/regions-creating-enums4.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
|
LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/regions-creating-enums4.rs:7:5
|
LL | Ast::Add(x, y)
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/regions/regions-ret-borrowed-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
|
LL | with(|o| o)
| ^^^^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/regions-ret-borrowed-1.rs:10:14
|
LL | with(|o| o)
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/regions/regions-ret-borrowed.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
|
LL | with(|o| o)
| ^^^^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/regions-ret-borrowed.rs:13:14
|
LL | with(|o| o)
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/regions/regions-trait-object-subtyping.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ note: but, the lifetime must be valid for the lifetime `'b` as defined on the fu
|
LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
| ^^
note: ...so that the expression is assignable
note: ...so that the types are compatible
--> $DIR/regions-trait-object-subtyping.rs:15:5
|
LL | x
Expand Down