Skip to content

Commit

Permalink
Auto merge of #133559 - compiler-errors:structurally-resolve-adjust-f…
Browse files Browse the repository at this point in the history
…or-branch, r=<try>

Structurally resolve before `adjust_for_branches`

r? lcnr
  • Loading branch information
bors committed Nov 29, 2024
2 parents a45391f + 28c13d2 commit 83a6b38
Show file tree
Hide file tree
Showing 25 changed files with 220 additions and 176 deletions.
7 changes: 4 additions & 3 deletions compiler/rustc_hir_typeck/src/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// type in that case)
let mut all_arms_diverge = Diverges::WarnedAlways;

let expected = orig_expected.adjust_for_branches(self);
let expected = orig_expected.adjust_for_branches(self, expr.span);
debug!(?expected);

let mut coercion = {
Expand Down Expand Up @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let arm_ty = self.check_expr_with_expectation(arm.body, expected);
all_arms_diverge &= self.diverges.get();
let tail_defines_return_position_impl_trait =
self.return_position_impl_trait_from_match_expectation(orig_expected);
self.return_position_impl_trait_from_match_expectation(orig_expected, expr.span);

let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
(Some(blk.hir_id), self.find_block_span(blk))
Expand Down Expand Up @@ -586,8 +586,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn return_position_impl_trait_from_match_expectation(
&self,
expectation: Expectation<'tcx>,
span: Span,
) -> Option<LocalDefId> {
let expected_ty = expectation.to_option(self)?;
let expected_ty = expectation.structurally_resolve(self, span)?;
let (def_id, args) = match *expected_ty.kind() {
// FIXME: Could also check that the RPIT is not defined
ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We didn't record the in scope traits during late resolution
// so we need to probe AllTraits unfortunately
ProbeScope::AllTraits,
expected.only_has_type(self),
expected.structurally_resolve_hard_expectation(self, call_expr.span),
) else {
return;
};
Expand Down
7 changes: 2 additions & 5 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
// type, and see if can glean a closure kind from there.
let (expected_sig, expected_kind) = match expected.to_option(self) {
Some(ty) => self.deduce_closure_signature(
self.try_structurally_resolve_type(expr_span, ty),
closure.kind,
),
let (expected_sig, expected_kind) = match expected.structurally_resolve(self, expr_span) {
Some(ty) => self.deduce_closure_signature(ty, closure.kind),
None => (None, None),
};

Expand Down
44 changes: 20 additions & 24 deletions compiler/rustc_hir_typeck/src/expectation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
// an expected type. Otherwise, we might write parts of the type
// when checking the 'then' block which are incompatible with the
// 'else' branch.
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
pub(super) fn adjust_for_branches(
&self,
fcx: &FnCtxt<'a, 'tcx>,
span: Span,
) -> Expectation<'tcx> {
match *self {
ExpectHasType(ety) => {
let ety = fcx.shallow_resolve(ety);
let ety = fcx.try_structurally_resolve_type(span, ety);
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
}
ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
Expand Down Expand Up @@ -77,39 +81,31 @@ impl<'a, 'tcx> Expectation<'tcx> {
}
}

/// Resolves `expected` by a single level if it is a variable. If
/// there is no expected type or resolution is not possible (e.g.,
/// no constraints yet present), just returns `self`.
fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
pub(super) fn structurally_resolve(
self,
fcx: &FnCtxt<'a, 'tcx>,
span: Span,
) -> Option<Ty<'tcx>> {
match self {
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)),
}
}

pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
match self.resolve(fcx) {
NoExpectation => None,
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => {
Some(fcx.try_structurally_resolve_type(span, ty))
}
}
}

/// It sometimes happens that we want to turn an expectation into
/// a **hard constraint** (i.e., something that must be satisfied
/// for the program to type-check). `only_has_type` will return
/// such a constraint, if it exists.
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
pub(super) fn structurally_resolve_hard_expectation(
self,
fcx: &FnCtxt<'a, 'tcx>,
span: Span,
) -> Option<Ty<'tcx>> {
match self {
ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
ExpectHasType(ty) => Some(fcx.try_structurally_resolve_type(span, ty)),
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
}
}

/// Like `only_has_type`, but instead of returning `None` if no
/// hard constraint exists, creates a fresh type variable.
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
self.only_has_type(fcx).unwrap_or_else(|| fcx.next_ty_var(span))
}
}
84 changes: 46 additions & 38 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,21 +628,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
match ty.kind() {
ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
if oprnd.is_syntactic_place_expr() {
// Places may legitimately have unsized types.
// For example, dereferences of a wide pointer and
// the last field of a struct can be unsized.
ExpectHasType(*ty)
} else {
Expectation::rvalue_hint(self, *ty)
let hint = expected.structurally_resolve_hard_expectation(self, expr.span).map_or(
NoExpectation,
|ty| {
match ty.kind() {
ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
if oprnd.is_syntactic_place_expr() {
// Places may legitimately have unsized types.
// For example, dereferences of a wide pointer and
// the last field of a struct can be unsized.
ExpectHasType(*ty)
} else {
Expectation::rvalue_hint(self, *ty)
}
}
_ => NoExpectation,
}
_ => NoExpectation,
}
});
},
);
let ty =
self.check_expr_with_expectation_and_needs(oprnd, hint, Needs::maybe_mut_place(mutbl));

