Skip to content

Commit 32851f5

Browse files
authored
Rollup merge of rust-lang#135900 - compiler-errors:derive-wf, r=lcnr
Manually walk into WF obligations in `BestObligation` proof tree visitor When we encounter a `WellFormed` obligation in the `BestObligation` proof tree visitor, ignore the proof tree and call `wf::unnormalized_obligations` to derive well-formed obligations with the correct cause codes. This is to avoid having to replicate the somewhat delicate logic that `wf.rs` does to set up its obligation causes... Don't see a better way to do this. vibes?? r? lcnr
2 parents b6884eb + 94ef5cf commit 32851f5

19 files changed

+648
-580
lines changed

compiler/rustc_trait_selection/src/solve/delegate.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ops::Deref;
22

33
use rustc_data_structures::fx::FxHashSet;
4-
use rustc_hir::def_id::DefId;
4+
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
55
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
66
use rustc_infer::infer::canonical::{
77
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
@@ -98,9 +98,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
9898
param_env: ty::ParamEnv<'tcx>,
9999
arg: ty::GenericArg<'tcx>,
100100
) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
101-
crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| {
102-
obligations.into_iter().map(|obligation| obligation.into()).collect()
103-
})
101+
crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
102+
.map(|obligations| {
103+
obligations.into_iter().map(|obligation| obligation.into()).collect()
104+
})
104105
}
105106

106107
fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {

compiler/rustc_trait_selection/src/solve/fulfill.rs

+6-490
Large diffs are not rendered by default.

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+527
Large diffs are not rendered by default.

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

+46-36
Original file line numberDiff line numberDiff line change
@@ -194,47 +194,57 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
194194

195195
let goals = instantiated_goals
196196
.into_iter()
197-
.map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
198-
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
199-
let unconstrained_term = match term.unpack() {
200-
ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
201-
ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
202-
};
203-
let goal =
204-
goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
205-
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
206-
// expected term. This means that candidates which only fail due to nested goals
207-
// and which normalize to a different term then the final result could ICE: when
208-
// building their proof tree, the expected term was unconstrained, but when
209-
// instantiating the candidate it is already constrained to the result of another
210-
// candidate.
211-
let proof_tree = infcx
212-
.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
213-
InspectGoal::new(
214-
infcx,
215-
self.goal.depth + 1,
216-
proof_tree.unwrap(),
217-
Some(NormalizesToTermHack { term, unconstrained_term }),
218-
source,
219-
)
220-
}
221-
_ => {
222-
// We're using a probe here as evaluating a goal could constrain
223-
// inference variables by choosing one candidate. If we then recurse
224-
// into another candidate who ends up with different inference
225-
// constraints, we get an ICE if we already applied the constraints
226-
// from the chosen candidate.
227-
let proof_tree = infcx
228-
.probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
229-
.unwrap();
230-
InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
231-
}
232-
})
197+
.map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
233198
.collect();
234199

235200
(goals, opt_impl_args)
236201
}
237202

203+
pub fn instantiate_proof_tree_for_nested_goal(
204+
&self,
205+
source: GoalSource,
206+
goal: Goal<'tcx, ty::Predicate<'tcx>>,
207+
span: Span,
208+
) -> InspectGoal<'a, 'tcx> {
209+
let infcx = self.goal.infcx;
210+
match goal.predicate.kind().no_bound_vars() {
211+
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
212+
let unconstrained_term = match term.unpack() {
213+
ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
214+
ty::TermKind::Const(_) => infcx.next_const_var(span).into(),
215+
};
216+
let goal =
217+
goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
218+
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
219+
// expected term. This means that candidates which only fail due to nested goals
220+
// and which normalize to a different term then the final result could ICE: when
221+
// building their proof tree, the expected term was unconstrained, but when
222+
// instantiating the candidate it is already constrained to the result of another
223+
// candidate.
224+
let proof_tree =
225+
infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
226+
InspectGoal::new(
227+
infcx,
228+
self.goal.depth + 1,
229+
proof_tree.unwrap(),
230+
Some(NormalizesToTermHack { term, unconstrained_term }),
231+
source,
232+
)
233+
}
234+
_ => {
235+
// We're using a probe here as evaluating a goal could constrain
236+
// inference variables by choosing one candidate. If we then recurse
237+
// into another candidate who ends up with different inference
238+
// constraints, we get an ICE if we already applied the constraints
239+
// from the chosen candidate.
240+
let proof_tree = infcx
241+
.probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
242+
.unwrap();
243+
InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
244+
}
245+
}
246+
}
247+
238248
/// Visit all nested goals of this candidate, rolling back
239249
/// all inference constraints.
240250
pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {

compiler/rustc_trait_selection/src/traits/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt};
7676
use crate::regions::InferCtxtRegionExt;
7777
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
7878

79+
#[derive(Debug)]
7980
pub struct FulfillmentError<'tcx> {
8081
pub obligation: PredicateObligation<'tcx>,
8182
pub code: FulfillmentErrorCode<'tcx>,
@@ -107,12 +108,6 @@ impl<'tcx> FulfillmentError<'tcx> {
107108
}
108109
}
109110

