Skip to content

Commit d58d52a

Browse files
committed
Fix handling of substitutions and binders when deciding whether to suggest references
When suggesting references, substitutions were being forgotten and some types were misused. This led to at least one ICE and other incorrectly emitted diagnostics. This has been fixed; in some cases this leads to diagnostics changing, and tests have been adjusted.
1 parent d71ba74 commit d58d52a

File tree

5 files changed

+55
-50
lines changed

5 files changed

+55
-50
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+21-38
Original file line numberDiff line numberDiff line change
@@ -706,36 +706,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
706706
}
707707

708708
let param_env = obligation.param_env;
709-
let trait_ref = poly_trait_ref.skip_binder();
710-
711-
let found_ty = trait_ref.self_ty();
712-
let found_ty_str = found_ty.to_string();
713-
let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty);
714-
let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]);
715-
let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty);
716-
let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
717709

718710
// Try to apply the original trait binding obligation by borrowing.
719-
let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
720-
new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
721-
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
711+
let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
722712
blacklist: &[DefId]|
723713
-> bool {
724-
if blacklist.contains(&expected_trait_ref.def_id()) {
714+
if blacklist.contains(&old_ref.def_id()) {
725715
return false;
726716
}
727717

728-
let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
729-
ObligationCause::dummy(),
730-
param_env,
731-
new_imm_trait_ref.without_const().to_predicate(self.tcx),
732-
));
733-
734-
let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
735-
ObligationCause::dummy(),
736-
param_env,
737-
new_mut_trait_ref.without_const().to_predicate(self.tcx),
738-
));
718+
let orig_ty = old_ref.self_ty().skip_binder();
719+
let mk_result = |new_ty| {
720+
let new_ref = old_ref.rebind(ty::TraitRef::new(
721+
old_ref.def_id(),
722+
self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]),
723+
));
724+
self.predicate_must_hold_modulo_regions(&Obligation::new(
725+
ObligationCause::dummy(),
726+
param_env,
727+
new_ref.without_const().to_predicate(self.tcx),
728+
))
729+
};
730+
let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
731+
let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
739732

740733
if imm_result || mut_result {
741734
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -747,8 +740,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
747740

748741
let msg = format!(
749742
"the trait bound `{}: {}` is not satisfied",
750-
found_ty_str,
751-
expected_trait_ref.print_only_trait_path(),
743+
orig_ty.to_string(),
744+
old_ref.print_only_trait_path(),
752745
);
753746
if has_custom_message {
754747
err.note(&msg);
@@ -764,7 +757,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
764757
span,
765758
&format!(
766759
"expected an implementor of trait `{}`",
767-
expected_trait_ref.print_only_trait_path(),
760+
old_ref.print_only_trait_path(),
768761
),
769762
);
770763

@@ -807,21 +800,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
807800
};
808801

809802
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code {
810-
let expected_trait_ref = obligation.parent_trait_ref;
811-
let new_imm_trait_ref = poly_trait_ref
812-
.rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs));
813-
let new_mut_trait_ref = poly_trait_ref
814-
.rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs));
815-
return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
803+
try_borrowing(obligation.parent_trait_ref, &[])
816804
} else if let ObligationCauseCode::BindingObligation(_, _)
817805
| ObligationCauseCode::ItemObligation(_) = &*code
818806
{
819-
return try_borrowing(
820-
poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)),
821-
poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)),
822-
*poly_trait_ref,
823-
&never_suggest_borrow[..],
824-
);
807+
try_borrowing(*poly_trait_ref, &never_suggest_borrow[..])
825808
} else {
826809
false
827810
}

src/test/ui/derives/deriving-copyclone.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `C: Copy` is not satisfied
1+
error[E0277]: the trait bound `B<C>: Copy` is not satisfied
22
--> $DIR/deriving-copyclone.rs:31:13
33
|
44
LL | is_copy(B { a: 1, b: C });
@@ -22,7 +22,7 @@ help: consider borrowing here
2222
LL | is_copy(&B { a: 1, b: C });
2323
| +
2424

25-
error[E0277]: the trait bound `C: Clone` is not satisfied
25+
error[E0277]: the trait bound `B<C>: Clone` is not satisfied
2626
--> $DIR/deriving-copyclone.rs:32:14
2727
|
2828
LL | is_clone(B { a: 1, b: C });
@@ -46,7 +46,7 @@ help: consider borrowing here
4646
LL | is_clone(&B { a: 1, b: C });
4747
| +
4848

49-
error[E0277]: the trait bound `D: Copy` is not satisfied
49+
error[E0277]: the trait bound `B<D>: Copy` is not satisfied
5050
--> $DIR/deriving-copyclone.rs:35:13
5151
|
5252
LL | is_copy(B { a: 1, b: D });

src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr

+3-9
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ LL | is_send(Box::new(TestType));
6565
| |
6666
| required by a bound introduced by this call
6767
|
68-
= note: the trait bound `dummy2::TestType: Send` is not satisfied
68+
= note: the trait bound `Unique<dummy2::TestType>: Send` is not satisfied
6969
= note: required because of the requirements on the impl of `Send` for `Unique<dummy2::TestType>`
7070
= note: required because it appears within the type `Box<dummy2::TestType>`
7171
note: required by a bound in `is_send`
@@ -104,11 +104,11 @@ error[E0277]: `main::TestType` cannot be sent between threads safely
104104
--> $DIR/negated-auto-traits-error.rs:66:13
105105
|
106106
LL | is_sync(Outer2(TestType));
107-
| ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync`
107+
| ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely
108108
| |
109109
| required by a bound introduced by this call
110110
|
111-
= note: the trait bound `main::TestType: Sync` is not satisfied
111+
= help: the trait `Send` is not implemented for `main::TestType`
112112
note: required because of the requirements on the impl of `Sync` for `Outer2<main::TestType>`
113113
--> $DIR/negated-auto-traits-error.rs:14:22
114114
|
@@ -119,12 +119,6 @@ note: required by a bound in `is_sync`
119119
|
120120
LL | fn is_sync<T: Sync>(_: T) {}
121121
| ^^^^ required by this bound in `is_sync`
122-
help: consider borrowing here
123-
|
124-
LL | is_sync(&Outer2(TestType));
125-
| +
126-
LL | is_sync(&mut Outer2(TestType));
127-
| ++++
128122

129123
error: aborting due to 7 previous errors
130124

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Do not suggest referencing the parameter to `check`
2+
3+
trait Marker<T> {}
4+
5+
impl<T> Marker<i32> for T {}
6+
7+
pub fn check<T: Marker<u32>>(_: T) {}
8+
9+
pub fn main() {
10+
check::<()>(()); //~ ERROR [E0277]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: the trait bound `(): Marker<u32>` is not satisfied
2+
--> $DIR/issue-90804-incorrect-reference-suggestion.rs:10:17
3+
|
4+
LL | check::<()>(());
5+
| ----------- ^^ the trait `Marker<u32>` is not implemented for `()`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `check`
10+
--> $DIR/issue-90804-incorrect-reference-suggestion.rs:7:17
11+
|
12+
LL | pub fn check<T: Marker<u32>>(_: T) {}
13+
| ^^^^^^^^^^^ required by this bound in `check`
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)