Skip to content

Commit dbf856c

Browse files
committed
wip
1 parent 7754276 commit dbf856c

File tree

4 files changed

+119
-75
lines changed

4 files changed

+119
-75
lines changed

Diff for: src/librustc_typeck/check/_match.rs

+66-69
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
556556

557557
use hir::MatchSource::*;
558558
let (source_if, if_no_else) = match match_src {
559-
IfDesugar { contains_else_clause } => (true, !contains_else_clause),
560-
IfLetDesugar { contains_else_clause } => (false, !contains_else_clause),
559+
IfDesugar { contains_else_clause } |
560+
IfLetDesugar { contains_else_clause } => (true, !contains_else_clause),
561561
_ => (false, false),
562562
};
563563

@@ -590,12 +590,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
590590
let mut all_pats_diverge = Diverges::WarnedAlways;
591591
for p in &arm.pats {
592592
self.diverges.set(Diverges::Maybe);
593-
self.check_pat_walk(
594-
&p,
595-
discrim_ty,
596-
ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
597-
Some(discrim.span),
598-
);
593+
let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable);
594+
self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span));
599595
all_pats_diverge &= self.diverges.get();
600596
}
601597

@@ -637,7 +633,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
637633
let mut other_arms = vec![]; // used only for diagnostics
638634
let mut prior_arm_ty = None;
639635
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
640-
if let Some(ref g) = arm.guard {
636+
if let Some(g) = &arm.guard {
641637
self.diverges.set(pats_diverge);
642638
match g {
643639
hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
@@ -648,64 +644,44 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
648644
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
649645
all_arms_diverge &= self.diverges.get();
650646

651-
// Handle the fallback arm of a desugared if(-let) like a missing else.
652-
let is_if_fallback = if_no_else && i == arms.len() - 1 && arm_ty.is_unit();
653-
654-
let arm_span = if let hir::ExprKind::Block(ref blk, _) = arm.body.node {
655-
// Point at the block expr instead of the entire block
656-
blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
657-
} else {
658-
arm.body.span
659-
};
660-
661-
use ObligationCauseCode::*;
647+
let span = expr.span;
662648

663-
if is_if_fallback {
649+
if source_if {
664650
let then_expr = &arms[0].body;
665-
// If this `if` expr is the parent's function return expr,
666-
// the cause of the type coercion is the return type, point at it. (#25228)
667-
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, expr.span);
668-
669-
let cause = self.cause(expr.span, IfExpressionWithNoElse);
670-
assert!(arm_ty.is_unit());
671-
672-
coercion.coerce_forced_unit(self, &cause, &mut |err| {
673-
if let Some((span, msg)) = &ret_reason {
674-
err.span_label(*span, msg.as_str());
675-
} else if let ExprKind::Block(block, _) = &then_expr.node {
676-
if let Some(expr) = &block.expr {
677-
err.span_label(expr.span, "found here".to_string());
678-
}
651+
match (i, if_no_else) {
652+
(0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty),
653+
(_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion),
654+
(_, _) => {
655+
let then_ty = prior_arm_ty.unwrap();
656+
let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty);
657+
coercion.coerce(self, &cause, &arm.body, arm_ty);
679658
}
680-
err.note("`if` expressions without `else` evaluate to `()`");
681-
err.help("consider adding an `else` block that evaluates to the expected type");
682-
}, ret_reason.is_none());
659+
}
683660
} else {
684-
let cause = if source_if {
685-
match i {
686-
0 => self.misc(expr.span),
687-
_ => self.if_cause(expr, arms, prior_arm_ty.unwrap(), arm_ty),
688-
}
661+
let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.node {
662+
// Point at the block expr instead of the entire block
663+
blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
689664
} else {
690-
let cause = match i {
691-
// The reason for the first arm to fail is not that the match arms diverge,
692-
// but rather that there's a prior obligation that doesn't hold.
693-
0 => self.cause(arm_span, BlockTailExpression(arm.body.hir_id)),
694-
_ => self.cause(expr.span, MatchExpressionArm {
695-
arm_span,
696-
source: match_src,
697-
prior_arms: other_arms.clone(),
698-
last_ty: prior_arm_ty.unwrap(),
699-
discrim_hir_id: discrim.hir_id,
700-
}),
701-
};
702-
other_arms.push(arm_span);
703-
if other_arms.len() > 5 {
704-
other_arms.remove(0);
705-
}
706-
cause
665+
arm.body.span
666+
};
667+
let (span, code) = match i {
668+
// The reason for the first arm to fail is not that the match arms diverge,
669+
// but rather that there's a prior obligation that doesn't hold.
670+
0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
671+
_ => (span, ObligationCauseCode::MatchExpressionArm {
672+
arm_span,
673+
source: match_src,
674+
prior_arms: other_arms.clone(),
675+
last_ty: prior_arm_ty.unwrap(),
676+
discrim_hir_id: discrim.hir_id,
677+
}),
707678
};
679+
let cause = self.cause(span, code);
708680
coercion.coerce(self, &cause, &arm.body, arm_ty);
681+
other_arms.push(arm_span);
682+
if other_arms.len() > 5 {
683+
other_arms.remove(0);
684+
}
709685
}
710686
prior_arm_ty = Some(arm_ty);
711687
}
@@ -716,6 +692,30 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
716692
coercion.complete(self)
717693
}
718694

695+
/// Handle the fallback arm of a desugared if(-let) like a missing else.
696+
fn if_fallback_coercion(
697+
&self,
698+
span: Span,
699+
then_expr: &'gcx hir::Expr,
700+
coercion: &mut CoerceMany<'gcx, 'tcx, '_, rustc::hir::Arm>,
701+
) {
702+
// If this `if` expr is the parent's function return expr,
703+
// the cause of the type coercion is the return type, point at it. (#25228)
704+
let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
705+
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
706+
coercion.coerce_forced_unit(self, &cause, &mut |err| {
707+
if let Some((span, msg)) = &ret_reason {
708+
err.span_label(*span, msg.as_str());
709+
} else if let ExprKind::Block(block, _) = &then_expr.node {
710+
if let Some(expr) = &block.expr {
711+
err.span_label(expr.span, "found here".to_string());
712+
}
713+
}
714+
err.note("`if` expressions without `else` evaluate to `()`");
715+
err.help("consider adding an `else` block that evaluates to the expected type");
716+
}, ret_reason.is_none());
717+
}
718+
719719
fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {
720720
use hir::Node::{Block, Item};
721721

@@ -751,12 +751,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
751751

752752
fn if_cause(
753753
&self,
754-
expr: &'gcx hir::Expr,
755-
arms: &'gcx [hir::Arm],
754+
span: Span,
755+
then_expr: &'gcx hir::Expr,
756+
else_expr: &'gcx hir::Expr,
756757
then_ty: Ty<'tcx>,
757758
else_ty: Ty<'tcx>,
758759
) -> ObligationCause<'tcx> {
759-
let mut outer_sp = if self.tcx.sess.source_map().is_multiline(expr.span) {
760+
let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
760761
// The `if`/`else` isn't in one line in the output, include some context to make it
761762
// clear it is an if/else expression:
762763
// ```
@@ -770,7 +771,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
770771
// LL || };
771772
// ||_____- if and else have incompatible types
772773
// ```
773-
Some(expr.span)
774+
Some(span)
774775
} else {
775776
// The entire expression is in one line, only point at the arms
776777
// ```
@@ -782,10 +783,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
782783
None
783784
};
784785

785-
// Extract `then` & `else` parts + their types:
786-
let else_expr = &arms[1].body;
787-
let then_expr = &arms[0].body;
788-
789786
let mut remove_semicolon = None;
790787
let error_sp = if let ExprKind::Block(block, _) = &else_expr.node {
791788
if let Some(expr) = &block.expr {
@@ -823,7 +820,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
823820
// | |_____^ expected integer, found ()
824821
// ```
825822
if outer_sp.is_some() {
826-
outer_sp = Some(self.tcx.sess.source_map().def_span(expr.span));
823+
outer_sp = Some(self.tcx.sess.source_map().def_span(span));
827824
}
828825
else_expr.span
829826
}

Diff for: src/test/ui/if/if-let-arm-types.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
error[E0308]: `if let` arms have incompatible types
1+
error[E0308]: if and else have incompatible types
22
--> $DIR/if-let-arm-types.rs:6:9
33
|
44
LL | / if let Some(b) = None {
55
LL | |
66
LL | | ()
7+
| | -- expected because of this
78
LL | | } else {
89
LL | | 1
910
| | ^ expected (), found integer
1011
LL | | };
11-
| |_____- `if let` arms have incompatible types
12+
| |_____- if and else have incompatible types
1213
|
1314
= note: expected type `()`
1415
found type `{integer}`

Diff for: src/test/ui/if/if-without-else-as-fn-expr.stderr

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/if-without-else-as-fn-expr.rs:2:5
3+
|
4+
LL | / if bar % 5 == 0 {
5+
LL | | return 3;
6+
LL | | }
7+
| |_____^ expected usize, found ()
8+
|
9+
= note: expected type `usize`
10+
found type `()`
11+
112
error[E0317]: if may be missing an else clause
213
--> $DIR/if-without-else-as-fn-expr.rs:2:5
314
|
@@ -13,6 +24,18 @@ LL | | }
1324
= note: `if` expressions without `else` evaluate to `()`
1425
= help: consider adding an `else` block that evaluates to the expected type
1526

27+
error[E0308]: mismatched types
28+
--> $DIR/if-without-else-as-fn-expr.rs:9:20
29+
|
30+
LL | let x: usize = if bar % 5 == 0 {
31+
| ____________________^
32+
LL | | return 3;
33+
LL | | };
34+
| |_____^ expected usize, found ()
35+
|
36+
= note: expected type `usize`
37+
found type `()`
38+
1639
error[E0317]: if may be missing an else clause
1740
--> $DIR/if-without-else-as-fn-expr.rs:9:20
1841
|
@@ -29,6 +52,17 @@ LL | | };
2952
= note: `if` expressions without `else` evaluate to `()`
3053
= help: consider adding an `else` block that evaluates to the expected type
3154

55+
error[E0308]: mismatched types
56+
--> $DIR/if-without-else-as-fn-expr.rs:17:5
57+
|
58+
LL | / if bar % 5 == 0 {
59+
LL | | 3
60+
LL | | }
61+
| |_____^ expected usize, found ()
62+
|
63+
= note: expected type `usize`
64+
found type `()`
65+
3266
error[E0317]: if may be missing an else clause
3367
--> $DIR/if-without-else-as-fn-expr.rs:17:5
3468
|
@@ -90,6 +124,7 @@ LL | | }
90124
= note: `if` expressions without `else` evaluate to `()`
91125
= help: consider adding an `else` block that evaluates to the expected type
92126

93-
error: aborting due to 6 previous errors
127+
error: aborting due to 9 previous errors
94128

95-
For more information about this error, try `rustc --explain E0317`.
129+
Some errors occurred: E0308, E0317.
130+
For more information about an error, try `rustc --explain E0308`.

Diff for: src/test/ui/issues/issue-50577.stderr

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-50577.rs:3:16
3+
|
4+
LL | Drop = assert_eq!(1, 1)
5+
| ^^^^^^^^^^^^^^^^ expected isize, found ()
6+
|
7+
= note: expected type `isize`
8+
found type `()`
9+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
10+
111
error[E0317]: if may be missing an else clause
212
--> $DIR/issue-50577.rs:3:16
313
|
@@ -13,6 +23,7 @@ LL | Drop = assert_eq!(1, 1)
1323
= help: consider adding an `else` block that evaluates to the expected type
1424
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1525

16-
error: aborting due to previous error
26+
error: aborting due to 2 previous errors
1727

18-
For more information about this error, try `rustc --explain E0317`.
28+
Some errors occurred: E0308, E0317.
29+
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)