Rollup merge of #112537 - compiler-errors:dont-record-adjustments-twice, r=cjgillot

Don't record adjustments twice in `note_source_of_type_mismatch_constraint`

We call `lookup_method` a few times in `note_source_of_type_mismatch_constraint`, but that function has side-effects to the typeck results. Replace it with a less side-effect-y variant of the function for use in diagnostics.

Specifically the ICE in #112532 happens because we're recording deref adjustments twice for a call receiver, which causes `ExprUseVisitor` to be angry.

Fixes #112532
This commit is contained in:
Michael Goulet 2023-06-18 13:17:05 -07:00 committed by GitHub
commit 90e51f110c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 7 deletions

View File

@ -370,13 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Fudge the receiver, so we can do new inference on it.
let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
let method = self
.lookup_method(
.lookup_method_for_diagnostic(
possible_rcvr_ty,
segment,
DUMMY_SP,
call_expr,
binding,
args,
)
.ok()?;
// Unify the method signature with our incompatible arg, to
@ -435,14 +434,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let Ok(method) =
self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
else {
continue;
};
let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
let ideal_method = self
.lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args)
.lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
.ok()
.and_then(|method| {
let _ = self.at(&ObligationCause::dummy(), self.param_env)

View File

@ -26,6 +26,7 @@ struct ConfirmContext<'a, 'tcx> {
span: Span,
self_expr: &'tcx hir::Expr<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
skip_record_for_diagnostics: bool,
}
impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> {
@ -59,6 +60,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
confirm_cx.confirm(unadjusted_self_ty, pick, segment)
}
pub fn confirm_method_for_diagnostic(
&self,
span: Span,
self_expr: &'tcx hir::Expr<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
unadjusted_self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>,
segment: &hir::PathSegment<'_>,
) -> ConfirmResult<'tcx> {
let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr);
confirm_cx.skip_record_for_diagnostics = true;
confirm_cx.confirm(unadjusted_self_ty, pick, segment)
}
}
impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
@ -68,7 +83,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_expr: &'tcx hir::Expr<'tcx>,
call_expr: &'tcx hir::Expr<'tcx>,
) -> ConfirmContext<'a, 'tcx> {
ConfirmContext { fcx, span, self_expr, call_expr }
ConfirmContext { fcx, span, self_expr, call_expr, skip_record_for_diagnostics: false }
}
fn confirm(
@ -219,7 +234,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.register_predicates(autoderef.into_obligations());
// Write out the final adjustments.
self.apply_adjustments(self.self_expr, adjustments);
if !self.skip_record_for_diagnostics {
self.apply_adjustments(self.self_expr, adjustments);
}
target
}
@ -453,7 +470,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
});
debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
if !self.skip_record_for_diagnostics {
self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
}
}
self.normalize(self.span, substs)

View File

@ -254,6 +254,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(result.callee)
}
pub fn lookup_method_for_diagnostic(
&self,
self_ty: Ty<'tcx>,
segment: &hir::PathSegment<'_>,
span: Span,
call_expr: &'tcx hir::Expr<'tcx>,
self_expr: &'tcx hir::Expr<'tcx>,
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
let pick = self.lookup_probe_for_diagnostic(
segment.ident,
self_ty,
call_expr,
ProbeScope::TraitsInScope,
None,
)?;
Ok(self
.confirm_method_for_diagnostic(span, self_expr, call_expr, self_ty, &pick, segment)
.callee)
}
#[instrument(level = "debug", skip(self, call_expr))]
pub fn lookup_probe(
&self,

View File

@ -0,0 +1,29 @@
pub trait NSWindow: Sized {
fn frame(self) -> () {
unimplemented!()
}
fn setFrame_display_(self, display: ()) {}
}
impl NSWindow for () {}
pub struct NSRect {}
use std::ops::Deref;
struct MainThreadSafe<T = ()>(T);
impl<T> Deref for MainThreadSafe<T> {
type Target = T;
fn deref(&self) -> &T {
unimplemented!()
}
}
fn main() {
|| {
let ns_window = MainThreadSafe(());
// Don't record adjustments twice for `*ns_window`
(*ns_window).frame();
ns_window.setFrame_display_(0);
//~^ ERROR mismatched types
};
}

View File

@ -0,0 +1,17 @@
error[E0308]: mismatched types
--> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:26:37
|
LL | ns_window.setFrame_display_(0);
| ----------------- ^ expected `()`, found integer
| |
| arguments to this method are incorrect
|
note: method defined here
--> $DIR/dont-record-adjustments-when-pointing-at-arg.rs:5:8
|
LL | fn setFrame_display_(self, display: ()) {}
| ^^^^^^^^^^^^^^^^^ -----------
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.