-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid ICES after reporting errors on erroneous patterns #126320
Changes from all commits
2733b8a
a621701
ece3e3e
e8d6170
7566307
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag}; | |
use rustc_hir as hir; | ||
use rustc_hir::def::Res; | ||
use rustc_hir::intravisit::Visitor; | ||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; | ||
use rustc_infer::infer::DefineOpaqueTypes; | ||
use rustc_middle::bug; | ||
use rustc_middle::ty::adjustment::AllowTwoPhase; | ||
use rustc_middle::ty::error::{ExpectedFound, TypeError}; | ||
|
@@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
/// Requires that the two types unify, and prints an error message if | ||
/// they don't. | ||
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { | ||
if let Some(e) = self.demand_suptype_diag(sp, expected, actual) { | ||
if let Err(e) = self.demand_suptype_diag(sp, expected, actual) { | ||
e.emit(); | ||
} | ||
} | ||
|
@@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
sp: Span, | ||
expected: Ty<'tcx>, | ||
actual: Ty<'tcx>, | ||
) -> Option<Diag<'tcx>> { | ||
) -> Result<(), Diag<'tcx>> { | ||
self.demand_suptype_with_origin(&self.misc(sp), expected, actual) | ||
} | ||
|
||
|
@@ -186,18 +186,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
cause: &ObligationCause<'tcx>, | ||
expected: Ty<'tcx>, | ||
actual: Ty<'tcx>, | ||
) -> Option<Diag<'tcx>> { | ||
match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { | ||
Ok(InferOk { obligations, value: () }) => { | ||
self.register_predicates(obligations); | ||
None | ||
} | ||
Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), | ||
} | ||
) -> Result<(), Diag<'tcx>> { | ||
self.at(cause, self.param_env) | ||
.sup(DefineOpaqueTypes::Yes, expected, actual) | ||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) | ||
.map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) | ||
} | ||
|
||
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { | ||
if let Some(err) = self.demand_eqtype_diag(sp, expected, actual) { | ||
if let Err(err) = self.demand_eqtype_diag(sp, expected, actual) { | ||
err.emit(); | ||
} | ||
} | ||
|
@@ -207,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
sp: Span, | ||
expected: Ty<'tcx>, | ||
actual: Ty<'tcx>, | ||
) -> Option<Diag<'tcx>> { | ||
) -> Result<(), Diag<'tcx>> { | ||
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) | ||
} | ||
|
||
|
@@ -216,14 +213,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
cause: &ObligationCause<'tcx>, | ||
expected: Ty<'tcx>, | ||
actual: Ty<'tcx>, | ||
) -> Option<Diag<'tcx>> { | ||
match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { | ||
Ok(InferOk { obligations, value: () }) => { | ||
self.register_predicates(obligations); | ||
None | ||
} | ||
Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), | ||
} | ||
) -> Result<(), Diag<'tcx>> { | ||
self.at(cause, self.param_env) | ||
.eq(DefineOpaqueTypes::Yes, expected, actual) | ||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) | ||
.map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) | ||
} | ||
|
||
pub fn demand_coerce( | ||
|
@@ -234,12 +228,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, | ||
allow_two_phase: AllowTwoPhase, | ||
) -> Ty<'tcx> { | ||
let (ty, err) = | ||
self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); | ||
if let Some(err) = err { | ||
err.emit(); | ||
match self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase) | ||
{ | ||
Ok(ty) => ty, | ||
Err(err) => { | ||
err.emit(); | ||
// Return the original type instead of an error type here, otherwise the type of `x` in | ||
// `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not | ||
// report errors, even though `x` is definitely `u32`. | ||
expected | ||
} | ||
} | ||
ty | ||
} | ||
|
||
/// Checks that the type of `expr` can be coerced to `expected`. | ||
|
@@ -254,11 +253,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
expected: Ty<'tcx>, | ||
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, | ||
allow_two_phase: AllowTwoPhase, | ||
) -> (Ty<'tcx>, Option<Diag<'tcx>>) { | ||
) -> Result<Ty<'tcx>, Diag<'tcx>> { | ||
let expected = self.resolve_vars_with_obligations(expected); | ||
|
||
let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { | ||
Ok(ty) => return (ty, None), | ||
Ok(ty) => return Ok(ty), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, we didn't emit the error initially, so I didn't change it, good catch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah nevermind, we're not actually emitting the error here, we're just creating the diagnostic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those functions don't have a great name, but that's a very common pattern throughout rustc. Maybe we should add an internal lint for methods with |
||
Err(e) => e, | ||
}; | ||
|
||
|
@@ -275,7 +274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
|
||
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e)); | ||
|
||
(expected, Some(err)) | ||
Err(err) | ||
} | ||
|
||
/// Notes the point at which a variable is constrained to some type incompatible | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting that we return
expected
instead ofTy::new_error
here 🤔 if someone wants to experiment with this, try changing it and run our UI test suite.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did have that, the result is not great. I should document it here