mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 17:24:06 +00:00
Auto merge of #97135 - Dylan-DPC:rollup-06u9pqn, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #94639 (Suggest dereferencing non-lval mutable reference on assignment) - #95979 (update coherence docs, fix generator + opaque type ICE) - #96378 (Mention traits and types involved in unstable trait upcasting) - #96917 (Make HashMap fall back to RtlGenRandom if BCryptGenRandom fails) - #97101 (Add tracking issue for ExitCode::exit_process) - #97123 (Clean fix for #96223) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a084b7ad35
@ -61,6 +61,9 @@ pub enum Reveal {
|
||||
/// let x: <() as Assoc>::Output = true;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We also do not reveal the hidden type of opaque types during
|
||||
/// type-checking.
|
||||
UserFacing,
|
||||
|
||||
/// At codegen time, all monomorphic projections will succeed.
|
||||
|
@ -645,7 +645,7 @@ fn orphan_check_trait_ref<'tcx>(
|
||||
.substs
|
||||
.types()
|
||||
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
|
||||
.find(|ty| ty_is_local_constructor(*ty, in_crate));
|
||||
.find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
|
||||
|
||||
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
|
||||
|
||||
@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
in_crate: InCrate,
|
||||
) -> Vec<Ty<'tcx>> {
|
||||
if ty_is_local_constructor(ty, in_crate) {
|
||||
if ty_is_local_constructor(tcx, ty, in_crate) {
|
||||
Vec::new()
|
||||
} else {
|
||||
match fundamental_ty_inner_tys(tcx, ty) {
|
||||
@ -730,7 +730,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||
fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||
debug!("ty_is_local_constructor({:?})", ty);
|
||||
|
||||
match *ty.kind() {
|
||||
@ -789,11 +789,6 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
ty::Closure(..) => {
|
||||
// Similar to the `Opaque` case (#83613).
|
||||
false
|
||||
}
|
||||
|
||||
ty::Dynamic(ref tt, ..) => {
|
||||
if let Some(principal) = tt.principal() {
|
||||
def_id_is_local(principal.def_id(), in_crate)
|
||||
@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
|
||||
|
||||
ty::Error(_) => true,
|
||||
|
||||
ty::Generator(..) | ty::GeneratorWitness(..) => {
|
||||
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
|
||||
// These variants should never appear during coherence checking because they
|
||||
// cannot be named directly.
|
||||
//
|
||||
// They could be indirectly used through an opaque type. While using opaque types
|
||||
// in impls causes an error, this path can still be hit afterwards.
|
||||
//
|
||||
// See `test/ui/coherence/coherence-with-closure.rs` for an example where this
|
||||
// could happens.
|
||||
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
|
||||
tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
format!("ty_is_local invoked on closure or generator: {:?}", ty),
|
||||
);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1384,8 +1384,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
|
||||
fn mk_trait_obligation_with_new_self_ty(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::PolyTraitPredicate<'tcx>,
|
||||
new_self_ty: Ty<'tcx>,
|
||||
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||
) -> PredicateObligation<'tcx>;
|
||||
|
||||
fn maybe_report_ambiguity(
|
||||
@ -1923,14 +1922,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
fn mk_trait_obligation_with_new_self_ty(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::PolyTraitPredicate<'tcx>,
|
||||
new_self_ty: Ty<'tcx>,
|
||||
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
assert!(!new_self_ty.has_escaping_bound_vars());
|
||||
|
||||
let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
|
||||
let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
|
||||
substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
|
||||
..tr.trait_ref
|
||||
},
|
||||
..*tr
|
||||
|
@ -628,17 +628,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
if let Some(parent_trait_pred) = parent_trait_pred {
|
||||
real_trait_pred = parent_trait_pred;
|
||||
}
|
||||
let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Skipping binder here, remapping below
|
||||
let real_ty = real_trait_pred.self_ty().skip_binder();
|
||||
|
||||
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
|
||||
let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
|
||||
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
||||
// Re-add the `&`
|
||||
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
||||
let obligation =
|
||||
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
|
||||
|
||||
// Remapping bound vars here
|
||||
let real_trait_pred_and_ty =
|
||||
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
|
||||
let obligation = self
|
||||
.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
|
||||
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
||||
}) {
|
||||
if steps > 0 {
|
||||
@ -659,10 +663,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
} else if real_trait_pred != trait_pred {
|
||||
// This branch addresses #87437.
|
||||
|
||||
// Remapping bound vars here
|
||||
let real_trait_pred_and_base_ty =
|
||||
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
|
||||
let obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
param_env,
|
||||
real_trait_pred,
|
||||
base_ty,
|
||||
real_trait_pred_and_base_ty,
|
||||
);
|
||||
if self.predicate_may_hold(&obligation) {
|
||||
err.span_suggestion_verbose(
|
||||
@ -720,9 +727,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
|
||||
return false;
|
||||
};
|
||||
// Skipping binder here, remapping below
|
||||
let self_ty = trait_pred.self_ty().skip_binder();
|
||||
|
||||
let (def_id, output_ty, callable) = match *self_ty.kind() {
|
||||
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
|
||||
@ -731,14 +737,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
};
|
||||
let msg = format!("use parentheses to call the {}", callable);
|
||||
|
||||
// `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
|
||||
// variables, so bail out if we have any.
|
||||
let Some(output_ty) = output_ty.no_bound_vars() else {
|
||||
return false;
|
||||
};
|
||||
// "We should really create a single list of bound vars from the combined vars
|
||||
// from the predicate and function, but instead we just liberate the function bound vars"
|
||||
let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
|
||||
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
|
||||
|
||||
let new_obligation =
|
||||
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
|
||||
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
|
||||
|
||||
match self.evaluate_obligation(&new_obligation) {
|
||||
Ok(
|
||||
@ -842,96 +849,97 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
let param_env = obligation.param_env;
|
||||
|
||||
// Try to apply the original trait binding obligation by borrowing.
|
||||
let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
blacklist: &[DefId]|
|
||||
-> bool {
|
||||
if blacklist.contains(&old_pred.def_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a quick fix to resolve an ICE (#96223).
|
||||
// This change should probably be deeper.
|
||||
// As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
|
||||
// instead of `Binder<Ty>` leading to some changes to its call places.
|
||||
let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
|
||||
return false;
|
||||
};
|
||||
let mk_result = |new_ty| {
|
||||
let obligation =
|
||||
self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
|
||||
self.predicate_must_hold_modulo_regions(&obligation)
|
||||
};
|
||||
let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
|
||||
let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
|
||||
|
||||
if imm_result || mut_result {
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
// We have a very specific type of error, where just borrowing this argument
|
||||
// might solve the problem. In cases like this, the important part is the
|
||||
// original type obligation, not the last one that failed, which is arbitrary.
|
||||
// Because of this, we modify the error to refer to the original obligation and
|
||||
// return early in the caller.
|
||||
|
||||
let msg = format!(
|
||||
"the trait bound `{}: {}` is not satisfied",
|
||||
orig_ty,
|
||||
old_pred.print_modifiers_and_trait_path(),
|
||||
);
|
||||
if has_custom_message {
|
||||
err.note(&msg);
|
||||
} else {
|
||||
err.message =
|
||||
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
|
||||
}
|
||||
if snippet.starts_with('&') {
|
||||
// This is already a literal borrow and the obligation is failing
|
||||
// somewhere else in the obligation chain. Do not suggest non-sense.
|
||||
return false;
|
||||
}
|
||||
err.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"expected an implementor of trait `{}`",
|
||||
old_pred.print_modifiers_and_trait_path(),
|
||||
),
|
||||
);
|
||||
|
||||
// This if is to prevent a special edge-case
|
||||
if matches!(
|
||||
span.ctxt().outer_expn_data().kind,
|
||||
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
|
||||
) {
|
||||
// We don't want a borrowing suggestion on the fields in structs,
|
||||
// ```
|
||||
// struct Foo {
|
||||
// the_foos: Vec<Foo>
|
||||
// }
|
||||
// ```
|
||||
|
||||
if imm_result && mut_result {
|
||||
err.span_suggestions(
|
||||
span.shrink_to_lo(),
|
||||
"consider borrowing here",
|
||||
["&".to_string(), "&mut ".to_string()].into_iter(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider{} borrowing here",
|
||||
if mut_result { " mutably" } else { "" }
|
||||
),
|
||||
format!("&{}", if mut_result { "mut " } else { "" }),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
let mut try_borrowing =
|
||||
|old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
|
||||
if blacklist.contains(&old_pred.def_id()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// We map bounds to `&T` and `&mut T`
|
||||
let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
|
||||
(
|
||||
trait_pred,
|
||||
self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
|
||||
)
|
||||
});
|
||||
let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
|
||||
(
|
||||
trait_pred,
|
||||
self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
|
||||
)
|
||||
});
|
||||
|
||||
let mk_result = |trait_pred_and_new_ty| {
|
||||
let obligation =
|
||||
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
|
||||
self.predicate_must_hold_modulo_regions(&obligation)
|
||||
};
|
||||
let imm_result = mk_result(trait_pred_and_imm_ref);
|
||||
let mut_result = mk_result(trait_pred_and_mut_ref);
|
||||
|
||||
if imm_result || mut_result {
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
// We have a very specific type of error, where just borrowing this argument
|
||||
// might solve the problem. In cases like this, the important part is the
|
||||
// original type obligation, not the last one that failed, which is arbitrary.
|
||||
// Because of this, we modify the error to refer to the original obligation and
|
||||
// return early in the caller.
|
||||
|
||||
let msg = format!("the trait bound `{}` is not satisfied", old_pred);
|
||||
if has_custom_message {
|
||||
err.note(&msg);
|
||||
} else {
|
||||
err.message =
|
||||
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
|
||||
}
|
||||
if snippet.starts_with('&') {
|
||||
// This is already a literal borrow and the obligation is failing
|
||||
// somewhere else in the obligation chain. Do not suggest non-sense.
|
||||
return false;
|
||||
}
|
||||
err.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"expected an implementor of trait `{}`",
|
||||
old_pred.print_modifiers_and_trait_path(),
|
||||
),
|
||||
);
|
||||
|
||||
// This if is to prevent a special edge-case
|
||||
if matches!(
|
||||
span.ctxt().outer_expn_data().kind,
|
||||
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
|
||||
) {
|
||||
// We don't want a borrowing suggestion on the fields in structs,
|
||||
// ```
|
||||
// struct Foo {
|
||||
// the_foos: Vec<Foo>
|
||||
// }
|
||||
// ```
|
||||
|
||||
if imm_result && mut_result {
|
||||
err.span_suggestions(
|
||||
span.shrink_to_lo(),
|
||||
"consider borrowing here",
|
||||
["&".to_string(), "&mut ".to_string()].into_iter(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
&format!(
|
||||
"consider{} borrowing here",
|
||||
if mut_result { " mutably" } else { "" }
|
||||
),
|
||||
format!("&{}", if mut_result { "mut " } else { "" }),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
|
||||
try_borrowing(cause.derived.parent_trait_pred, &[])
|
||||
@ -992,9 +1000,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
|
||||
return false;
|
||||
};
|
||||
// Skipping binder here, remapping below
|
||||
let mut suggested_ty = trait_pred.self_ty().skip_binder();
|
||||
|
||||
for refs_remaining in 0..refs_number {
|
||||
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
|
||||
@ -1002,10 +1009,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
};
|
||||
suggested_ty = *inner_ty;
|
||||
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_suggested_ty =
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||
|
||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred,
|
||||
suggested_ty,
|
||||
trait_pred_and_suggested_ty,
|
||||
);
|
||||
|
||||
if self.predicate_may_hold(&new_obligation) {
|
||||
@ -1125,26 +1135,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skipping binder here, remapping below
|
||||
if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
|
||||
{
|
||||
if region.is_late_bound() || t_type.has_escaping_bound_vars() {
|
||||
// Avoid debug assertion in `mk_obligation_for_def_id`.
|
||||
//
|
||||
// If the self type has escaping bound vars then it's not
|
||||
// going to be the type of an expression, so the suggestion
|
||||
// probably won't apply anyway.
|
||||
return;
|
||||
}
|
||||
|
||||
let suggested_ty = match mutability {
|
||||
hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
|
||||
hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
|
||||
};
|
||||
|
||||
// Remapping bound vars here
|
||||
let trait_pred_and_suggested_ty =
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||
|
||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred,
|
||||
suggested_ty,
|
||||
trait_pred_and_suggested_ty,
|
||||
);
|
||||
let suggested_ty_would_satisfy_obligation = self
|
||||
.evaluate_obligation_no_overflow(&new_obligation)
|
||||
@ -1195,7 +1200,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
// Only suggest this if the expression behind the semicolon implements the predicate
|
||||
&& let Some(typeck_results) = self.in_progress_typeck_results
|
||||
&& let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
|
||||
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
|
||||
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
|
||||
))
|
||||
{
|
||||
err.span_label(
|
||||
expr.span,
|
||||
@ -2727,8 +2734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
);
|
||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred,
|
||||
normalized_ty.ty().unwrap(),
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())),
|
||||
);
|
||||
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
|
||||
if self.predicate_may_hold(&try_obligation)
|
||||
|
@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
|
||||
/// require themselves.
|
||||
freshener: TypeFreshener<'cx, 'tcx>,
|
||||
|
||||
/// If `true`, indicates that the evaluation should be conservative
|
||||
/// and consider the possibility of types outside this crate.
|
||||
/// During coherence we have to assume that other crates may add
|
||||
/// additional impls which we currently don't know about.
|
||||
///
|
||||
/// To deal with this evaluation should be conservative
|
||||
/// and consider the possibility of impls from outside this crate.
|
||||
/// This comes up primarily when resolving ambiguity. Imagine
|
||||
/// there is some trait reference `$0: Bar` where `$0` is an
|
||||
/// inference variable. If `intercrate` is true, then we can never
|
||||
/// say for sure that this reference is not implemented, even if
|
||||
/// there are *no impls at all for `Bar`*, because `$0` could be
|
||||
/// bound to some type that in a downstream crate that implements
|
||||
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
|
||||
/// though, we set this to false, because we are only interested
|
||||
/// in types that the user could actually have written --- in
|
||||
/// other words, we consider `$0: Bar` to be unimplemented if
|
||||
/// `Bar`.
|
||||
///
|
||||
/// Outside of coherence we set this to false because we are only
|
||||
/// interested in types that the user could actually have written.
|
||||
/// In other words, we consider `$0: Bar` to be unimplemented if
|
||||
/// there is no type that the user could *actually name* that
|
||||
/// would satisfy it. This avoids crippling inference, basically.
|
||||
intercrate: bool,
|
||||
|
||||
/// If `intercrate` is set, we remember predicates which were
|
||||
/// considered ambiguous because of impls potentially added in other crates.
|
||||
/// This is used in coherence to give improved diagnostics.
|
||||
/// We don't do his until we detect a coherence error because it can
|
||||
/// lead to false overflow results (#47139) and because always
|
||||
/// computing it may negatively impact performance.
|
||||
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
|
||||
|
||||
/// The mode that trait queries run in, which informs our error handling
|
||||
@ -240,11 +249,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables tracking of intercrate ambiguity causes. These are
|
||||
/// used in coherence to give improved diagnostics. We don't do
|
||||
/// this until we detect a coherence error because it can lead to
|
||||
/// false overflow results (#47139) and because it costs
|
||||
/// computation time.
|
||||
/// Enables tracking of intercrate ambiguity causes. See
|
||||
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
|
||||
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
|
||||
assert!(self.intercrate);
|
||||
assert!(self.intercrate_ambiguity_causes.is_none());
|
||||
|
@ -58,7 +58,8 @@ use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, BytePos, DesugaringKind, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@ -615,7 +616,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
)];
|
||||
|
||||
let mut has_unsized_tuple_coercion = false;
|
||||
let mut has_trait_upcasting_coercion = false;
|
||||
let mut has_trait_upcasting_coercion = None;
|
||||
|
||||
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||
@ -635,7 +636,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
&& data_a.principal_def_id() != data_b.principal_def_id()
|
||||
{
|
||||
debug!("coerce_unsized: found trait upcasting coercion");
|
||||
has_trait_upcasting_coercion = true;
|
||||
has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
|
||||
}
|
||||
if let ty::Tuple(..) = unsize_ty.kind() {
|
||||
debug!("coerce_unsized: found unsized tuple coercion");
|
||||
@ -706,14 +707,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
|
||||
feature_err(
|
||||
if let Some((sub, sup)) = has_trait_upcasting_coercion
|
||||
&& !self.tcx().features().trait_upcasting
|
||||
{
|
||||
// Renders better when we erase regions, since they're not really the point here.
|
||||
let (sub, sup) = self.tcx.erase_regions((sub, sup));
|
||||
let mut err = feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::trait_upcasting,
|
||||
self.cause.span,
|
||||
"trait upcasting coercion is experimental",
|
||||
)
|
||||
.emit();
|
||||
&format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
|
||||
);
|
||||
err.note(&format!("required when coercing `{source}` into `{target}`"));
|
||||
err.emit();
|
||||
}
|
||||
|
||||
Ok(coercion)
|
||||
@ -962,6 +968,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
|
||||
}
|
||||
|
||||
/// Given a type, this function will calculate and return the type given
|
||||
/// for `<Ty as Deref>::Target` only if `Ty` also implements `DerefMut`.
|
||||
///
|
||||
/// This function is for diagnostics only, since it does not register
|
||||
/// trait or region sub-obligations. (presumably we could, but it's not
|
||||
/// particularly important for diagnostics...)
|
||||
pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
|
||||
self.infcx
|
||||
.type_implements_trait(
|
||||
self.infcx.tcx.lang_items().deref_mut_trait()?,
|
||||
expr_ty,
|
||||
ty::List::empty(),
|
||||
self.param_env,
|
||||
)
|
||||
.may_apply()
|
||||
.then(|| deref_ty)
|
||||
})
|
||||
}
|
||||
|
||||
/// Given some expressions, their known unified type and another expression,
|
||||
/// tries to unify the types, potentially inserting coercions on any of the
|
||||
/// provided expressions and returns their LUB (aka "common supertype").
|
||||
|
@ -696,28 +696,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
if let Some(hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Assign(left_expr, ..),
|
||||
kind: hir::ExprKind::Assign(..),
|
||||
..
|
||||
})) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
|
||||
{
|
||||
if mutability == hir::Mutability::Mut {
|
||||
// Found the following case:
|
||||
// fn foo(opt: &mut Option<String>){ opt = None }
|
||||
// --- ^^^^
|
||||
// | |
|
||||
// consider dereferencing here: `*opt` |
|
||||
// expected mutable reference, found enum `Option`
|
||||
if sm.span_to_snippet(left_expr.span).is_ok() {
|
||||
return Some((
|
||||
left_expr.span.shrink_to_lo(),
|
||||
"consider dereferencing here to assign to the mutable \
|
||||
borrowed piece of memory"
|
||||
.to_string(),
|
||||
"*".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
true,
|
||||
));
|
||||
}
|
||||
// Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ use rustc_span::lev_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Pos};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
@ -836,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
lhs: &'tcx hir::Expr<'tcx>,
|
||||
err_code: &'static str,
|
||||
op_span: Span,
|
||||
adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
|
||||
) {
|
||||
if lhs.is_syntactic_place_expr() {
|
||||
return;
|
||||
@ -858,6 +860,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
});
|
||||
|
||||
adjust_err(&mut err);
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
@ -1050,10 +1054,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return self.tcx.ty_error();
|
||||
}
|
||||
|
||||
self.check_lhs_assignable(lhs, "E0070", span);
|
||||
|
||||
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
|
||||
let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
|
||||
|
||||
let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
|
||||
rhs_ty: Ty<'tcx>| {
|
||||
if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
|
||||
// Can only assign if the type is sized, so if `DerefMut` yields a type that is
|
||||
// unsized, do not suggest dereferencing it.
|
||||
let lhs_deref_ty_is_sized = self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.lang_items().sized_trait().unwrap(),
|
||||
lhs_deref_ty,
|
||||
ty::List::empty(),
|
||||
self.param_env,
|
||||
)
|
||||
.may_apply();
|
||||
if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
|
||||
err.span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
"consider dereferencing here to assign to the mutably borrowed value",
|
||||
"*".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.check_lhs_assignable(lhs, "E0070", span, |err| {
|
||||
let rhs_ty = self.check_expr(&rhs);
|
||||
suggest_deref_binop(err, rhs_ty);
|
||||
});
|
||||
|
||||
// This is (basically) inlined `check_expr_coercable_to_type`, but we want
|
||||
// to suggest an additional fixup here in `suggest_deref_binop`.
|
||||
let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
|
||||
if let (_, Some(mut diag)) =
|
||||
self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No)
|
||||
{
|
||||
suggest_deref_binop(&mut diag, rhs_ty);
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
|
||||
|
||||
|
@ -41,7 +41,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return_ty
|
||||
};
|
||||
|
||||
self.check_lhs_assignable(lhs, "E0067", op.span);
|
||||
self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
|
||||
if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
|
||||
if self
|
||||
.lookup_op_method(
|
||||
lhs_deref_ty,
|
||||
Some(rhs_ty),
|
||||
Some(rhs),
|
||||
Op::Binary(op, IsAssign::Yes),
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
// Suppress this error, since we already emitted
|
||||
// a deref suggestion in check_overloaded_binop
|
||||
err.delay_as_bug();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ty
|
||||
}
|
||||
@ -404,16 +420,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
(err, missing_trait, use_output)
|
||||
}
|
||||
};
|
||||
if let Ref(_, rty, _) = lhs_ty.kind() {
|
||||
if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
|
||||
&& self
|
||||
.lookup_op_method(
|
||||
*rty,
|
||||
Some(rhs_ty),
|
||||
Some(rhs_expr),
|
||||
Op::Binary(op, is_assign),
|
||||
)
|
||||
.is_ok()
|
||||
|
||||
let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
|
||||
if self
|
||||
.lookup_op_method(
|
||||
lhs_deref_ty,
|
||||
Some(rhs_ty),
|
||||
Some(rhs_expr),
|
||||
Op::Binary(op, is_assign),
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
|
||||
let msg = &format!(
|
||||
@ -423,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
IsAssign::Yes => "=",
|
||||
IsAssign::No => "",
|
||||
},
|
||||
rty.peel_refs(),
|
||||
lhs_deref_ty.peel_refs(),
|
||||
lstring,
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
@ -434,6 +450,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
|
||||
// `a += b` => `*a += b` if a is a mut ref.
|
||||
if is_assign == IsAssign::Yes
|
||||
&& let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
|
||||
suggest_deref_binop(lhs_deref_ty);
|
||||
} else if is_assign == IsAssign::No
|
||||
&& let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
|
||||
if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
|
||||
suggest_deref_binop(*lhs_deref_ty);
|
||||
}
|
||||
}
|
||||
if let Some(missing_trait) = missing_trait {
|
||||
let mut visitor = TypeParamVisitor(vec![]);
|
||||
|
@ -1764,7 +1764,7 @@ impl ExitCode {
|
||||
/// code.exit_process()
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "exitcode_exit_method", issue = "none")]
|
||||
#[unstable(feature = "exitcode_exit_method", issue = "97100")]
|
||||
pub fn exit_process(self) -> ! {
|
||||
exit(self.to_i32())
|
||||
}
|
||||
|
@ -788,6 +788,10 @@ if #[cfg(not(target_vendor = "uwp"))] {
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
// Forbidden when targeting UWP
|
||||
#[link_name = "SystemFunction036"]
|
||||
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
|
||||
|
||||
// Allowed but unused by UWP
|
||||
pub fn OpenProcessToken(
|
||||
ProcessHandle: HANDLE,
|
||||
|
@ -1,8 +1,60 @@
|
||||
use crate::io;
|
||||
use crate::lazy;
|
||||
use crate::mem;
|
||||
use crate::sys::c;
|
||||
|
||||
/// The kinds of HashMap RNG that may be available
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum HashMapRng {
|
||||
Preferred,
|
||||
Fallback,
|
||||
}
|
||||
|
||||
pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
match get_hashmap_rng() {
|
||||
HashMapRng::Preferred => {
|
||||
preferred_rng().expect("couldn't generate random bytes with preferred RNG")
|
||||
}
|
||||
HashMapRng::Fallback => {
|
||||
fallback_rng().expect("couldn't generate random bytes with fallback RNG")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the HashMap RNG that should be used
|
||||
///
|
||||
/// Panics if they are both broken
|
||||
fn get_hashmap_rng() -> HashMapRng {
|
||||
// Assume that if the preferred RNG is broken the first time we use it, it likely means
|
||||
// that: the DLL has failed to load, there is no point to calling it over-and-over again,
|
||||
// and we should cache the result
|
||||
static VALUE: lazy::SyncOnceCell<HashMapRng> = lazy::SyncOnceCell::new();
|
||||
*VALUE.get_or_init(choose_hashmap_rng)
|
||||
}
|
||||
|
||||
/// Test whether we should use the preferred or fallback RNG
|
||||
///
|
||||
/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
|
||||
/// we choose that
|
||||
///
|
||||
/// Panics if both the preferred and the fallback RNG are both non-functional
|
||||
fn choose_hashmap_rng() -> HashMapRng {
|
||||
let preferred_error = match preferred_rng() {
|
||||
Ok(_) => return HashMapRng::Preferred,
|
||||
Err(e) => e,
|
||||
};
|
||||
|
||||
match fallback_rng() {
|
||||
Ok(_) => return HashMapRng::Fallback,
|
||||
Err(fallback_error) => panic!(
|
||||
"preferred RNG broken: `{}`, fallback RNG broken: `{}`",
|
||||
preferred_error, fallback_error
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
|
||||
fn preferred_rng() -> Result<(u64, u64), io::Error> {
|
||||
use crate::ptr;
|
||||
|
||||
let mut v = (0, 0);
|
||||
@ -14,8 +66,22 @@ pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
|
||||
)
|
||||
};
|
||||
if ret != 0 {
|
||||
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
|
||||
}
|
||||
return v;
|
||||
|
||||
if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
|
||||
}
|
||||
|
||||
/// Generate random numbers using the fallback RNG function (RtlGenRandom)
|
||||
#[cfg(not(target_vendor = "uwp"))]
|
||||
fn fallback_rng() -> Result<(u64, u64), io::Error> {
|
||||
let mut v = (0, 0);
|
||||
let ret =
|
||||
unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
|
||||
|
||||
if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
|
||||
}
|
||||
|
||||
/// We can't use RtlGenRandom with UWP, so there is no fallback
|
||||
#[cfg(target_vendor = "uwp")]
|
||||
fn fallback_rng() -> Result<(u64, u64), io::Error> {
|
||||
Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
|
||||
}
|
||||
|
@ -12,20 +12,14 @@ LL | assert_eq!(foo, y);
|
||||
error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
|
||||
--> $DIR/issue-77910-1.rs:8:5
|
||||
|
|
||||
LL | fn foo(s: &i32) -> &i32 {
|
||||
| --- consider calling this function
|
||||
...
|
||||
LL | assert_eq!(foo, y);
|
||||
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||
|
|
||||
= help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
|
||||
= help: the following other types implement trait `Debug`:
|
||||
extern "C" fn() -> Ret
|
||||
extern "C" fn(A) -> Ret
|
||||
extern "C" fn(A, ...) -> Ret
|
||||
extern "C" fn(A, B) -> Ret
|
||||
extern "C" fn(A, B, ...) -> Ret
|
||||
extern "C" fn(A, B, C) -> Ret
|
||||
extern "C" fn(A, B, C, ...) -> Ret
|
||||
extern "C" fn(A, B, C, D) -> Ret
|
||||
and 68 others
|
||||
= help: use parentheses to call the function: `foo(s)`
|
||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
15
src/test/ui/coherence/coherence-with-closure.rs
Normal file
15
src/test/ui/coherence/coherence-with-closure.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Test that encountering closures during coherence does not cause issues.
|
||||
#![feature(type_alias_impl_trait)]
|
||||
type OpaqueClosure = impl Sized;
|
||||
fn defining_use() -> OpaqueClosure {
|
||||
|| ()
|
||||
}
|
||||
|
||||
struct Wrapper<T>(T);
|
||||
trait Trait {}
|
||||
impl Trait for Wrapper<OpaqueClosure> {}
|
||||
//~^ ERROR cannot implement trait on type alias impl trait
|
||||
impl<T: Sync> Trait for Wrapper<T> {}
|
||||
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
|
||||
|
||||
fn main() {}
|
24
src/test/ui/coherence/coherence-with-closure.stderr
Normal file
24
src/test/ui/coherence/coherence-with-closure.stderr
Normal file
@ -0,0 +1,24 @@
|
||||
error: cannot implement trait on type alias impl trait
|
||||
--> $DIR/coherence-with-closure.rs:10:24
|
||||
|
|
||||
LL | impl Trait for Wrapper<OpaqueClosure> {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: type alias impl trait defined here
|
||||
--> $DIR/coherence-with-closure.rs:3:22
|
||||
|
|
||||
LL | type OpaqueClosure = impl Sized;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
|
||||
--> $DIR/coherence-with-closure.rs:12:1
|
||||
|
|
||||
LL | impl Trait for Wrapper<OpaqueClosure> {}
|
||||
| ------------------------------------- first implementation here
|
||||
LL |
|
||||
LL | impl<T: Sync> Trait for Wrapper<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
19
src/test/ui/coherence/coherence-with-generator.rs
Normal file
19
src/test/ui/coherence/coherence-with-generator.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Test that encountering closures during coherence does not cause issues.
|
||||
#![feature(type_alias_impl_trait, generators)]
|
||||
type OpaqueGenerator = impl Sized;
|
||||
fn defining_use() -> OpaqueGenerator {
|
||||
|| {
|
||||
for i in 0..10 {
|
||||
yield i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Wrapper<T>(T);
|
||||
trait Trait {}
|
||||
impl Trait for Wrapper<OpaqueGenerator> {}
|
||||
//~^ ERROR cannot implement trait on type alias impl trait
|
||||
impl<T: Sync> Trait for Wrapper<T> {}
|
||||
//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
||||
|
||||
fn main() {}
|
24
src/test/ui/coherence/coherence-with-generator.stderr
Normal file
24
src/test/ui/coherence/coherence-with-generator.stderr
Normal file
@ -0,0 +1,24 @@
|
||||
error: cannot implement trait on type alias impl trait
|
||||
--> $DIR/coherence-with-generator.rs:14:24
|
||||
|
|
||||
LL | impl Trait for Wrapper<OpaqueGenerator> {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: type alias impl trait defined here
|
||||
--> $DIR/coherence-with-generator.rs:3:24
|
||||
|
|
||||
LL | type OpaqueGenerator = impl Sized;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
|
||||
--> $DIR/coherence-with-generator.rs:16:1
|
||||
|
|
||||
LL | impl Trait for Wrapper<OpaqueGenerator> {}
|
||||
| --------------------------------------- first implementation here
|
||||
LL |
|
||||
LL | impl<T: Sync> Trait for Wrapper<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
@ -1,4 +1,4 @@
|
||||
error[E0658]: trait upcasting coercion is experimental
|
||||
error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
|
||||
--> $DIR/feature-gate-trait_upcasting.rs:11:25
|
||||
|
|
||||
LL | let foo: &dyn Foo = bar;
|
||||
@ -6,6 +6,7 @@ LL | let foo: &dyn Foo = bar;
|
||||
|
|
||||
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||
= note: required when coercing `&dyn Bar` into `&dyn Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0658]: trait upcasting coercion is experimental
|
||||
error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
|
||||
--> $DIR/issue-11515.rs:9:33
|
||||
|
|
||||
LL | let test = box Test { func: closure };
|
||||
@ -6,6 +6,7 @@ LL | let test = box Test { func: closure };
|
||||
|
|
||||
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||
= note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,11 +5,6 @@ LL | let x = |ref x: isize| { x += 1; };
|
||||
| -^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `&isize`
|
||||
|
|
||||
help: `+=` can be used on `isize`, you can dereference `x`
|
||||
|
|
||||
LL | let x = |ref x: isize| { *x += 1; };
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,6 +5,7 @@ LL | foo::<S>(s);
|
||||
| ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
|
||||
|
|
||||
= help: the trait `Trait` is implemented for `&'a mut S`
|
||||
= note: `for<'b> Trait` is implemented for `&'b mut S`, but not for `&'b S`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20
|
||||
|
|
||||
|
@ -8,7 +8,7 @@ LL | opt = None;
|
||||
|
|
||||
= note: expected mutable reference `&mut Option<String>`
|
||||
found enum `Option<_>`
|
||||
help: consider dereferencing here to assign to the mutable borrowed piece of memory
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *opt = None;
|
||||
| +
|
||||
@ -34,7 +34,7 @@ LL | opt = Some(String::new())
|
||||
|
|
||||
= note: expected mutable reference `&mut Option<String>`
|
||||
found enum `Option<String>`
|
||||
help: consider dereferencing here to assign to the mutable borrowed piece of memory
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *opt = Some(String::new())
|
||||
| +
|
||||
|
15
src/test/ui/typeck/assign-non-lval-derefmut.fixed
Normal file
15
src/test/ui/typeck/assign-non-lval-derefmut.fixed
Normal file
@ -0,0 +1,15 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let x = std::sync::Mutex::new(1usize);
|
||||
*x.lock().unwrap() = 2;
|
||||
//~^ ERROR invalid left-hand side of assignment
|
||||
*x.lock().unwrap() += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
|
||||
let mut y = x.lock().unwrap();
|
||||
*y = 2;
|
||||
//~^ ERROR mismatched types
|
||||
*y += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
}
|
15
src/test/ui/typeck/assign-non-lval-derefmut.rs
Normal file
15
src/test/ui/typeck/assign-non-lval-derefmut.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let x = std::sync::Mutex::new(1usize);
|
||||
x.lock().unwrap() = 2;
|
||||
//~^ ERROR invalid left-hand side of assignment
|
||||
x.lock().unwrap() += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
|
||||
let mut y = x.lock().unwrap();
|
||||
y = 2;
|
||||
//~^ ERROR mismatched types
|
||||
y += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
}
|
58
src/test/ui/typeck/assign-non-lval-derefmut.stderr
Normal file
58
src/test/ui/typeck/assign-non-lval-derefmut.stderr
Normal file
@ -0,0 +1,58 @@
|
||||
error[E0070]: invalid left-hand side of assignment
|
||||
--> $DIR/assign-non-lval-derefmut.rs:5:23
|
||||
|
|
||||
LL | x.lock().unwrap() = 2;
|
||||
| ----------------- ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
|
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *x.lock().unwrap() = 2;
|
||||
| +
|
||||
|
||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
--> $DIR/assign-non-lval-derefmut.rs:7:5
|
||||
|
|
||||
LL | x.lock().unwrap() += 1;
|
||||
| -----------------^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `MutexGuard<'_, usize>`
|
||||
|
|
||||
help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()`
|
||||
|
|
||||
LL | *x.lock().unwrap() += 1;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/assign-non-lval-derefmut.rs:11:9
|
||||
|
|
||||
LL | let mut y = x.lock().unwrap();
|
||||
| ----------------- expected due to this value
|
||||
LL | y = 2;
|
||||
| ^ expected struct `MutexGuard`, found integer
|
||||
|
|
||||
= note: expected struct `MutexGuard<'_, usize>`
|
||||
found type `{integer}`
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *y = 2;
|
||||
| +
|
||||
|
||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
|
||||
--> $DIR/assign-non-lval-derefmut.rs:13:5
|
||||
|
|
||||
LL | y += 1;
|
||||
| -^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `MutexGuard<'_, usize>`
|
||||
|
|
||||
help: `+=` can be used on `usize`, you can dereference `y`
|
||||
|
|
||||
LL | *y += 1;
|
||||
| +
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0070, E0308, E0368.
|
||||
For more information about an error, try `rustc --explain E0070`.
|
15
src/test/ui/typeck/assign-non-lval-mut-ref.fixed
Normal file
15
src/test/ui/typeck/assign-non-lval-mut-ref.fixed
Normal file
@ -0,0 +1,15 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let mut x = vec![1usize];
|
||||
*x.last_mut().unwrap() = 2;
|
||||
//~^ ERROR invalid left-hand side of assignment
|
||||
*x.last_mut().unwrap() += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
|
||||
let y = x.last_mut().unwrap();
|
||||
*y = 2;
|
||||
//~^ ERROR mismatched types
|
||||
*y += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
}
|
15
src/test/ui/typeck/assign-non-lval-mut-ref.rs
Normal file
15
src/test/ui/typeck/assign-non-lval-mut-ref.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
let mut x = vec![1usize];
|
||||
x.last_mut().unwrap() = 2;
|
||||
//~^ ERROR invalid left-hand side of assignment
|
||||
x.last_mut().unwrap() += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
|
||||
let y = x.last_mut().unwrap();
|
||||
y = 2;
|
||||
//~^ ERROR mismatched types
|
||||
y += 1;
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
}
|
56
src/test/ui/typeck/assign-non-lval-mut-ref.stderr
Normal file
56
src/test/ui/typeck/assign-non-lval-mut-ref.stderr
Normal file
@ -0,0 +1,56 @@
|
||||
error[E0070]: invalid left-hand side of assignment
|
||||
--> $DIR/assign-non-lval-mut-ref.rs:5:27
|
||||
|
|
||||
LL | x.last_mut().unwrap() = 2;
|
||||
| --------------------- ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
|
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *x.last_mut().unwrap() = 2;
|
||||
| +
|
||||
|
||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
--> $DIR/assign-non-lval-mut-ref.rs:7:5
|
||||
|
|
||||
LL | x.last_mut().unwrap() += 1;
|
||||
| ---------------------^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `&mut usize`
|
||||
|
|
||||
help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
|
||||
|
|
||||
LL | *x.last_mut().unwrap() += 1;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/assign-non-lval-mut-ref.rs:11:9
|
||||
|
|
||||
LL | let y = x.last_mut().unwrap();
|
||||
| --------------------- expected due to this value
|
||||
LL | y = 2;
|
||||
| ^ expected `&mut usize`, found integer
|
||||
|
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *y = 2;
|
||||
| +
|
||||
|
||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
|
||||
--> $DIR/assign-non-lval-mut-ref.rs:13:5
|
||||
|
|
||||
LL | y += 1;
|
||||
| -^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `&mut usize`
|
||||
|
|
||||
help: `+=` can be used on `usize`, you can dereference `y`
|
||||
|
|
||||
LL | *y += 1;
|
||||
| +
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0070, E0308, E0368.
|
||||
For more information about an error, try `rustc --explain E0070`.
|
@ -5,6 +5,11 @@ LL | vec![].last_mut().unwrap() = 3_u8;
|
||||
| -------------------------- ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
|
|
||||
help: consider dereferencing here to assign to the mutably borrowed value
|
||||
|
|
||||
LL | *vec![].last_mut().unwrap() = 3_u8;
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user