Suggest fn call on pattern type mismatch
This commit is contained in:
parent
d1ac43a9b9
commit
0eba2f3c16
@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// #55810: Type check patterns first so we get types for all bindings.
|
// #55810: Type check patterns first so we get types for all bindings.
|
||||||
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
|
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), true);
|
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now typecheck the blocks.
|
// Now typecheck the blocks.
|
||||||
|
@ -90,7 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||||
// Check the pattern.
|
// Check the pattern.
|
||||||
let ty_span = try { inputs_hir?.get(idx)?.span };
|
let ty_span = try { inputs_hir?.get(idx)?.span };
|
||||||
fcx.check_pat_top(¶m.pat, param_ty, ty_span, false);
|
fcx.check_pat_top(¶m.pat, param_ty, ty_span, None);
|
||||||
|
|
||||||
// Check that argument is Sized.
|
// Check that argument is Sized.
|
||||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||||
|
@ -1330,11 +1330,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
// Does the expected pattern type originate from an expression and what is the span?
|
// Does the expected pattern type originate from an expression and what is the span?
|
||||||
let (origin_expr, ty_span) = match (decl.ty, decl.init) {
|
let (origin_expr, ty_span) = match (decl.ty, decl.init) {
|
||||||
(Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
|
(Some(ty), _) => (None, Some(ty.span)), // Bias towards the explicit user type.
|
||||||
(_, Some(init)) => {
|
(_, Some(init)) => {
|
||||||
(true, Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
|
(Some(init), Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
|
||||||
} // No explicit type; so use the scrutinee.
|
} // No explicit type; so use the scrutinee.
|
||||||
_ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
|
_ => (None, None), // We have `let $pat;`, so the expected type is unconstrained.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type check the pattern. Override if necessary to avoid knock-on errors.
|
// Type check the pattern. Override if necessary to avoid knock-on errors.
|
||||||
|
@ -46,7 +46,7 @@ struct TopInfo<'tcx> {
|
|||||||
/// Was the origin of the `span` from a scrutinee expression?
|
/// Was the origin of the `span` from a scrutinee expression?
|
||||||
///
|
///
|
||||||
/// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter.
|
/// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter.
|
||||||
origin_expr: bool,
|
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
/// The span giving rise to the `expected` type, if one could be provided.
|
/// The span giving rise to the `expected` type, if one could be provided.
|
||||||
///
|
///
|
||||||
/// If `origin_expr` is `true`, then this is the span of the scrutinee as in:
|
/// If `origin_expr` is `true`, then this is the span of the scrutinee as in:
|
||||||
@ -74,7 +74,8 @@ struct TopInfo<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
||||||
let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
|
let code =
|
||||||
|
Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() };
|
||||||
self.cause(cause_span, code)
|
self.cause(cause_span, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||||||
actual: Ty<'tcx>,
|
actual: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: TopInfo<'tcx>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||||
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
|
let mut diag =
|
||||||
|
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
|
||||||
|
if let Some(expr) = ti.origin_expr {
|
||||||
|
self.suggest_fn_call(&mut diag, expr, expected, |output| {
|
||||||
|
self.can_eq(self.param_env, output, actual).is_ok()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(diag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demand_eqtype_pat(
|
fn demand_eqtype_pat(
|
||||||
@ -127,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
pat: &'tcx Pat<'tcx>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
origin_expr: bool,
|
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span };
|
||||||
self.check_pat(pat, expected, INITIAL_BM, info);
|
self.check_pat(pat, expected, INITIAL_BM, info);
|
||||||
@ -2146,7 +2154,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
err.help("the semantics of slice patterns changed recently; see issue #62254");
|
||||||
} else if self.autoderef(span, expected_ty)
|
} else if self.autoderef(span, expected_ty)
|
||||||
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
|
||||||
&& let (Some(span), true) = (ti.span, ti.origin_expr)
|
&& let Some(span) = ti.span
|
||||||
|
&& let Some(_) = ti.origin_expr
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||||
{
|
{
|
||||||
let ty = self.resolve_vars_if_possible(ti.expected);
|
let ty = self.resolve_vars_if_possible(ti.expected);
|
||||||
|
16
tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
Normal file
16
tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
enum E {
|
||||||
|
One(i32, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let var = E::One;
|
||||||
|
if let E::One(var1, var2) = var {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP use parentheses to construct this tuple variant
|
||||||
|
println!("{var1} {var2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(x) = Some;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP use parentheses to construct this tuple variant
|
||||||
|
}
|
33
tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
Normal file
33
tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/suggest-call-on-pat-mismatch.rs:7:12
|
||||||
|
|
|
||||||
|
LL | if let E::One(var1, var2) = var {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ --- this expression has type `fn(i32, i32) -> E {E::One}`
|
||||||
|
| |
|
||||||
|
| expected enum constructor, found `E`
|
||||||
|
|
|
||||||
|
= note: expected enum constructor `fn(i32, i32) -> E {E::One}`
|
||||||
|
found enum `E`
|
||||||
|
help: use parentheses to construct this tuple variant
|
||||||
|
|
|
||||||
|
LL | if let E::One(var1, var2) = var(/* i32 */, /* i32 */) {
|
||||||
|
| ++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/suggest-call-on-pat-mismatch.rs:13:9
|
||||||
|
|
|
||||||
|
LL | let Some(x) = Some;
|
||||||
|
| ^^^^^^^ ---- this expression has type `fn(_) -> Option<_> {Option::<_>::Some}`
|
||||||
|
| |
|
||||||
|
| expected enum constructor, found `Option<_>`
|
||||||
|
|
|
||||||
|
= note: expected enum constructor `fn(_) -> Option<_> {Option::<_>::Some}`
|
||||||
|
found enum `Option<_>`
|
||||||
|
help: use parentheses to construct this tuple variant
|
||||||
|
|
|
||||||
|
LL | let Some(x) = Some(/* value */);
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user