110-
impl<'tcx> Debug for FulfillmentError<'tcx> {
111-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112-
write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
113-
}
114-
}
115-
116111
#[derive(Clone)]
117112
pub enum FulfillmentErrorCode<'tcx> {
118113
/// Inherently impossible to fulfill; this trait is implemented if and only

compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds;
55
use rustc_middle::infer::canonical::CanonicalQueryResponse;
66
use rustc_middle::traits::ObligationCause;
77
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
8-
use rustc_span::Span;
98
use rustc_span::def_id::CRATE_DEF_ID;
9+
use rustc_span::{DUMMY_SP, Span};
1010
use rustc_type_ir::outlives::{Component, push_outlives_components};
1111
use smallvec::{SmallVec, smallvec};
1212
use tracing::debug;
@@ -92,7 +92,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
9292

9393
// From the full set of obligations, just filter down to the region relationships.
9494
for obligation in
95-
wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
95+
wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
96+
.into_iter()
97+
.flatten()
9698
{
9799
assert!(!obligation.has_escaping_bound_vars());
98100
let Some(pred) = obligation.predicate.kind().no_bound_vars() else {

compiler/rustc_trait_selection/src/traits/wf.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_middle::ty::{
88
self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
99
TypeVisitable, TypeVisitableExt, TypeVisitor,
1010
};
11-
use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
12-
use rustc_span::{DUMMY_SP, Span};
11+
use rustc_span::Span;
12+
use rustc_span::def_id::{DefId, LocalDefId};
1313
use tracing::{debug, instrument, trace};
1414

1515
use crate::infer::InferCtxt;
@@ -89,6 +89,8 @@ pub fn unnormalized_obligations<'tcx>(
8989
infcx: &InferCtxt<'tcx>,
9090
param_env: ty::ParamEnv<'tcx>,
9191
arg: GenericArg<'tcx>,
92+
span: Span,
93+
body_id: LocalDefId,
9294
) -> Option<PredicateObligations<'tcx>> {
9395
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
9496

@@ -106,8 +108,8 @@ pub fn unnormalized_obligations<'tcx>(
106108
let mut wf = WfPredicates {
107109
infcx,
108110
param_env,
109-
body_id: CRATE_DEF_ID,
110-
span: DUMMY_SP,
111+
body_id,
112+
span,
111113
out: PredicateObligations::new(),
112114
recursion_depth: 0,
113115
item: None,

tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
55
| ^^^^^^^^^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `[u32]`
8+
note: required by an implicit `Sized` bound in `Vec`
9+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
810

911
error: aborting due to 1 previous error
1012

tests/ui/const-generics/issues/issue-88119.stderr

+14-20
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,29 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
66
|
77
= help: remove one of these features
88

9-
error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}`
10-
--> $DIR/issue-88119.rs:19:49
9+
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
10+
--> $DIR/issue-88119.rs:21:5
1111
|
12-
LL | impl<T: ?Sized + ConstName> const ConstName for &T
13-
| ^^ cannot normalize `<&T as ConstName>::{constant#0}`
12+
LL | [(); name_len::<T>()]:,
13+
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
1414
|
15-
note: required for `&T` to implement `~const ConstName`
16-
--> $DIR/issue-88119.rs:19:35
15+
note: required by a bound in `<&T as ConstName>`
16+
--> $DIR/issue-88119.rs:21:10
1717
|
18-
LL | impl<T: ?Sized + ConstName> const ConstName for &T
19-
| ^^^^^^^^^ ^^
20-
LL | where
2118
LL | [(); name_len::<T>()]:,
22-
| --------------------- unsatisfied trait bound introduced here
19+
| ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
2320

24-
error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
25-
--> $DIR/issue-88119.rs:26:49
21+
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
22+
--> $DIR/issue-88119.rs:28:5
2623
|
27-
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
28-
| ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
24+
LL | [(); name_len::<T>()]:,
25+
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
2926
|
30-
note: required for `&mut T` to implement `~const ConstName`
31-
--> $DIR/issue-88119.rs:26:35
27+
note: required by a bound in `<&mut T as ConstName>`
28+
--> $DIR/issue-88119.rs:28:10
3229
|
33-
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
34-
| ^^^^^^^^^ ^^^^^^
35-
LL | where
3630
LL | [(); name_len::<T>()]:,
37-
| --------------------- unsatisfied trait bound introduced here
31+
| ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
3832

3933
error: aborting due to 3 previous errors
4034

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr

+1-11
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,13 @@ LL | where
1616
LL | T: AsExpression<Self::SqlType>,
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
1818

19-
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
20-
--> $DIR/as_expression.rs:55:15
21-
|
22-
LL | SelectInt.check("bar");
23-
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
24-
|
25-
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
26-
but trait `AsExpression<Text>` is implemented for it
27-
= help: for that trait implementation, expected `Text`, found `Integer`
28-
2919
error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
3020
--> $DIR/as_expression.rs:55:5
3121
|
3222
LL | SelectInt.check("bar");
3323
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
3424

35-
error: aborting due to 3 previous errors
25+
error: aborting due to 2 previous errors
3626

3727
Some errors have detailed explanations: E0271, E0277.
3828
For more information about an error, try `rustc --explain E0271`.

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<T> Foo for T where T: Expression {}
5353

5454
fn main() {
5555
SelectInt.check("bar");
56-
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
57-
//[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
56+
//[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
57+
//[next]~^^ the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
5858
//[next]~| type mismatch
5959
}

tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ help: this trait has no implementations, consider adding one
1818
|
1919
LL | trait Foo {}
2020
| ^^^^^^^^^
21+
note: required by a bound in `A`
22+
--> $DIR/alias-bounds-when-not-wf.rs:8:11
23+
|
24+
LL | type A<T: Foo> = T;
25+
| ^^^ required by this bound in `A`
2126

2227
error[E0277]: the trait bound `usize: Foo` is not satisfied
2328
--> $DIR/alias-bounds-when-not-wf.rs:16:10

tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0284]: type annotations needed: cannot normalize `X::{constant#0}`
1+
error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
22
--> $DIR/const-region-infer-to-static-in-binder.rs:4:10
33
|
44
LL | struct X<const FN: fn() = { || {} }>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
66

77
error: using function pointers as const generic parameters is forbidden
88
--> $DIR/const-region-infer-to-static-in-binder.rs:4:20

tests/ui/traits/next-solver/specialization-transmute.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ LL | #![feature(specialization)]
1010

1111
error: cannot normalize `<T as Default>::Id: '_`
1212

13-
error[E0284]: type annotations needed: cannot normalize `<T as Default>::Id`
13+
error[E0282]: type annotations needed
1414
--> $DIR/specialization-transmute.rs:15:23
1515
|
1616
LL | fn intu(&self) -> &Self::Id {
17-
| ^^^^^^^^^ cannot normalize `<T as Default>::Id`
17+
| ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id`
1818

1919
error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T`
2020
--> $DIR/specialization-transmute.rs:17:9
@@ -36,4 +36,5 @@ LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
3636

3737
error: aborting due to 4 previous errors; 1 warning emitted
3838

39-
For more information about this error, try `rustc --explain E0284`.
39+
Some errors have detailed explanations: E0282, E0284.
40+
For more information about an error, try `rustc --explain E0282`.

tests/ui/union/union-derive-eq.next.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ LL | union U2 {
77
LL | a: PartialEqNotEq,
88
| ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
99
|
10+
note: required by a bound in `AssertParamIsEq`
11+
--> $SRC_DIR/core/src/cmp.rs:LL:COL
1012
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
1113
help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]`
1214
|

tests/ui/wf/wf-normalization-sized.next.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
55
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
8+
= note: slice and array elements must have `Sized` type
89

910
error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
1011
--> $DIR/wf-normalization-sized.rs:19:11
@@ -13,6 +14,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
1314
| ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
1415
|
1516
= help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
17+
= note: slice and array elements must have `Sized` type
1618
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1719

1820
error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -22,6 +24,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
2224
| ^^^^^^^^ doesn't have a size known at compile-time
2325
|
2426
= help: the trait `Sized` is not implemented for `str`
27+
note: required by an implicit `Sized` bound in `Vec`
28+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
2529

2630
error[E0277]: the size for values of type `str` cannot be known at compilation time
2731
--> $DIR/wf-normalization-sized.rs:22:11
@@ -30,6 +34,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
3034
| ^^^^^^^^ doesn't have a size known at compile-time
3135
|
3236
= help: the trait `Sized` is not implemented for `str`
37+
note: required by an implicit `Sized` bound in `Vec`
38+
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
3339
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
3440

3541
error: aborting due to 4 previous errors

tests/ui/wf/wf-trait-fn-arg.next.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
44
LL | fn bar(&self, x: &Bar<Self>);
55
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
66
|
7+
note: required by a bound in `Bar`
8+
--> $DIR/wf-trait-fn-arg.rs:11:15
9+
|
10+
LL | struct Bar<T: Eq + ?Sized> {
11+
| ^^ required by this bound in `Bar`
712
help: consider further restricting `Self`
813
|
914
LL | fn bar(&self, x: &Bar<Self>) where Self: Eq;

tests/ui/wf/wf-trait-fn-ret.next.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied
44
LL | fn bar(&self) -> &Bar<Self>;
55
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
66
|
7+
note: required by a bound in `Bar`
8+
--> $DIR/wf-trait-fn-ret.rs:10:15
9+
|
10+
LL | struct Bar<T: Eq + ?Sized> {
11+
| ^^ required by this bound in `Bar`
712
help: consider further restricting `Self`
813
|
914
LL | fn bar(&self) -> &Bar<Self> where Self: Eq;

0 commit comments

Comments
 (0)