Skip to content

Commit 690f50a

Browse files
committed
WIP
1 parent 5cef4bf commit 690f50a

12 files changed

Lines changed: 964 additions & 46 deletions

File tree

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
178178
//let coerce_never = self.tcx.expr_guaranteed_to_constitute_read_for_never(expr);
179179
let coerce_never = true;
180180
tracing::debug!("calling complete in check_expr_match");
181-
coercion.complete(self, &cause, coerce_never)
181+
let expected = expected.coercion_target_type(self, expr.span);
182+
coercion.complete(self, &cause, expected, coerce_never)
182183
}
183184

184185
fn explain_never_type_coerced_to_unit(

compiler/rustc_hir_typeck/src/check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub(super) fn check_fn<'a, 'tcx>(
136136
let coercion = fcx.ret_coercion.take().unwrap().into_inner();
137137
let cause = ObligationCause::dummy();
138138
tracing::debug!("calling complete in check_fn");
139-
let mut actual_return_ty = coercion.complete(fcx, &cause, true);
139+
let mut actual_return_ty = coercion.complete(fcx, &cause, ret_ty, true);
140140
debug!("actual_return_ty = {:?}", actual_return_ty);
141141
if let ty::Dynamic(..) = declared_ret_ty.kind() {
142142
// We have special-cased the case where the function is declared

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
818818
ForceLeakCheck::No,
819819
)?;
820820

821+
tracing::debug!(?coercion);
822+
821823
// Create an obligation for `Source: CoerceUnsized<Target>`.
822824
let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target });
823825
let pred = ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]);
@@ -1271,7 +1273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12711273
}
12721274
}
12731275

1274-
fn sig_for_fn_def_coercion(
1276+
pub(crate) fn sig_for_fn_def_coercion(
12751277
&self,
12761278
fndef: Ty<'tcx>,
12771279
expected_safety: Option<hir::Safety>,
@@ -1314,7 +1316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13141316
}
13151317
}
13161318

