]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_typeck/check/coercion.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_typeck / check / coercion.rs
index f79351dc903106cd1d89d6edd0a5119253e078f4..726b3ba985778c2b2b08917c0a7ad3e09d20458a 100644 (file)
@@ -73,6 +73,8 @@ use syntax::symbol::sym;
 use syntax_pos;
 use rustc_target::spec::abi::Abi;
 
+use rustc_error_codes::*;
+
 struct Coerce<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     cause: ObligationCause<'tcx>,
@@ -99,10 +101,10 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                        to_mutbl: hir::Mutability)
                        -> RelateResult<'tcx, ()> {
     match (from_mutbl, to_mutbl) {
-        (hir::MutMutable, hir::MutMutable) |
-        (hir::MutImmutable, hir::MutImmutable) |
-        (hir::MutMutable, hir::MutImmutable) => Ok(()),
-        (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability),
+        (hir::Mutability::Mutable, hir::Mutability::Mutable) |
+        (hir::Mutability::Immutable, hir::Mutability::Immutable) |
+        (hir::Mutability::Mutable, hir::Mutability::Immutable) => Ok(()),
+        (hir::Mutability::Immutable, hir::Mutability::Mutable) => Err(TypeError::Mutability),
     }
 }
 
@@ -410,7 +412,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
         };
 
-        if ty == a && mt_a.mutbl == hir::MutImmutable && autoderef.step_count() == 1 {
+        if ty == a && mt_a.mutbl == hir::Mutability::Immutable && autoderef.step_count() == 1 {
             // As a special case, if we would produce `&'a *x`, that's
             // a total no-op. We end up with the type `&'a T` just as
             // we started with.  In that case, just skip it
@@ -422,7 +424,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             // `self.x` both have `&mut `type would be a move of
             // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
             // which is a borrow.
-            assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
+            assert_eq!(mt_b.mutbl, hir::Mutability::Immutable); // can only coerce &T -> &U
             return success(vec![], ty, obligations);
         }
 
@@ -439,8 +441,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             _ => span_bug!(span, "expected a ref type, got {:?}", ty),
         };
         let mutbl = match mt_b.mutbl {
-            hir::MutImmutable => AutoBorrowMutability::Immutable,
-            hir::MutMutable => AutoBorrowMutability::Mutable {
+            hir::Mutability::Immutable => AutoBorrowMutability::Immutable,
+            hir::Mutability::Mutable => AutoBorrowMutability::Mutable {
                 allow_two_phase_borrow: self.allow_two_phase,
             }
         };
@@ -485,8 +487,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 let coercion = Coercion(self.cause.span);
                 let r_borrow = self.next_region_var(coercion);
                 let mutbl = match mutbl_b {
-                    hir::MutImmutable => AutoBorrowMutability::Immutable,
-                    hir::MutMutable => AutoBorrowMutability::Mutable {
+                    hir::Mutability::Immutable => AutoBorrowMutability::Immutable,
+                    hir::Mutability::Mutable => AutoBorrowMutability::Mutable {
                         // We don't allow two-phase borrows here, at least for initial
                         // implementation. If it happens that this coercion is a function argument,
                         // the reborrow in coerce_borrowed_ptr will pick it up.
@@ -642,11 +644,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         }
 
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
-            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           sym::unsized_tuple_coercion,
-                                           self.cause.span,
-                                           feature_gate::GateIssue::Language,
-                                           feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
+            feature_gate::feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::unsized_tuple_coercion,
+                self.cause.span,
+                "unsized tuple coercion is not stable enough for use and is subject to change",
+            )
+            .emit();
         }
 
         Ok(coercion)
@@ -1280,9 +1284,25 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     augment_error(&mut err);
                 }
 
+                if let Some(expr) = expression {
+                    fcx.emit_coerce_suggestions(&mut err, expr, found, expected);
+                }
+
                 // Error possibly reported in `check_assign` so avoid emitting error again.
-                err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
-                    .is_some());
+                let assign_to_bool = expression
+                    // #67273: Use initial expected type as opposed to `expected`.
+                    // Otherwise we end up using prior coercions in e.g. a `match` expression:
+                    // ```
+                    // match i {
+                    //     0 => true, // Because of this...
+                    //     1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
+                    //     _ => (),
+                    // };
+                    // ```
+                    .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
+                    .is_some();
+
+                err.emit_unless(assign_to_bool);
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }