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>,
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),
}
}
}
};
- 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
// `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);
}
_ => 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,
}
};
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.
}
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)
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);
}