1317-
fn sig_for_closure_coercion(
1319+
pub(crate) fn sig_for_closure_coercion(
13181320
&self,
13191321
closure: Ty<'tcx>,
13201322
expected_safety: Option<hir::Safety>,
@@ -1600,7 +1602,7 @@ pub(crate) struct CoerceMany<'tcx> {
16001602
expected_ty: Ty<'tcx>,
16011603
final_ty: Option<Ty<'tcx>>,
16021604
expressions: Vec<(Option<&'tcx hir::Expr<'tcx>>, Ty<'tcx>)>,
1603-
pub(crate) force_initial_sub: bool,
1605+
pub(crate) initial_guidance_only: bool,
16041606
}
16051607

16061608
impl<'tcx> CoerceMany<'tcx> {
@@ -1618,7 +1620,7 @@ impl<'tcx> CoerceMany<'tcx> {
16181620
expected_ty,
16191621
final_ty: None,
16201622
expressions: Vec::with_capacity(capacity),
1621-
force_initial_sub: false,
1623+
initial_guidance_only: false,
16221624
}
16231625
}
16241626

@@ -1736,16 +1738,43 @@ impl<'tcx> CoerceMany<'tcx> {
17361738
// Special-case the first expression we are coercing.
17371739
// To be honest, I'm not entirely sure why we do this.
17381740
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1739-
if self.force_initial_sub {
1741+
if !self.initial_guidance_only {
17401742
fcx.coerce(
17411743
expression,
17421744
expression_ty,
17431745
self.expected_ty,
17441746
AllowTwoPhase::No,
17451747
Some(cause.clone()),
17461748
)
1747-
} else {
1749+
} else if false {
17481750
Ok(expression_ty)
1751+
} else {
1752+
// See `tests/ui/coercion/expected-guidance.rs` for why this is needed.
1753+
// If the expected type is e.g. `Option<?0>` and the first arm match sets it to `Option<X>`, the
1754+
// second arm should be able to observe that `?0` is `X`.
1755+
1756+
let source = fcx.try_structurally_resolve_type(expression.span, expression_ty);
1757+
let target = if fcx.next_trait_solver() {
1758+
fcx.try_structurally_resolve_type(cause.span, self.expected_ty)
1759+
} else {
1760+
self.expected_ty
1761+
};
1762+
let coerce_never =
1763+
fcx.tcx.expr_guaranteed_to_constitute_read_for_never(expression);
1764+
let guidance = crate::coercion_guidance::CoerceGuidance::new(
1765+
fcx,
1766+
cause.clone(),
1767+
AllowTwoPhase::No,
1768+
coerce_never,
1769+
)
1770+
.do_guidance(source, target);
1771+
match guidance {
1772+
Ok(ok) => {
1773+
fcx.register_infer_ok_obligations(ok);
1774+
Ok(source)
1775+
}
1776+
Err(e) => Err(e),
1777+
}
17491778
}
17501779
} else {
17511780
fcx.try_find_coercion_lub(
@@ -2196,6 +2225,7 @@ impl<'tcx> CoerceMany<'tcx> {
21962225
&self,
21972226
fcx: &FnCtxt<'a, 'tcx>,
21982227
cause: &ObligationCause<'tcx>,
2228+
mut expected_ty: Ty<'tcx>,
21992229
coerce_never: bool,
22002230
) -> Ty<'tcx> {
22012231
let Some(final_ty) = self.final_ty else {
@@ -2205,7 +2235,7 @@ impl<'tcx> CoerceMany<'tcx> {
22052235
return fcx.tcx.types.never;
22062236
};
22072237

2208-
if self.force_initial_sub {
2238+
if !self.initial_guidance_only {
22092239
return final_ty;
22102240
}
22112241

@@ -2214,32 +2244,39 @@ impl<'tcx> CoerceMany<'tcx> {
22142244
expected_ty = fcx.try_structurally_resolve_type(cause.span, expected_ty);
22152245
}
22162246

2217-
// You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2218-
// then *also* each expression ty to the `expected_ty`?".
2219-
// TODO: investigate and validate the following claim
2220-
// Basically, if `expected_ty` is an inference variable, then a coercion
2221-
// with the first arm can constrain that because of the `unify` fallback.
2247+
if fcx.next_trait_solver() {
2248+
expected_ty = fcx.try_structurally_resolve_type(cause.span, expected_ty);
2249+
}
22222250

22232251
let final_ty = fcx.try_structurally_resolve_type(cause.span, final_ty);
2252+
let expected_ty = fcx.try_structurally_resolve_type(cause.span, expected_ty);
22242253
debug!("coerce::complete (final_ty): {:?} -> {:?}", final_ty, expected_ty);
22252254

2226-
let coerce = Coerce::new(fcx, cause.clone(), AllowTwoPhase::No, coerce_never);
2227-
let ok = match fcx.commit_if_ok(|_| coerce.coerce(final_ty, expected_ty)) {
2228-
Ok(coerce) => coerce,
2229-
Err(err) => {
2230-
let reported = self.report_coercion_error(
2231-
fcx,
2232-
err,
2233-
cause,
2234-
None,
2235-
expected_ty,
2236-
final_ty,
2237-
|_| {},
2238-
);
2239-
return Ty::new_error(fcx.tcx, reported);
2240-
}
2241-
};
2242-
let _ = fcx.register_infer_ok_obligations(ok);
2255+
if true {
2256+
// You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2257+
// then *also* each expression ty to the `expected_ty`?".
2258+
// TODO: investigate and validate the following claim
2259+
// Basically, if `expected_ty` is an inference variable, then a coercion
2260+
// with the first arm can constrain that because of the `unify` fallback.
2261+
2262+
let coerce = Coerce::new(fcx, cause.clone(), AllowTwoPhase::No, coerce_never);
2263+
let ok = match fcx.commit_if_ok(|_| coerce.coerce(final_ty, expected_ty)) {
2264+
Ok(coerce) => coerce,
2265+
Err(err) => {
2266+
let reported = self.report_coercion_error(
2267+
fcx,
2268+
err,
2269+
cause,
2270+
None,
2271+
expected_ty,
2272+
final_ty,
2273+
|_| {},
2274+
);
2275+
return Ty::new_error(fcx.tcx, reported);
2276+
}
2277+
};
2278+
let _ = fcx.register_infer_ok_obligations(ok);
2279+
}
22432280

22442281
for (expr, ty) in self.expressions.iter() {
22452282
let source = fcx.try_structurally_resolve_type(cause.span, *ty);
@@ -2273,21 +2310,21 @@ impl<'tcx> CoerceMany<'tcx> {
22732310
if let Err(guar) = final_ty.error_reported() {
22742311
Ty::new_error(fcx.tcx, guar)
22752312
} else {
2276-
self.expected_ty
2313+
expected_ty
22772314
}
22782315
}
22792316
}
22802317

22812318
/// Recursively visit goals to decide whether an unsizing is possible.
22822319
/// `Break`s when it isn't, and an error should be raised.
22832320
/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.
2284-
struct CoerceVisitor<'a, 'tcx> {
2285-
fcx: &'a FnCtxt<'a, 'tcx>,
2286-
span: Span,
2321+
pub(crate) struct CoerceVisitor<'a, 'tcx> {
2322+
pub(crate) fcx: &'a FnCtxt<'a, 'tcx>,
2323+
pub(crate) span: Span,
22872324
/// Whether the coercion is impossible. If so we sometimes still try to
22882325
/// coerce in these cases to emit better errors. This changes the behavior
22892326
/// when hitting the recursion limit.
2290-
errored: bool,
2327+
pub(crate) errored: bool,
22912328
}
22922329

22932330
impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {

0 commit comments

Comments
 (0)