From 9b2890196eba62fdfec09447305e197642d1c612 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 30 Apr 2018 22:43:33 +0100 Subject: [PATCH 1/3] Remove vestigial diverging !-coercion Such conversions are no longer permitted. --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 24 +++++--------------- src/librustc_typeck/check/mod.rs | 32 +++++++++------------------ 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 7b4dc60409b12..6a76e170a6254 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -690,7 +690,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); arm_span: arm.body.span, source: match_src }); - coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get()); + coercion.coerce(self, &cause, &arm.body, arm_ty); } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8c69608a26170..770a44a9b8b8e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::{Diverges, FnCtxt, Needs}; +use check::{FnCtxt, Needs}; use rustc::hir; use rustc::hir::def_id::DefId; @@ -798,8 +798,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { exprs: &[E], prev_ty: Ty<'tcx>, new: &hir::Expr, - new_ty: Ty<'tcx>, - new_diverges: Diverges) + new_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> where E: AsCoercionSite { @@ -807,13 +806,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); - // Special-ish case: we can coerce any type `T` into the `!` - // type, but only if the source expression diverges. - if prev_ty.is_never() && new_diverges.always() { - debug!("permit coercion to `!` because expr diverges"); - return Ok(prev_ty); - } - // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) { @@ -1052,14 +1044,12 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: &'gcx hir::Expr, - expression_ty: Ty<'tcx>, - expression_diverges: Diverges) + expression_ty: Ty<'tcx>) { self.coerce_inner(fcx, cause, Some(expression), expression_ty, - expression_diverges, None, false) } @@ -1085,7 +1075,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause, None, fcx.tcx.mk_nil(), - Diverges::Maybe, Some(augment_error), label_unit_as_expected) } @@ -1098,7 +1087,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, mut expression_ty: Ty<'tcx>, - expression_diverges: Diverges, augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>, label_expression_as_expected: bool) { @@ -1132,15 +1120,13 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> exprs, self.merged_ty(), expression, - expression_ty, - expression_diverges), + expression_ty), Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub(cause, &coercion_sites[0..self.pushed], self.merged_ty(), expression, - expression_ty, - expression_diverges), + expression_ty), } } } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db859e42057e9..9c73e5a8ce7ad 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -542,7 +542,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// you get indicates whether any subexpression that was /// evaluating up to and including `X` diverged. /// - /// We use this flag for two purposes: + /// We currently use this flag only for diagnostic purposes: /// /// - To warn about unreachable code: if, after processing a /// sub-expression but before we have applied the effects of the @@ -556,16 +556,8 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// foo();}` or `{return; 22}`, where we would warn on the /// `foo()` or `22`. /// - /// - To permit assignment into a local variable or other place - /// (including the "return slot") of type `!`. This is allowed - /// if **either** the type of value being assigned is `!`, which - /// means the current code is dead, **or** the expression's - /// diverging flag is true, which means that a diverging value was - /// wrapped (e.g., `let x: ! = foo(return)`). - /// - /// To repeat the last point: an expression represents dead-code - /// if, after checking it, **either** its type is `!` OR the - /// diverges flag is set to something other than `Maybe`. + /// An expression represents dead-code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. diverges: Cell, /// Whether any child nodes have any type errors. @@ -2999,8 +2991,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.cause(return_expr.span, ObligationCauseCode::ReturnType(return_expr.id)), return_expr, - return_expr_ty, - self.diverges.get()); + return_expr_ty); } @@ -3031,13 +3022,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); - coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges); + 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(); - coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges); + coerce.coerce(self, &if_cause, else_expr, else_ty); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); @@ -3722,7 +3713,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprBreak(destination, ref expr_opt) => { if let Some(target_id) = destination.target_id.opt_id() { - let (e_ty, e_diverges, cause); + let (e_ty, cause); if let Some(ref e) = *expr_opt { // If this is a break with a value, we need to type-check // the expression. Get an expected type from the loop context. @@ -3741,13 +3732,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); - e_diverges = self.diverges.get(); cause = self.misc(e.span); } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. e_ty = tcx.mk_nil(); - e_diverges = Diverges::Maybe; cause = self.misc(expr.span); } @@ -3758,7 +3747,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ctxt = enclosing_breakables.find_breakable(target_id); if let Some(ref mut coerce) = ctxt.coerce { if let Some(ref e) = *expr_opt { - coerce.coerce(self, &cause, e, e_ty, e_diverges); + coerce.coerce(self, &cause, e, e_ty); } else { assert!(e_ty.is_nil()); coerce.coerce_forced_unit(self, &cause, &mut |_| (), true); @@ -3964,7 +3953,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); - coerce.coerce(self, &cause, e, e_ty, self.diverges.get()); + coerce.coerce(self, &cause, e, e_ty); } coerce.complete(self) } else { @@ -4375,8 +4364,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { coerce.coerce(self, &cause, tail_expr, - tail_expr_ty, - self.diverges.get()); + tail_expr_ty); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression From 5a013b2fbcd2eebc8345ccd1611e39b867b4c1f8 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 1 May 2018 00:23:34 +0100 Subject: [PATCH 2/3] Fix coerce-to-bang test This was explicitly testing the behaviour which is now no longer permitted. --- src/test/compile-fail/coerce-to-bang.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 62ff09f4616b8..4a0e31d2deb4e 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -56,9 +56,8 @@ fn call_foo_f() { } fn array_a() { - // Accepted: return is coerced to `!` just fine, and then `22` can be - // because we already diverged. - let x: [!; 2] = [return, 22]; + // Accepted: return is coerced to `!` just fine, but `22` cannot be. + let x: [!; 2] = [return, 22]; //~ ERROR mismatched types } fn array_b() { From 5489969fa18cc74d4b72077940a5c05491ec681f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 1 May 2018 12:27:09 -0400 Subject: [PATCH 3/3] Test is no longer "accepted" --- src/test/compile-fail/coerce-to-bang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 4a0e31d2deb4e..8b4e2c3c051e8 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -56,7 +56,7 @@ fn call_foo_f() { } fn array_a() { - // Accepted: return is coerced to `!` just fine, but `22` cannot be. + // Return is coerced to `!` just fine, but `22` cannot be. let x: [!; 2] = [return, 22]; //~ ERROR mismatched types }