From 7fc1685c47e316d1377e4d54393db6c18ff8a744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 6 Jan 2019 13:37:03 -0800 Subject: [PATCH 1/2] Tweak output of type mismatch between "then" and `else` `if` arms --- src/librustc/infer/error_reporting/mod.rs | 8 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/mod.rs | 5 +- src/librustc/traits/structural_impls.rs | 2 +- src/librustc_typeck/check/mod.rs | 88 +++++++++++++++++- src/test/ui/if-else-type-mismatch.rs | 34 +++++++ src/test/ui/if-else-type-mismatch.stderr | 92 +++++++++++++++++++ src/test/ui/if/if-branch-types.stderr | 6 +- ...on-invariant-static-error-reporting.stderr | 8 +- src/test/ui/str/str-array-assignment.stderr | 6 +- 10 files changed, 238 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/if-else-type-mismatch.rs create mode 100644 src/test/ui/if-else-type-mismatch.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f71cce8273c46..d61b37ef7c8f1 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -511,6 +511,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } }, + ObligationCauseCode::IfExpression { then, outer } => { + err.span_label(then, "expected because of this"); + outer.map(|sp| err.span_label(sp, "if and else have incompatible types")); + } _ => (), } } @@ -1460,7 +1464,7 @@ impl<'tcx> ObligationCause<'tcx> { } _ => "match arms have incompatible types", }), - IfExpression => Error0308("if and else have incompatible types"), + IfExpression { .. } => Error0308("if and else have incompatible types"), IfExpressionWithNoElse => Error0317("if may be missing an else clause"), MainFunctionType => Error0580("main function has wrong type"), StartFunctionType => Error0308("start function has wrong type"), @@ -1488,7 +1492,7 @@ impl<'tcx> ObligationCause<'tcx> { hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", _ => "match arms have compatible types", }, - IfExpression => "if and else have compatible types", + IfExpression { .. } => "if and else have compatible types", IfExpressionWithNoElse => "if missing an else returns ()", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`start` function has the correct type", diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7d9e80fd60f5c..367a7eacdfcaf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1445,7 +1445,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::ExprAssignable | ObligationCauseCode::MatchExpressionArm { .. } | ObligationCauseCode::MatchExpressionArmPattern { .. } | - ObligationCauseCode::IfExpression | + ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType | ObligationCauseCode::StartFunctionType | diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 14c25b77a1b82..3f3f489013cff 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -229,7 +229,10 @@ pub enum ObligationCauseCode<'tcx> { MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> }, /// Computing common supertype in an if expression - IfExpression, + IfExpression { + then: Span, + outer: Option, + }, /// Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 277e2ed0e87d2..a1dd99457d1e6 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -520,7 +520,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::MatchExpressionArmPattern { span, ty } => { tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) } - super::IfExpression => Some(super::IfExpression), + super::IfExpression { then, outer } => Some(super::IfExpression { then, outer }), super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), super::MainFunctionType => Some(super::MainFunctionType), super::StartFunctionType => Some(super::StartFunctionType), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index dbbb7f42feb24..9939c2a12b860 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3366,7 +3366,93 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce_to_ty = expected.coercion_target_type(self, sp); let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); - let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) { + // The `if`/`else` isn't in one line in the output, include some context to make it + // clear it is an if/else expression: + // ``` + // LL | let x = if true { + // | _____________- + // LL || 10i32 + // || ----- expected because of this + // LL || } else { + // LL || 10u32 + // || ^^^^^ expected i32, found u32 + // LL || }; + // ||_____- if and else have incompatible types + // ``` + Some(sp) + } else { + // The entire expression is in one line, only point at the arms + // ``` + // LL | let x = if true { 10i32 } else { 10u32 }; + // | ----- ^^^^^ expected i32, found u32 + // | | + // | expected because of this + // ``` + None + }; + let error_sp = opt_else_expr.map(|expr| { + if let ExprKind::Block(block, _) = &expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + stmt.span + } else { // empty block, point at its entirety + // Avoid overlapping spans that aren't as readable: + // ``` + // 2 | let x = if true { + // | _____________- + // 3 | | 3 + // | | - expected because of this + // 4 | | } else { + // | |____________^ + // 5 | || + // 6 | || }; + // | || ^ + // | ||_____| + // | |______if and else have incompatible types + // | expected integer, found () + // ``` + // by not pointing at the entire expression: + // ``` + // 2 | let x = if true { + // | ------- if and else have incompatible types + // 3 | 3 + // | - expected because of this + // 4 | } else { + // | ____________^ + // 5 | | + // 6 | | }; + // | |_____^ expected integer, found () + // ``` + if outer_sp.is_some() { + outer_sp = Some(self.tcx.sess.source_map().def_span(sp)); + } + expr.span + } + } else { // shouldn't happen unless the parser has done something weird + expr.span + } + }).unwrap_or(sp); // shouldn't be needed + let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + stmt.span + } else { // empty block, point at its entirety + outer_sp = None; // same as in `error_sp`, cleanup output + then_expr.span + } + } else { // shouldn't happen unless the parser has done something weird + then_expr.span + }; + + let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression { + then: then_sp, + outer: outer_sp, + }); coerce.coerce(self, &if_cause, then_expr, then_ty); if let Some(else_expr) = opt_else_expr { diff --git a/src/test/ui/if-else-type-mismatch.rs b/src/test/ui/if-else-type-mismatch.rs new file mode 100644 index 0000000000000..37955a29d2421 --- /dev/null +++ b/src/test/ui/if-else-type-mismatch.rs @@ -0,0 +1,34 @@ +fn main() { + let _ = if true { + 42i32 + } else { + 42u32 + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { 42i32 } else { 42u32 }; + //~^ ERROR if and else have incompatible types + let _ = if true { + 42i32; + } else { + 42u32 + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { + 42i32 + } else { + 42u32; + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { + + } else { + 42u32 + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { + 42i32 + } else { + + }; + //~^^^ ERROR if and else have incompatible types +} diff --git a/src/test/ui/if-else-type-mismatch.stderr b/src/test/ui/if-else-type-mismatch.stderr new file mode 100644 index 0000000000000..d20edc57cbda1 --- /dev/null +++ b/src/test/ui/if-else-type-mismatch.stderr @@ -0,0 +1,92 @@ +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:5:9 + | +LL | let _ = if true { + | _____________- +LL | | 42i32 + | | ----- expected because of this +LL | | } else { +LL | | 42u32 + | | ^^^^^ expected i32, found u32 +LL | | }; + | |_____- if and else have incompatible types + | + = note: expected type `i32` + found type `u32` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:8:38 + | +LL | let _ = if true { 42i32 } else { 42u32 }; + | ----- ^^^^^ expected i32, found u32 + | | + | expected because of this + | + = note: expected type `i32` + found type `u32` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:13:9 + | +LL | let _ = if true { + | _____________- +LL | | 42i32; + | | ------ expected because of this +LL | | } else { +LL | | 42u32 + | | ^^^^^ expected (), found u32 +LL | | }; + | |_____- if and else have incompatible types + | + = note: expected type `()` + found type `u32` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:19:9 + | +LL | let _ = if true { + | _____________- +LL | | 42i32 + | | ----- expected because of this +LL | | } else { +LL | | 42u32; + | | ^^^^^^ expected i32, found () +LL | | }; + | |_____- if and else have incompatible types + | + = note: expected type `i32` + found type `()` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:25:9 + | +LL | let _ = if true { + | _____________________- +LL | | +LL | | } else { + | |_____- expected because of this +LL | 42u32 + | ^^^^^ expected (), found u32 + | + = note: expected type `()` + found type `u32` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:30:12 + | +LL | let _ = if true { + | ------- if and else have incompatible types +LL | 42i32 + | ----- expected because of this +LL | } else { + | ____________^ +LL | | +LL | | }; + | |_____^ expected i32, found () + | + = note: expected type `i32` + found type `()` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/if/if-branch-types.stderr b/src/test/ui/if/if-branch-types.stderr index 44e172da78394..74b925f72fff0 100644 --- a/src/test/ui/if/if-branch-types.stderr +++ b/src/test/ui/if/if-branch-types.stderr @@ -1,8 +1,10 @@ error[E0308]: if and else have incompatible types - --> $DIR/if-branch-types.rs:2:13 + --> $DIR/if-branch-types.rs:2:38 | LL | let x = if true { 10i32 } else { 10u32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found u32 + | ----- ^^^^^ expected i32, found u32 + | | + | expected because of this | = note: expected type `i32` found type `u32` diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.stderr index 40a3e7e96486b..60e70ddcd9701 100644 --- a/src/test/ui/regions/region-invariant-static-error-reporting.stderr +++ b/src/test/ui/regions/region-invariant-static-error-reporting.stderr @@ -1,13 +1,15 @@ error[E0308]: if and else have incompatible types - --> $DIR/region-invariant-static-error-reporting.rs:14:15 + --> $DIR/region-invariant-static-error-reporting.rs:17:9 | LL | let bad = if x.is_some() { - | _______________^ + | _______________- LL | | x.unwrap() + | | ---------- expected because of this LL | | } else { LL | | mk_static() + | | ^^^^^^^^^^^ lifetime mismatch LL | | }; - | |_____^ lifetime mismatch + | |_____- if and else have incompatible types | = note: expected type `Invariant<'a>` found type `Invariant<'static>` diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index 24d8db481b468..87809d212d79d 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -1,8 +1,10 @@ error[E0308]: if and else have incompatible types - --> $DIR/str-array-assignment.rs:3:11 + --> $DIR/str-array-assignment.rs:3:37 | LL | let t = if true { s[..2] } else { s }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected str, found &str + | ------ ^ expected str, found &str + | | + | expected because of this | = note: expected type `str` found type `&str` From 9567544902e1a6cca1b10333b6fc929e50ec1fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 6 Jan 2019 17:21:43 -0800 Subject: [PATCH 2/2] Suggest removal of semicolon when appropriate --- src/librustc/infer/error_reporting/mod.rs | 10 +- src/librustc/traits/mod.rs | 1 + src/librustc/traits/structural_impls.rs | 6 +- src/librustc_typeck/check/mod.rs | 147 ++++++++++++---------- src/test/ui/if-else-type-mismatch.rs | 28 +++-- src/test/ui/if-else-type-mismatch.stderr | 68 +++++++--- 6 files changed, 169 insertions(+), 91 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d61b37ef7c8f1..2995b25308d4c 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -511,9 +511,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } }, - ObligationCauseCode::IfExpression { then, outer } => { + ObligationCauseCode::IfExpression { then, outer, semicolon } => { err.span_label(then, "expected because of this"); outer.map(|sp| err.span_label(sp, "if and else have incompatible types")); + if let Some(sp) = semicolon { + err.span_suggestion_short_with_applicability( + sp, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } } _ => (), } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 3f3f489013cff..68383bef37a6a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -232,6 +232,7 @@ pub enum ObligationCauseCode<'tcx> { IfExpression { then: Span, outer: Option, + semicolon: Option, }, /// Computing common supertype of an if expression with no else counter-part diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index a1dd99457d1e6..2f5df022218fe 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -520,7 +520,11 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::MatchExpressionArmPattern { span, ty } => { tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) } - super::IfExpression { then, outer } => Some(super::IfExpression { then, outer }), + super::IfExpression { then, outer, semicolon } => Some(super::IfExpression { + then, + outer, + semicolon, + }), super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), super::MainFunctionType => Some(super::MainFunctionType), super::StartFunctionType => Some(super::StartFunctionType), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9939c2a12b860..1b07385d4d1f4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3366,37 +3366,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce_to_ty = expected.coercion_target_type(self, sp); let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); - let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) { - // The `if`/`else` isn't in one line in the output, include some context to make it - // clear it is an if/else expression: - // ``` - // LL | let x = if true { - // | _____________- - // LL || 10i32 - // || ----- expected because of this - // LL || } else { - // LL || 10u32 - // || ^^^^^ expected i32, found u32 - // LL || }; - // ||_____- if and else have incompatible types - // ``` - Some(sp) - } else { - // The entire expression is in one line, only point at the arms - // ``` - // LL | let x = if true { 10i32 } else { 10u32 }; - // | ----- ^^^^^ expected i32, found u32 - // | | - // | expected because of this - // ``` - None - }; - let error_sp = opt_else_expr.map(|expr| { - if let ExprKind::Block(block, _) = &expr.node { + coerce.coerce(self, &self.misc(sp), then_expr, then_ty); + + if let Some(else_expr) = opt_else_expr { + let else_ty = self.check_expr_with_expectation(else_expr, expected); + let else_diverges = self.diverges.get(); + + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) { + // The `if`/`else` isn't in one line in the output, include some context to make it + // clear it is an if/else expression: + // ``` + // LL | let x = if true { + // | _____________- + // LL || 10i32 + // || ----- expected because of this + // LL || } else { + // LL || 10u32 + // || ^^^^^ expected i32, found u32 + // LL || }; + // ||_____- if and else have incompatible types + // ``` + Some(sp) + } else { + // The entire expression is in one line, only point at the arms + // ``` + // LL | let x = if true { 10i32 } else { 10u32 }; + // | ----- ^^^^^ expected i32, found u32 + // | | + // | expected because of this + // ``` + None + }; + let mut remove_semicolon = None; + let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { if let Some(expr) = &block.expr { expr.span } else if let Some(stmt) = block.stmts.last() { // possibly incorrect trailing `;` in the else arm + remove_semicolon = self.could_remove_semicolon(block, then_ty); stmt.span } else { // empty block, point at its entirety // Avoid overlapping spans that aren't as readable: @@ -3429,35 +3436,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if outer_sp.is_some() { outer_sp = Some(self.tcx.sess.source_map().def_span(sp)); } - expr.span + else_expr.span } } else { // shouldn't happen unless the parser has done something weird - expr.span - } - }).unwrap_or(sp); // shouldn't be needed - let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - stmt.span - } else { // empty block, point at its entirety - outer_sp = None; // same as in `error_sp`, cleanup output + else_expr.span + }; + let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + remove_semicolon = remove_semicolon.or( + self.could_remove_semicolon(block, else_ty)); + stmt.span + } else { // empty block, point at its entirety + outer_sp = None; // same as in `error_sp`, cleanup output + then_expr.span + } + } else { // shouldn't happen unless the parser has done something weird then_expr.span - } - } else { // shouldn't happen unless the parser has done something weird - then_expr.span - }; - - let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression { - then: then_sp, - outer: outer_sp, - }); - coerce.coerce(self, &if_cause, then_expr, then_ty); + }; - if let Some(else_expr) = opt_else_expr { - let else_ty = self.check_expr_with_expectation(else_expr, expected); - let else_diverges = self.diverges.get(); + let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression { + then: then_sp, + outer: outer_sp, + semicolon: remove_semicolon, + }); coerce.coerce(self, &if_cause, else_expr, else_ty); @@ -5230,7 +5234,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// A common error is to add an extra semicolon: /// /// ``` @@ -5242,31 +5245,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This routine checks if the final statement in a block is an /// expression with an explicit semicolon whose type is compatible /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon(&self, - blk: &'gcx hir::Block, - expected_ty: Ty<'tcx>, - err: &mut DiagnosticBuilder) { + fn consider_hint_about_removing_semicolon( + &self, + blk: &'gcx hir::Block, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder, + ) { + if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { + err.span_suggestion_with_applicability( + span_semi, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn could_remove_semicolon( + &self, + blk: &'gcx hir::Block, + expected_ty: Ty<'tcx>, + ) -> Option { // Be helpful when the user wrote `{... expr;}` and // taking the `;` off is enough to fix the error. let last_stmt = match blk.stmts.last() { Some(s) => s, - None => return, + None => return None, }; let last_expr = match last_stmt.node { hir::StmtKind::Semi(ref e, _) => e, - _ => return, + _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { - return; + return None; } let original_span = original_sp(last_stmt.span, blk.span); - let span_semi = original_span.with_lo(original_span.hi() - BytePos(1)); - err.span_suggestion_with_applicability( - span_semi, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable); + Some(original_span.with_lo(original_span.hi() - BytePos(1))) } // Instantiates the given path, which must refer to an item with the given diff --git a/src/test/ui/if-else-type-mismatch.rs b/src/test/ui/if-else-type-mismatch.rs index 37955a29d2421..583c3d0b765cf 100644 --- a/src/test/ui/if-else-type-mismatch.rs +++ b/src/test/ui/if-else-type-mismatch.rs @@ -1,32 +1,44 @@ fn main() { let _ = if true { - 42i32 + 1i32 } else { - 42u32 + 2u32 }; //~^^ ERROR if and else have incompatible types let _ = if true { 42i32 } else { 42u32 }; //~^ ERROR if and else have incompatible types let _ = if true { - 42i32; + 3u32; } else { - 42u32 + 4u32 }; //~^^ ERROR if and else have incompatible types let _ = if true { - 42i32 + 5u32 } else { - 42u32; + 6u32; + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { + 7i32; + } else { + 8u32 + }; + //~^^ ERROR if and else have incompatible types + let _ = if true { + 9i32 + } else { + 10u32; }; //~^^ ERROR if and else have incompatible types let _ = if true { } else { - 42u32 + 11u32 }; //~^^ ERROR if and else have incompatible types let _ = if true { - 42i32 + 12i32 } else { }; diff --git a/src/test/ui/if-else-type-mismatch.stderr b/src/test/ui/if-else-type-mismatch.stderr index d20edc57cbda1..b418c961189d6 100644 --- a/src/test/ui/if-else-type-mismatch.stderr +++ b/src/test/ui/if-else-type-mismatch.stderr @@ -3,11 +3,11 @@ error[E0308]: if and else have incompatible types | LL | let _ = if true { | _____________- -LL | | 42i32 - | | ----- expected because of this +LL | | 1i32 + | | ---- expected because of this LL | | } else { -LL | | 42u32 - | | ^^^^^ expected i32, found u32 +LL | | 2u32 + | | ^^^^ expected i32, found u32 LL | | }; | |_____- if and else have incompatible types | @@ -30,11 +30,14 @@ error[E0308]: if and else have incompatible types | LL | let _ = if true { | _____________- -LL | | 42i32; - | | ------ expected because of this +LL | | 3u32; + | | ----- + | | | | + | | | help: consider removing this semicolon + | | expected because of this LL | | } else { -LL | | 42u32 - | | ^^^^^ expected (), found u32 +LL | | 4u32 + | | ^^^^ expected (), found u32 LL | | }; | |_____- if and else have incompatible types | @@ -46,10 +49,45 @@ error[E0308]: if and else have incompatible types | LL | let _ = if true { | _____________- -LL | | 42i32 +LL | | 5u32 + | | ---- expected because of this +LL | | } else { +LL | | 6u32; + | | ^^^^- + | | | | + | | | help: consider removing this semicolon + | | expected u32, found () +LL | | }; + | |_____- if and else have incompatible types + | + = note: expected type `u32` + found type `()` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:25:9 + | +LL | let _ = if true { + | _____________- +LL | | 7i32; | | ----- expected because of this LL | | } else { -LL | | 42u32; +LL | | 8u32 + | | ^^^^ expected (), found u32 +LL | | }; + | |_____- if and else have incompatible types + | + = note: expected type `()` + found type `u32` + +error[E0308]: if and else have incompatible types + --> $DIR/if-else-type-mismatch.rs:31:9 + | +LL | let _ = if true { + | _____________- +LL | | 9i32 + | | ---- expected because of this +LL | | } else { +LL | | 10u32; | | ^^^^^^ expected i32, found () LL | | }; | |_____- if and else have incompatible types @@ -58,25 +96,25 @@ LL | | }; found type `()` error[E0308]: if and else have incompatible types - --> $DIR/if-else-type-mismatch.rs:25:9 + --> $DIR/if-else-type-mismatch.rs:37:9 | LL | let _ = if true { | _____________________- LL | | LL | | } else { | |_____- expected because of this -LL | 42u32 +LL | 11u32 | ^^^^^ expected (), found u32 | = note: expected type `()` found type `u32` error[E0308]: if and else have incompatible types - --> $DIR/if-else-type-mismatch.rs:30:12 + --> $DIR/if-else-type-mismatch.rs:42:12 | LL | let _ = if true { | ------- if and else have incompatible types -LL | 42i32 +LL | 12i32 | ----- expected because of this LL | } else { | ____________^ @@ -87,6 +125,6 @@ LL | | }; = note: expected type `i32` found type `()` -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0308`.