Skip to content

Commit 31a5381

Browse files
authored
Unrolled build for rust-lang#131751
Rollup merge of rust-lang#131751 - compiler-errors:structurally-resolve, r=lcnr Rename `can_coerce` to `may_coerce`, and then structurally resolve correctly in the probe We need to structurally resolve the lhs and rhs of the coercion. Also, renaming the method so it's less ambiguous about what it's doing... the word "may" gives more clear signal that it has false positives imo. r? lcnr
2 parents 7342830 + 9070aba commit 31a5381

File tree

11 files changed

+121
-57
lines changed

11 files changed

+121
-57
lines changed

compiler/rustc_hir_typeck/src/_match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
235235
Some(ret_coercion) => {
236236
let ret_ty = ret_coercion.borrow().expected_ty();
237237
let ret_ty = self.infcx.shallow_resolve(ret_ty);
238-
self.can_coerce(arm_ty, ret_ty)
239-
&& prior_arm.is_none_or(|(_, ty, _)| self.can_coerce(ty, ret_ty))
238+
self.may_coerce(arm_ty, ret_ty)
239+
&& prior_arm.is_none_or(|(_, ty, _)| self.may_coerce(ty, ret_ty))
240240
// The match arms need to unify for the case of `impl Trait`.
241241
&& !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..))
242242
}

compiler/rustc_hir_typeck/src/cast.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
409409
let mut sugg_mutref = false;
410410
if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
411411
if let ty::RawPtr(expr_ty, _) = *self.expr_ty.kind()
412-
&& fcx.can_coerce(
412+
&& fcx.may_coerce(
413413
Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, expr_ty, mutbl),
414414
self.cast_ty,
415415
)
@@ -418,22 +418,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
418418
} else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
419419
&& expr_mutbl == Mutability::Not
420420
&& mutbl == Mutability::Mut
421-
&& fcx.can_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty)
421+
&& fcx.may_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty)
422422
{
423423
sugg_mutref = true;
424424
}
425425

426426
if !sugg_mutref
427427
&& sugg == None
428-
&& fcx.can_coerce(
428+
&& fcx.may_coerce(
429429
Ty::new_ref(fcx.tcx, reg, self.expr_ty, mutbl),
430430
self.cast_ty,
431431
)
432432
{
433433
sugg = Some((format!("&{}", mutbl.prefix_str()), false));
434434
}
435435
} else if let ty::RawPtr(_, mutbl) = *self.cast_ty.kind()
436-
&& fcx.can_coerce(
436+
&& fcx.may_coerce(
437437
Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, self.expr_ty, mutbl),
438438
self.cast_ty,
439439
)

compiler/rustc_hir_typeck/src/coercion.rs

+30-12
Original file line numberDiff line numberDiff line change
@@ -1084,24 +1084,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10841084
})
10851085
}
10861086

1087-
/// Same as `coerce()`, but without side-effects.
1087+
/// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects,
1088+
/// and may return false positives if types are not yet fully constrained by inference.
10881089
///
1089-
/// Returns false if the coercion creates any obligations that result in
1090-
/// errors.
1091-
pub(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
1092-
// FIXME(-Znext-solver): We need to structurally resolve both types here.
1093-
let source = self.resolve_vars_with_obligations(expr_ty);
1094-
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
1095-
1090+
/// Returns false if the coercion is not possible, or if the coercion creates any
1091+
/// sub-obligations that result in errors.
1092+
///
1093+
/// This should only be used for diagnostics.
1094+
pub(crate) fn may_coerce(&self, expr_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> bool {
10961095
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
10971096
// We don't ever need two-phase here since we throw out the result of the coercion.
10981097
// We also just always set `coerce_never` to true, since this is a heuristic.
1099-
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
1098+
let coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
11001099
self.probe(|_| {
1101-
let Ok(ok) = coerce.coerce(source, target) else {
1100+
// Make sure to structurally resolve the types, since we use
1101+
// the `TyKind`s heavily in coercion.
1102+
let ocx = ObligationCtxt::new(self);
1103+
let structurally_resolve = |ty| {
1104+
let ty = self.shallow_resolve(ty);
1105+
if self.next_trait_solver()
1106+
&& let ty::Alias(..) = ty.kind()
1107+
{
1108+
ocx.structurally_normalize(&cause, self.param_env, ty)
1109+
} else {
1110+
Ok(ty)
1111+
}
1112+
};
1113+
let Ok(expr_ty) = structurally_resolve(expr_ty) else {
1114+
return false;
1115+
};
1116+
let Ok(target_ty) = structurally_resolve(target_ty) else {
1117+
return false;
1118+
};
1119+
1120+
let Ok(ok) = coerce.coerce(expr_ty, target_ty) else {
11021121
return false;
11031122
};
1104-
let ocx = ObligationCtxt::new(self);
11051123
ocx.register_obligations(ok.obligations);
11061124
ocx.select_where_possible().is_empty()
11071125
})
@@ -1370,7 +1388,7 @@ pub fn can_coerce<'tcx>(
13701388
) -> bool {
13711389
let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id);
13721390
let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id);
1373-
fn_ctxt.can_coerce(ty, output_ty)
1391+
fn_ctxt.may_coerce(ty, output_ty)
13741392
}
13751393

13761394
/// CoerceMany encapsulates the pattern you should use when you have

compiler/rustc_hir_typeck/src/expr.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1330,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13301330
let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| {
13311331
let lhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, lhs.peel_refs());
13321332
let rhs = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rhs.peel_refs());
1333-
self.can_coerce(rhs, lhs)
1333+
self.may_coerce(rhs, lhs)
13341334
};
1335-
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
1335+
let (applicability, eq) = if self.may_coerce(rhs_ty, lhs_ty) {
13361336
(Applicability::MachineApplicable, true)
13371337
} else if refs_can_coerce(rhs_ty, lhs_ty) {
13381338
// The lhs and rhs are likely missing some references in either side. Subsequent
@@ -1349,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13491349
let actual_lhs_ty = self.check_expr(rhs_expr);
13501350
(
13511351
Applicability::MaybeIncorrect,
1352-
self.can_coerce(rhs_ty, actual_lhs_ty)
1352+
self.may_coerce(rhs_ty, actual_lhs_ty)
13531353
|| refs_can_coerce(rhs_ty, actual_lhs_ty),
13541354
)
13551355
} else if let ExprKind::Binary(
@@ -1363,7 +1363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13631363
let actual_rhs_ty = self.check_expr(lhs_expr);
13641364
(
13651365
Applicability::MaybeIncorrect,
1366-
self.can_coerce(actual_rhs_ty, lhs_ty)
1366+
self.may_coerce(actual_rhs_ty, lhs_ty)
13671367
|| refs_can_coerce(actual_rhs_ty, lhs_ty),
13681368
)
13691369
} else {
@@ -1414,7 +1414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14141414
self.param_env,
14151415
)
14161416
.may_apply();
1417-
if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
1417+
if lhs_deref_ty_is_sized && self.may_coerce(rhs_ty, lhs_deref_ty) {
14181418
err.span_suggestion_verbose(
14191419
lhs.span.shrink_to_lo(),
14201420
"consider dereferencing here to assign to the mutably borrowed value",

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
658658
&& fn_sig.inputs()[1..]
659659
.iter()
660660
.zip(input_types.iter())
661-
.all(|(expected, found)| self.can_coerce(*expected, *found))
661+
.all(|(expected, found)| self.may_coerce(*expected, *found))
662662
&& fn_sig.inputs()[1..].len() == input_types.len()
663663
{
664664
err.span_suggestion_verbose(
@@ -722,7 +722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
722722

723723
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
724724
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
725-
let can_coerce = self.can_coerce(arg_ty, coerced_ty);
725+
let can_coerce = self.may_coerce(arg_ty, coerced_ty);
726726
if !can_coerce {
727727
return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts(
728728
ty::error::ExpectedFound::new(true, coerced_ty, arg_ty),
@@ -802,7 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
802802
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
803803
),
804804
) {
805-
if !self.can_coerce(provided_ty, *expected_ty) {
805+
if !self.may_coerce(provided_ty, *expected_ty) {
806806
satisfied = false;
807807
break;
808808
}
@@ -1023,7 +1023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10231023
std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all(
10241024
|((expected_ty, _), (provided_ty, _))| {
10251025
!provided_ty.references_error()
1026-
&& self.can_coerce(*provided_ty, *expected_ty)
1026+
&& self.may_coerce(*provided_ty, *expected_ty)
10271027
},
10281028
)
10291029
};
@@ -2124,7 +2124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21242124
let expr_ty = self.typeck_results.borrow().expr_ty(expr);
21252125
let return_ty = fn_sig.output();
21262126
if !matches!(expr.kind, hir::ExprKind::Ret(..))
2127-
&& self.can_coerce(expr_ty, return_ty)
2127+
&& self.may_coerce(expr_ty, return_ty)
21282128
{
21292129
found_semi = true;
21302130
}

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+17-17
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
261261
if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
262262
expr.kind
263263
&& let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
264-
&& self.can_coerce(recv_ty, expected)
264+
&& self.may_coerce(recv_ty, expected)
265265
&& let name = method.name.as_str()
266266
&& (name.starts_with("to_") || name.starts_with("as_") || name == "into")
267267
{
@@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
349349
return true;
350350
}
351351

352-
if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
352+
if self.suggest_fn_call(err, expr, found, |output| self.may_coerce(output, expected))
353353
&& let ty::FnDef(def_id, ..) = *found.kind()
354354
&& let Some(sp) = self.tcx.hir().span_if_local(def_id)
355355
{
@@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
568568
if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
569569
return false;
570570
}
571-
if self.can_coerce(Ty::new_box(self.tcx, found), expected) {
571+
if self.may_coerce(Ty::new_box(self.tcx, found), expected) {
572572
let suggest_boxing = match found.kind() {
573573
ty::Tuple(tuple) if tuple.is_empty() => {
574574
errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
@@ -663,7 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
663663
};
664664
match expected.kind() {
665665
ty::Adt(def, _) if Some(def.did()) == pin_did => {
666-
if self.can_coerce(pin_box_found, expected) {
666+
if self.may_coerce(pin_box_found, expected) {
667667
debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
668668
match found.kind() {
669669
ty::Adt(def, _) if def.is_box() => {
@@ -689,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
689689
}
690690
}
691691
true
692-
} else if self.can_coerce(pin_found, expected) {
692+
} else if self.may_coerce(pin_found, expected) {
693693
match found.kind() {
694694
ty::Adt(def, _) if def.is_box() => {
695695
err.help("use `Box::pin`");
@@ -701,7 +701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
701701
false
702702
}
703703
}
704-
ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => {
704+
ty::Adt(def, _) if def.is_box() && self.may_coerce(box_found, expected) => {
705705
// Check if the parent expression is a call to Pin::new. If it
706706
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
707707
// can suggest Box::pin.
@@ -884,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
884884
let ty = Binder::bind_with_vars(ty, bound_vars);
885885
let ty = self.normalize(hir_ty.span, ty);
886886
let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
887-
if self.can_coerce(expected, ty) {
887+
if self.may_coerce(expected, ty) {
888888
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
889889
span: hir_ty.span,
890890
expected,
@@ -1141,12 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11411141
ty::Asyncness::No => ty,
11421142
};
11431143
let ty = self.normalize(expr.span, ty);
1144-
self.can_coerce(found, ty)
1144+
self.may_coerce(found, ty)
11451145
}
11461146
hir::FnRetTy::DefaultReturn(_) if in_closure => {
11471147
self.ret_coercion.as_ref().map_or(false, |ret| {
11481148
let ret_ty = ret.borrow().expected_ty();
1149-
self.can_coerce(found, ret_ty)
1149+
self.may_coerce(found, ret_ty)
11501150
})
11511151
}
11521152
_ => false,
@@ -1510,7 +1510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15101510
provided_ty
15111511
};
15121512

1513-
if !self.can_coerce(expected_ty, dummy_ty) {
1513+
if !self.may_coerce(expected_ty, dummy_ty) {
15141514
return;
15151515
}
15161516
let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
@@ -1534,7 +1534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15341534
expected_ty: Ty<'tcx>,
15351535
) {
15361536
if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() {
1537-
if self.can_coerce(blk_ty, *elem_ty)
1537+
if self.may_coerce(blk_ty, *elem_ty)
15381538
&& blk.stmts.is_empty()
15391539
&& blk.rules == hir::BlockCheckMode::DefaultBlock
15401540
{
@@ -1744,7 +1744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17441744
if item_ty.has_param() {
17451745
return false;
17461746
}
1747-
if self.can_coerce(item_ty, expected_ty) {
1747+
if self.may_coerce(item_ty, expected_ty) {
17481748
err.span_suggestion_verbose(
17491749
segment.ident.span,
17501750
format!("try referring to the associated const `{capitalized_name}` instead",),
@@ -1804,7 +1804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18041804
// diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
18051805
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
18061806
// Check that we're in fact trying to clone into the expected type
1807-
&& self.can_coerce(*pointee_ty, expected_ty)
1807+
&& self.may_coerce(*pointee_ty, expected_ty)
18081808
&& let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
18091809
// And the expected type doesn't implement `Clone`
18101810
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
@@ -2022,7 +2022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20222022
} else {
20232023
return false;
20242024
};
2025-
if is_ctor || !self.can_coerce(args.type_at(0), expected) {
2025+
if is_ctor || !self.may_coerce(args.type_at(0), expected) {
20262026
return false;
20272027
}
20282028

@@ -2293,7 +2293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22932293
.then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
22942294

22952295
let sole_field_ty = sole_field.ty(self.tcx, args);
2296-
if self.can_coerce(expr_ty, sole_field_ty) {
2296+
if self.may_coerce(expr_ty, sole_field_ty) {
22972297
let variant_path =
22982298
with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
22992299
// FIXME #56861: DRYer prelude filtering
@@ -2401,7 +2401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24012401
}
24022402

24032403
let int_type = args.type_at(0);
2404-
if !self.can_coerce(expr_ty, int_type) {
2404+
if !self.may_coerce(expr_ty, int_type) {
24052405
return false;
24062406
}
24072407

@@ -2585,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25852585
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
25862586
}
25872587
};
2588-
if self.can_coerce(ref_ty, expected) {
2588+
if self.may_coerce(ref_ty, expected) {
25892589
let mut sugg_sp = sp;
25902590
if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind {
25912591
let clone_trait =

compiler/rustc_hir_typeck/src/method/suggest.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19341934
&& fn_sig.inputs()[1..]
19351935
.iter()
19361936
.zip(args.into_iter())
1937-
.all(|(expected, found)| self.can_coerce(*expected, *found))
1937+
.all(|(expected, found)| self.may_coerce(*expected, *found))
19381938
&& fn_sig.inputs()[1..].len() == args.len()
19391939
{
19401940
err.span_suggestion_verbose(
@@ -4148,7 +4148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
41484148
return false;
41494149
};
41504150

4151-
if !self.can_coerce(output, expected) {
4151+
if !self.may_coerce(output, expected) {
41524152
return false;
41534153
}
41544154

compiler/rustc_hir_typeck/src/pat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1780,7 +1780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17801780
} else if inexistent_fields.len() == 1 {
17811781
match pat_field.pat.kind {
17821782
PatKind::Lit(expr)
1783-
if !self.can_coerce(
1783+
if !self.may_coerce(
17841784
self.typeck_results.borrow().expr_ty(expr),
17851785
self.field_ty(field.span, field_def, args),
17861786
) => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ compile-flags: -Znext-solver
2+
3+
trait Mirror {
4+
type Assoc;
5+
}
6+
impl<T> Mirror for T {
7+
type Assoc = T;
8+
}
9+
10+
fn arg() -> &'static [i32; 1] { todo!() }
11+
12+
fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
13+
14+
fn main() {
15+
// Should suggest to reverse the args...
16+
// but if we don't normalize the expected, then we don't.
17+
arg_error((), || ());
18+
//~^ ERROR arguments to this function are incorrect
19+
}

0 commit comments

Comments
 (0)