Propagate coercion cause into try_coerce
Currently, `coerce_inner` discards its `ObligationCause` when calling `try_coerce`. This interfers with other diagnostc improvements I'm working on, since we will lose the original span by the time the actual coercion occurs. Additionally, we now use the span of the trailing expression (rather than the span of the entire function) when performing a coercion in `check_return_expr`. This currently has no visible effect on any of the unit tests, but will unblock future diagnostic improvements.
This commit is contained in:
parent
237bb5e008
commit
31cdd8cdd2
16 changed files with 52 additions and 23 deletions
|
@ -362,6 +362,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
AllowTwoPhase::No,
|
AllowTwoPhase::No,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
@ -379,6 +380,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
AllowTwoPhase::No,
|
AllowTwoPhase::No,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
@ -394,6 +396,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
|
fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
AllowTwoPhase::No,
|
AllowTwoPhase::No,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
@ -409,6 +412,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
),
|
),
|
||||||
self.cast_ty,
|
self.cast_ty,
|
||||||
AllowTwoPhase::No,
|
AllowTwoPhase::No,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
|
@ -666,6 +670,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
self.expr_ty,
|
self.expr_ty,
|
||||||
fcx.tcx.mk_fn_ptr(f),
|
fcx.tcx.mk_fn_ptr(f),
|
||||||
AllowTwoPhase::No,
|
AllowTwoPhase::No,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
if let Err(TypeError::IntrinsicCast) = res {
|
if let Err(TypeError::IntrinsicCast) = res {
|
||||||
return Err(CastError::IllegalCast);
|
return Err(CastError::IllegalCast);
|
||||||
|
@ -829,7 +834,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
|
|
||||||
// Coerce to a raw pointer so that we generate AddressOf in MIR.
|
// Coerce to a raw pointer so that we generate AddressOf in MIR.
|
||||||
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
|
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(|_| {
|
.unwrap_or_else(|_| {
|
||||||
bug!(
|
bug!(
|
||||||
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
"could not cast from reference to array to pointer to array ({:?} to {:?})",
|
||||||
|
@ -861,7 +866,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
|
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(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
} else {
|
} else {
|
||||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
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;
|
fcx.in_tail_expr = false;
|
||||||
|
|
||||||
|
|
|
@ -941,11 +941,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expr_ty: Ty<'tcx>,
|
expr_ty: Ty<'tcx>,
|
||||||
target: Ty<'tcx>,
|
target: Ty<'tcx>,
|
||||||
allow_two_phase: AllowTwoPhase,
|
allow_two_phase: AllowTwoPhase,
|
||||||
|
cause: Option<ObligationCause<'tcx>>,
|
||||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
let source = self.resolve_vars_with_obligations(expr_ty);
|
let source = self.resolve_vars_with_obligations(expr_ty);
|
||||||
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
|
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 coerce = Coerce::new(self, cause, allow_two_phase);
|
||||||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
|
||||||
|
|
||||||
|
@ -1369,7 +1371,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
// Special-case the first expression we are coercing.
|
// Special-case the first expression we are coercing.
|
||||||
// To be honest, I'm not entirely sure why we do this.
|
// 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
|
// 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 {
|
} else {
|
||||||
match self.expressions {
|
match self.expressions {
|
||||||
Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
|
Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
|
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
|
||||||
let expected = self.resolve_vars_with_obligations(expected);
|
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),
|
Ok(ty) => return (ty, None),
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
};
|
};
|
||||||
|
|
|
@ -747,7 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if self.ret_coercion_span.get().is_none() {
|
if self.ret_coercion_span.get().is_none() {
|
||||||
self.ret_coercion_span.set(Some(e.span));
|
self.ret_coercion_span.set(Some(e.span));
|
||||||
}
|
}
|
||||||
self.check_return_expr(e);
|
self.check_return_expr(e, true);
|
||||||
} else {
|
} else {
|
||||||
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
|
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
|
||||||
if self.ret_coercion_span.get().is_none() {
|
if self.ret_coercion_span.get().is_none() {
|
||||||
|
@ -776,16 +776,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.tcx.types.never
|
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(|| {
|
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
||||||
span_bug!(return_expr.span, "check_return_expr called outside fn body")
|
span_bug!(return_expr.span, "check_return_expr called outside fn body")
|
||||||
});
|
});
|
||||||
|
|
||||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||||
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_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 {
|
||||||
|
if let ExprKind::Block(body, _) = return_expr.kind {
|
||||||
|
if let Some(last_expr) = body.expr {
|
||||||
|
span = last_expr.span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ret_coercion.borrow_mut().coerce(
|
ret_coercion.borrow_mut().coerce(
|
||||||
self,
|
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,
|
||||||
return_expr_ty,
|
return_expr_ty,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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()))
|
LL | Box::new(self.out_edges(u).map(|e| e.target()))
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: but, the lifetime must be valid for the static lifetime...
|
= 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
|
--> $DIR/issue-55796.rs:18:9
|
||||||
|
|
|
|
||||||
LL | Box::new(self.out_edges(u).map(|e| e.target()))
|
LL | Box::new(self.out_edges(u).map(|e| e.target()))
|
||||||
|
@ -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()))
|
LL | Box::new(self.in_edges(u).map(|e| e.target()))
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: but, the lifetime must be valid for the static lifetime...
|
= 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
|
--> $DIR/issue-55796.rs:23:9
|
||||||
|
|
|
|
||||||
LL | Box::new(self.in_edges(u).map(|e| e.target()))
|
LL | Box::new(self.in_edges(u).map(|e| e.target()))
|
||||||
|
|
|
@ -17,7 +17,7 @@ LL | Box::new(move |_| fut)
|
||||||
= note: expected `(Pin<Box<dyn Future<Output = A> + Send>>,)`
|
= note: expected `(Pin<Box<dyn Future<Output = A> + Send>>,)`
|
||||||
found `(Pin<Box<(dyn Future<Output = A> + Send + 'a)>>,)`
|
found `(Pin<Box<(dyn Future<Output = A> + Send + 'a)>>,)`
|
||||||
= note: but, the lifetime must be valid for the static lifetime...
|
= 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
|
--> $DIR/issue-75777.rs:13:5
|
||||||
|
|
|
|
||||||
LL | Box::new(move |_| fut)
|
LL | Box::new(move |_| fut)
|
||||||
|
|
|
@ -19,7 +19,7 @@ note: but, the lifetime must be valid for the lifetime `'_` as defined on the im
|
||||||
|
|
|
|
||||||
LL | impl Foo<'_> {
|
LL | impl Foo<'_> {
|
||||||
| ^^
|
| ^^
|
||||||
note: ...so that the expression is assignable
|
note: ...so that the types are compatible
|
||||||
--> $DIR/issue-55394.rs:9:9
|
--> $DIR/issue-55394.rs:9:9
|
||||||
|
|
|
|
||||||
LL | Foo { bar }
|
LL | Foo { bar }
|
||||||
|
|
|
@ -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> {
|
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
|
--> $DIR/type-alias-free-regions.rs:17:9
|
||||||
|
|
|
|
||||||
LL | C { f: b }
|
LL | C { f: b }
|
||||||
|
@ -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> {
|
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
|
--> $DIR/type-alias-free-regions.rs:27:9
|
||||||
|
|
|
|
||||||
LL | C { f: Box::new(b.0) }
|
LL | C { f: Box::new(b.0) }
|
||||||
|
|
|
@ -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 {
|
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
|
--> $DIR/object-lifetime-default-elision.rs:71:5
|
||||||
|
|
|
|
||||||
LL | ss
|
LL | ss
|
||||||
|
@ -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 {
|
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
|
--> $DIR/object-lifetime-default-elision.rs:71:5
|
||||||
|
|
|
|
||||||
LL | ss
|
LL | ss
|
||||||
|
|
|
@ -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> {
|
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
|
--> $DIR/region-object-lifetime-in-coercion.rs:23:5
|
||||||
|
|
|
|
||||||
LL | Box::new(v)
|
LL | Box::new(v)
|
||||||
|
|
|
@ -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> {
|
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
|
--> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
|
||||||
|
|
|
|
||||||
LL | box v as Box<dyn SomeTrait + 'a>
|
LL | box v as Box<dyn SomeTrait + 'a>
|
||||||
|
|
|
@ -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> {
|
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
|
--> $DIR/regions-creating-enums4.rs:7:5
|
||||||
|
|
|
|
||||||
LL | Ast::Add(x, y)
|
LL | Ast::Add(x, y)
|
||||||
|
|
|
@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
|
||||||
|
|
|
|
||||||
LL | with(|o| o)
|
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
|
--> $DIR/regions-ret-borrowed-1.rs:10:14
|
||||||
|
|
|
|
||||||
LL | with(|o| o)
|
LL | with(|o| o)
|
||||||
|
|
|
@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on th
|
||||||
|
|
|
|
||||||
LL | with(|o| o)
|
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
|
--> $DIR/regions-ret-borrowed.rs:13:14
|
||||||
|
|
|
|
||||||
LL | with(|o| o)
|
LL | with(|o| o)
|
||||||
|
|
|
@ -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 {
|
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
|
--> $DIR/regions-trait-object-subtyping.rs:15:5
|
||||||
|
|
|
|
||||||
LL | x
|
LL | x
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue