Skip to content

Commit da88a87

Browse files
committed
WIP
1 parent 370fc9b commit da88a87

14 files changed

Lines changed: 1009 additions & 90 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/closure.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
1111
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult};
1212
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
1313
use rustc_macros::{TypeFoldable, TypeVisitable};
14-
use rustc_middle::{bug, span_bug};
1514
use rustc_middle::ty::{
1615
self, ClosureKind, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
1716
TypeVisitableExt, TypeVisitor,
1817
};
18+
use rustc_middle::{bug, span_bug};
1919
use rustc_span::def_id::LocalDefId;
2020
use rustc_span::{DUMMY_SP, Span};
2121
use rustc_trait_selection::error_reporting::traits::ArgKind;
@@ -352,7 +352,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
352352
_ => bug!(),
353353
};
354354
let output = sig.inputs_and_output.last().unwrap();
355-
let inputs_and_output = self.tcx.mk_type_list(&inputs.iter().chain([*output]).collect::<smallvec::SmallVec<[_; 4]>>());
355+
let inputs_and_output = self.tcx.mk_type_list(
356+
&inputs.iter().chain([*output]).collect::<smallvec::SmallVec<[_; 4]>>(),
357+
);
356358
ty::FnSig {
357359
abi: sig.abi,
358360
safety: sig.safety,
@@ -368,7 +370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368370
hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => {
369371
(None, None)
370372
}
371-
}
373+
},
372374
_ => (None, None),
373375
}
374376
}

compiler/rustc_hir_typeck/src/coercion.rs

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

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

1273-
fn sig_for_fn_def_coercion(
1275+
pub(crate) fn sig_for_fn_def_coercion(
12741276
&self,
12751277
fndef: Ty<'tcx>,
12761278
expected_safety: Option<hir::Safety>,
@@ -1313,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13131315
}
13141316
}
13151317

1316-
fn sig_for_closure_coercion(
1318+
pub(crate) fn sig_for_closure_coercion(
13171319
&self,
13181320
closure: Ty<'tcx>,
13191321
expected_safety: Option<hir::Safety>,
@@ -1504,13 +1506,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15041506
target
15051507
}
15061508
Err(coerce_mutual_err) => {
1507-
let new_to_expected_res = self.coerce(
1508-
new,
1509-
new_ty,
1510-
expected_ty,
1511-
AllowTwoPhase::No,
1512-
Some(cause.clone()),
1513-
);
1509+
let new_to_expected_res =
1510+
self.coerce(new, new_ty, expected_ty, AllowTwoPhase::No, Some(cause.clone()));
15141511
match new_to_expected_res {
15151512
Ok(t) => t,
15161513
Err(_) => return Err(coerce_mutual_err),
@@ -1581,7 +1578,7 @@ pub(crate) struct CoerceMany<'tcx> {
15811578
expected_ty: Ty<'tcx>,
15821579
final_ty: Option<Ty<'tcx>>,
15831580
expressions: Vec<(Option<&'tcx hir::Expr<'tcx>>, Ty<'tcx>)>,
1584-
pub(crate) force_initial_sub: bool
1581+
pub(crate) initial_guidance_only: bool,
15851582
}
15861583

15871584
impl<'tcx> CoerceMany<'tcx> {
@@ -1595,7 +1592,12 @@ impl<'tcx> CoerceMany<'tcx> {
15951592
/// Creates a `CoerceMany` with a given capacity.
15961593
#[tracing::instrument()]
15971594
pub(crate) fn with_capacity(expected_ty: Ty<'tcx>, capacity: usize) -> Self {
1598-
CoerceMany { expected_ty, final_ty: None, expressions: Vec::with_capacity(capacity), force_initial_sub: false }
1595+
CoerceMany {
1596+
expected_ty,
1597+
final_ty: None,
1598+
expressions: Vec::with_capacity(capacity),
1599+
initial_guidance_only: false,
1600+
}
15991601
}
16001602

16011603
/// Returns the "expected type" with which this coercion was
@@ -1712,16 +1714,43 @@ impl<'tcx> CoerceMany<'tcx> {
17121714
// Special-case the first expression we are coercing.
17131715
// To be honest, I'm not entirely sure why we do this.
17141716
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1715-
if self.force_initial_sub {
1717+
if !self.initial_guidance_only {
17161718
fcx.coerce(
17171719
expression,
17181720
expression_ty,
17191721
self.expected_ty,
17201722
AllowTwoPhase::No,
17211723
Some(cause.clone()),
17221724
)
1723-
} else {
1725+
} else if false {
17241726
Ok(expression_ty)
1727+
} else {
1728+
// See `tests/ui/coercion/expected-guidance.rs` for why this is needed.
1729+
// If the expected type is e.g. `Option<?0>` and the first arm match sets it to `Option<X>`, the
1730+
// second arm should be able to observe that `?0` is `X`.
1731+
1732+
let source = fcx.try_structurally_resolve_type(expression.span, expression_ty);
1733+
let target = if fcx.next_trait_solver() {
1734+
fcx.try_structurally_resolve_type(cause.span, self.expected_ty)
1735+
} else {
1736+
self.expected_ty
1737+
};
1738+
let coerce_never =
1739+
fcx.tcx.expr_guaranteed_to_constitute_read_for_never(expression);
1740+
let guidance = crate::coercion_guidance::CoerceGuidance::new(
1741+
fcx,
1742+
cause.clone(),
1743+
AllowTwoPhase::No,
1744+
coerce_never,
1745+
)
1746+
.do_guidance(source, target);
1747+
match guidance {
1748+
Ok(ok) => {
1749+
fcx.register_infer_ok_obligations(ok);
1750+
Ok(source)
1751+
}
1752+
Err(e) => Err(e),
1753+
}
17251754
}
17261755
} else {
17271756
fcx.try_find_coercion_lub(
@@ -1749,12 +1778,7 @@ impl<'tcx> CoerceMany<'tcx> {
17491778
// Another example is `break` with no argument expression.
17501779
assert!(expression_ty.is_unit(), "if let hack without unit type");
17511780
for (expr, expr_ty) in self.expressions.iter() {
1752-
let coerce = Coerce::new(
1753-
fcx,
1754-
cause.clone(),
1755-
AllowTwoPhase::No,
1756-
true,
1757-
);
1781+
let coerce = Coerce::new(fcx, cause.clone(), AllowTwoPhase::No, true);
17581782
let ok = match fcx.commit_if_ok(|_| coerce.coerce(*expr_ty, expression_ty)) {
17591783
Ok(coerce) => coerce,
17601784
Err(e) => {
@@ -1843,8 +1867,7 @@ impl<'tcx> CoerceMany<'tcx> {
18431867
E0069,
18441868
"`return;` in a function whose return type is not `()`"
18451869
);
1846-
if let Some(value) = fcx.err_ctxt().ty_kind_suggestion(fcx.param_env, found)
1847-
{
1870+
if let Some(value) = fcx.err_ctxt().ty_kind_suggestion(fcx.param_env, found) {
18481871
err.span_suggestion_verbose(
18491872
cause.span.shrink_to_hi(),
18501873
"give the `return` a value of the expected type",
@@ -1901,10 +1924,7 @@ impl<'tcx> CoerceMany<'tcx> {
19011924
rpit_def_id,
19021925
arm_ty,
19031926
prior_arm_ty,
1904-
prior_non_diverging_arms
1905-
.iter()
1906-
.chain(std::iter::once(&arm_span))
1907-
.copied(),
1927+
prior_non_diverging_arms.iter().chain(std::iter::once(&arm_span)).copied(),
19081928
);
19091929
}
19101930
}
@@ -2181,6 +2201,7 @@ impl<'tcx> CoerceMany<'tcx> {
21812201
&self,
21822202
fcx: &FnCtxt<'a, 'tcx>,
21832203
cause: &ObligationCause<'tcx>,
2204+
mut expected_ty: Ty<'tcx>,
21842205
coerce_never: bool,
21852206
) -> Ty<'tcx> {
21862207
let Some(final_ty) = self.final_ty else {
@@ -2190,69 +2211,70 @@ impl<'tcx> CoerceMany<'tcx> {
21902211
return fcx.tcx.types.never;
21912212
};
21922213

2193-
if self.force_initial_sub {
2214+
if !self.initial_guidance_only {
21942215
return final_ty;
21952216
}
2196-
2197-
let mut expected_ty = self.expected_ty;
2198-
if fcx.next_trait_solver() {
2199-
expected_ty = fcx.try_structurally_resolve_type(
2200-
cause.span,
2201-
expected_ty,
2202-
);
2217+
2218+
if true {
2219+
//return final_ty;
22032220
}
22042221

2205-
// You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2206-
// then *also* each expression ty to the `expected_ty`?".
2207-
// TODO: investigate and validate the following claim
2208-
// Basically, if `expected_ty` is an inference variable, then a coercion
2209-
// with the first arm can constrain that because of the `unify` fallback.
2222+
if fcx.next_trait_solver() {
2223+
expected_ty = fcx.try_structurally_resolve_type(cause.span, expected_ty);
2224+
}
22102225

22112226
let final_ty = fcx.try_structurally_resolve_type(cause.span, final_ty);
2227+
let expected_ty = fcx.try_structurally_resolve_type(cause.span, expected_ty);
22122228
debug!("coerce::complete (final_ty): {:?} -> {:?}", final_ty, expected_ty);
22132229

2214-
let coerce = Coerce::new(
2215-
fcx,
2216-
cause.clone(),
2217-
AllowTwoPhase::No,
2218-
coerce_never,
2219-
);
2220-
let ok = match fcx.commit_if_ok(|_| coerce.coerce(final_ty, expected_ty)) {
2221-
Ok(coerce) => coerce,
2222-
Err(err) => {
2223-
let reported = self.report_coercion_error(
2224-
fcx,
2225-
err,
2226-
cause,
2227-
None,
2228-
expected_ty,
2229-
final_ty,
2230-
|_| {}
2231-
);
2232-
return Ty::new_error(fcx.tcx, reported);
2233-
}
2234-
};
2235-
let _ = fcx.register_infer_ok_obligations(ok);
2230+
if true {
2231+
// You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2232+
// then *also* each expression ty to the `expected_ty`?".
2233+
// TODO: investigate and validate the following claim
2234+
// Basically, if `expected_ty` is an inference variable, then a coercion
2235+
// with the first arm can constrain that because of the `unify` fallback.
2236+
2237+
let coerce = Coerce::new(fcx, cause.clone(), AllowTwoPhase::No, coerce_never);
2238+
let ok = match fcx.commit_if_ok(|_| coerce.coerce(final_ty, expected_ty)) {
2239+
Ok(coerce) => coerce,
2240+
Err(err) => {
2241+
let reported = self.report_coercion_error(
2242+
fcx,
2243+
err,
2244+
cause,
2245+
None,
2246+
expected_ty,
2247+
final_ty,
2248+
|_| {},
2249+
);
2250+
return Ty::new_error(fcx.tcx, reported);
2251+
}
2252+
};
2253+
let _ = fcx.register_infer_ok_obligations(ok);
2254+
}
22362255

22372256
for (expr, ty) in self.expressions.iter() {
22382257
let source = fcx.try_structurally_resolve_type(cause.span, *ty);
22392258
debug!("coerce::complete (expression): {:?} -> {:?}", source, expected_ty);
22402259

2241-
let coerce = Coerce::new(
2242-
fcx,
2243-
cause.clone(),
2244-
AllowTwoPhase::No,
2245-
coerce_never,
2246-
);
2260+
let coerce = Coerce::new(fcx, cause.clone(), AllowTwoPhase::No, coerce_never);
22472261
let ok = match fcx.commit_if_ok(|_| coerce.coerce(source, expected_ty)) {
22482262
Ok(coerce) => coerce,
22492263
Err(e) => {
2250-
let reported = self.report_coercion_error(fcx, e, cause, *expr, expected_ty, source, |_| {});
2264+
let reported = self.report_coercion_error(
2265+
fcx,
2266+
e,
2267+
cause,
2268+
*expr,
2269+
expected_ty,
2270+
source,
2271+
|_| {},
2272+
);
22512273
return Ty::new_error(fcx.tcx, reported);
22522274
}
22532275
};
22542276
let (adjustments, _) = fcx.register_infer_ok_obligations(ok);
2255-
2277+
22562278
if let Some(expr) = expr {
22572279
fcx.set_adjustments(expr, adjustments.clone());
22582280
}
@@ -2263,17 +2285,17 @@ impl<'tcx> CoerceMany<'tcx> {
22632285
if let Err(guar) = final_ty.error_reported() {
22642286
Ty::new_error(fcx.tcx, guar)
22652287
} else {
2266-
self.expected_ty
2288+
expected_ty
22672289
}
22682290
}
22692291
}
22702292

22712293
/// Recursively visit goals to decide whether an unsizing is possible.
22722294
/// `Break`s when it isn't, and an error should be raised.
22732295
/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.
2274-
struct CoerceVisitor<'a, 'tcx> {
2275-
fcx: &'a FnCtxt<'a, 'tcx>,
2276-
span: Span,
2296+
pub(crate) struct CoerceVisitor<'a, 'tcx> {
2297+
pub(crate) fcx: &'a FnCtxt<'a, 'tcx>,
2298+
pub(crate) span: Span,
22772299
}
22782300

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

0 commit comments

Comments
 (0)