Expand Down Expand Up @@ -1294,7 +1297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cond_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);

let expected = orig_expected.adjust_for_branches(self);
let expected = orig_expected.adjust_for_branches(self, sp);
let then_ty = self.check_expr_with_expectation(then_expr, expected);
let then_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);
Expand All @@ -1305,7 +1308,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// `expected` if it represents a *hard* constraint
// (`only_has_type`); otherwise, we just go with a
// fresh type variable.
let coerce_to_ty = expected.coercion_target_type(self, sp);
let coerce_to_ty = expected
.structurally_resolve_hard_expectation(self, sp)
.unwrap_or_else(|| self.next_ty_var(sp));
let mut coerce: DynamicCoerceMany<'_> = CoerceMany::new(coerce_to_ty);

coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
Expand All @@ -1315,7 +1320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let else_diverges = self.diverges.get();

let tail_defines_return_position_impl_trait =
self.return_position_impl_trait_from_match_expectation(orig_expected);
self.return_position_impl_trait_from_match_expectation(orig_expected, sp);
let if_cause = self.if_cause(
sp,
cond_expr.span,
Expand Down Expand Up @@ -1355,8 +1360,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rhs: &'tcx hir::Expr<'tcx>,
span: Span,
) -> Ty<'tcx> {
let expected_ty = expected.coercion_target_type(self, expr.span);
if expected_ty == self.tcx.types.bool {
let expected_ty = expected.structurally_resolve_hard_expectation(self, expr.span);
if expected_ty == Some(self.tcx.types.bool) {
let guar = self.expr_assign_expected_bool_error(expr, lhs, rhs, span);
return Ty::new_error(self.tcx, guar);
}
Expand Down Expand Up @@ -1522,7 +1527,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let coerce = match source {
// you can only use break with a value from a normal `loop { }`
hir::LoopSource::Loop => {
let coerce_to = expected.coercion_target_type(self, body.span);
let coerce_to = expected
.structurally_resolve_hard_expectation(self, body.span)
.unwrap_or_else(|| self.next_ty_var(body.span));
Some(CoerceMany::new(coerce_to))
}

Expand Down Expand Up @@ -1639,7 +1646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let element_ty = if !args.is_empty() {
let coerce_to = expected
.to_option(self)
.structurally_resolve(self, expr.span)
.and_then(|uty| match *uty.kind() {
ty::Array(ty, _) | ty::Slice(ty) => Some(ty),
_ => None,
Expand Down Expand Up @@ -1824,13 +1831,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let flds = expected.only_has_type(self).and_then(|ty| {
let ty = self.try_structurally_resolve_type(expr.span, ty);
match ty.kind() {
let flds =
expected.structurally_resolve_hard_expectation(self, expr.span).and_then(|ty| match ty
.kind()
{
ty::Tuple(flds) => Some(&flds[..]),
_ => None,
}
});
});

let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
Some(fs) if i < fs.len() => {
Expand Down Expand Up @@ -1904,17 +1911,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;

let adt_ty = self.try_structurally_resolve_type(span, adt_ty);
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
self.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);
ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}
Ok(self.resolve_vars_if_possible(adt_ty))
})
.ok()
});
let adt_ty_hint =
expected.structurally_resolve_hard_expectation(self, expr.span).and_then(|expected| {
self.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);
ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
if !ocx.select_where_possible().is_empty() {
return Err(TypeError::Mismatch);
}
Ok(self.resolve_vars_if_possible(adt_ty))
})
.ok()
});
if let Some(adt_ty_hint) = adt_ty_hint {
// re-link the variables that the fudging above can create.
self.demand_eqtype(span, adt_ty_hint, adt_ty);
Expand Down Expand Up @@ -2682,7 +2690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base_ty,
field,
did,
expected.only_has_type(self),
expected.structurally_resolve_hard_expectation(self, expr.span),
);
return Ty::new_error(self.tcx(), guar);
}
Expand All @@ -2693,7 +2701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
field,
base_ty,
expr.hir_id,
expected.only_has_type(self),
expected.structurally_resolve_hard_expectation(self, expr.span),
) {
self.ban_take_value_of_method(expr, base_ty, field)
} else if !base_ty.is_primitive_ty() {
Expand Down
Loading

0 comments on commit 83a6b38

Please sign in to comment.