Skip to content

Commit 69444d1

Browse files
authored
Unrolled build for rust-lang#139335
Rollup merge of rust-lang#139335 - compiler-errors:error-implies, r=oli-obk Pass correct param-env to `error_implies` Duplicated comment from the test: In the error reporting code, when reporting fulfillment errors for goals A and B, we try to see if elaborating A will result in another goal that can equate with B. That would signal that B is "implied by" A, allowing us to skip reporting it, which is beneficial for cutting down on the number of diagnostics we report. In the new trait solver especially, but even in the old trait solver through things like defining opaque type usages, this `can_equate` call was not properly taking the param-env of the goals, resulting in nested obligations that had empty param-envs. If one of these nested obligations was a `ConstParamHasTy` goal, then we would ICE, since those goals are particularly strict about the param-env they're evaluated in. This is morally a fix for <rust-lang#139314>, but that repro uses details about how defining usages in the `check_opaque_well_formed` code can spring out of type equality, and will likely stop failing soon coincidentally once we start using `PostBorrowck` mode in that check. Instead, we use lazy normalization to end up generating an alias-eq goal whose nested goals woul trigger the ICE instead, since this is a lot more stable. Fixes rust-lang#139314 r? ``@oli-obk`` or reassign
2 parents f174fd7 + 64b58dd commit 69444d1

File tree

5 files changed

+98
-29
lines changed

5 files changed

+98
-29
lines changed

compiler/rustc_infer/src/infer/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use rustc_middle::bug;
2727
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
2828
use rustc_middle::mir::ConstraintCategory;
2929
use rustc_middle::traits::select;
30+
use rustc_middle::traits::solve::Goal;
3031
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3132
use rustc_middle::ty::{
3233
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
@@ -268,7 +269,7 @@ pub struct InferCtxt<'tcx> {
268269
/// The set of predicates on which errors have been reported, to
269270
/// avoid reporting the same error twice.
270271
pub reported_trait_errors:
271-
RefCell<FxIndexMap<Span, (Vec<ty::Predicate<'tcx>>, ErrorGuaranteed)>>,
272+
RefCell<FxIndexMap<Span, (Vec<Goal<'tcx, ty::Predicate<'tcx>>>, ErrorGuaranteed)>>,
272273

273274
pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
274275

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

+21-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
1414
use rustc_hir::intravisit::Visitor;
1515
use rustc_hir::{self as hir, LangItem, Node};
1616
use rustc_infer::infer::{InferOk, TypeTrace};
17+
use rustc_infer::traits::solve::Goal;
1718
use rustc_middle::traits::SignatureMismatchData;
1819
use rustc_middle::traits::select::OverflowError;
1920
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -930,7 +931,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
930931
)) = arg.kind
931932
&& let Node::Pat(pat) = self.tcx.hir_node(*hir_id)
932933
&& let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)
933-
&& preds.contains(&obligation.predicate)
934+
&& preds.contains(&obligation.as_goal())
934935
{
935936
return Err(*guar);
936937
}
@@ -1292,6 +1293,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12921293
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12931294
fn can_match_trait(
12941295
&self,
1296+
param_env: ty::ParamEnv<'tcx>,
12951297
goal: ty::TraitPredicate<'tcx>,
12961298
assumption: ty::PolyTraitPredicate<'tcx>,
12971299
) -> bool {
@@ -1306,11 +1308,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13061308
assumption,
13071309
);
13081310

1309-
self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref)
1311+
self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref)
13101312
}
13111313

13121314
fn can_match_projection(
13131315
&self,
1316+
param_env: ty::ParamEnv<'tcx>,
13141317
goal: ty::ProjectionPredicate<'tcx>,
13151318
assumption: ty::PolyProjectionPredicate<'tcx>,
13161319
) -> bool {
@@ -1320,7 +1323,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13201323
assumption,
13211324
);
13221325

1323-
let param_env = ty::ParamEnv::empty();
13241326
self.can_eq(param_env, goal.projection_term, assumption.projection_term)
13251327
&& self.can_eq(param_env, goal.term, assumption.term)
13261328
}
@@ -1330,24 +1332,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13301332
#[instrument(level = "debug", skip(self), ret)]
13311333
pub(super) fn error_implies(
13321334
&self,
1333-
cond: ty::Predicate<'tcx>,
1334-
error: ty::Predicate<'tcx>,
1335+
cond: Goal<'tcx, ty::Predicate<'tcx>>,
1336+
error: Goal<'tcx, ty::Predicate<'tcx>>,
13351337
) -> bool {
13361338
if cond == error {
13371339
return true;
13381340
}
13391341

1340-
if let Some(error) = error.as_trait_clause() {
1342+
// FIXME: We could be smarter about this, i.e. if cond's param-env is a
1343+
// subset of error's param-env. This only matters when binders will carry
1344+
// predicates though, and obviously only matters for error reporting.
1345+
if cond.param_env != error.param_env {
1346+
return false;
1347+
}
1348+
let param_env = error.param_env;
1349+
1350+
if let Some(error) = error.predicate.as_trait_clause() {
13411351
self.enter_forall(error, |error| {
1342-
elaborate(self.tcx, std::iter::once(cond))
1352+
elaborate(self.tcx, std::iter::once(cond.predicate))
13431353
.filter_map(|implied| implied.as_trait_clause())
1344-
.any(|implied| self.can_match_trait(error, implied))
1354+
.any(|implied| self.can_match_trait(param_env, error, implied))
13451355
})
1346-
} else if let Some(error) = error.as_projection_clause() {
1356+
} else if let Some(error) = error.predicate.as_projection_clause() {
13471357
self.enter_forall(error, |error| {
1348-
elaborate(self.tcx, std::iter::once(cond))
1358+
elaborate(self.tcx, std::iter::once(cond.predicate))
13491359
.filter_map(|implied| implied.as_projection_clause())
1350-
.any(|implied| self.can_match_projection(error, implied))
1360+
.any(|implied| self.can_match_projection(param_env, error, implied))
13511361
})
13521362
} else {
13531363
false

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

+11-17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_cod
1212
use rustc_hir::def_id::{DefId, LocalDefId};
1313
use rustc_hir::intravisit::Visitor;
1414
use rustc_hir::{self as hir, AmbigArg, LangItem};
15+
use rustc_infer::traits::solve::Goal;
1516
use rustc_infer::traits::{
1617
DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
1718
PredicateObligation, SelectionError,
@@ -144,23 +145,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
144145

145146
#[derive(Debug)]
146147
struct ErrorDescriptor<'tcx> {
147-
predicate: ty::Predicate<'tcx>,
148+
goal: Goal<'tcx, ty::Predicate<'tcx>>,
148149
index: Option<usize>, // None if this is an old error
149150
}
150151

151152
let mut error_map: FxIndexMap<_, Vec<_>> = self
152153
.reported_trait_errors
153154
.borrow()
154155
.iter()
155-
.map(|(&span, predicates)| {
156-
(
157-
span,
158-
predicates
159-
.0
160-
.iter()
161-
.map(|&predicate| ErrorDescriptor { predicate, index: None })
162-
.collect(),
163-
)
156+
.map(|(&span, goals)| {
157+
(span, goals.0.iter().map(|&goal| ErrorDescriptor { goal, index: None }).collect())
164158
})
165159
.collect();
166160

@@ -186,10 +180,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
186180
span = expn_data.call_site;
187181
}
188182

189-
error_map.entry(span).or_default().push(ErrorDescriptor {
190-
predicate: error.obligation.predicate,
191-
index: Some(index),
192-
});
183+
error_map
184+
.entry(span)
185+
.or_default()
186+
.push(ErrorDescriptor { goal: error.obligation.as_goal(), index: Some(index) });
193187
}
194188

195189
// We do this in 2 passes because we want to display errors in order, though
@@ -210,9 +204,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
210204
continue;
211205
}
212206

213-
if self.error_implies(error2.predicate, error.predicate)
207+
if self.error_implies(error2.goal, error.goal)
214208
&& !(error2.index >= error.index
215-
&& self.error_implies(error.predicate, error2.predicate))
209+
&& self.error_implies(error.goal, error2.goal))
216210
{
217211
info!("skipping {:?} (implied by {:?})", error, error2);
218212
is_suppressed[index] = true;
@@ -243,7 +237,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
243237
.entry(span)
244238
.or_insert_with(|| (vec![], guar))
245239
.0
246-
.push(error.obligation.predicate);
240+
.push(error.obligation.as_goal());
247241
}
248242
}
249243
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// compile-flags: -Znext-solver
2+
3+
// Test for a weird diagnostics corner case. In the error reporting code, when reporting
4+
// fulfillment errors for goals A and B, we try to see if elaborating A will result in
5+
// another goal that can equate with B. That would signal that B is "implied by" A,
6+
// allowing us to skip reporting it, which is beneficial for cutting down on the number
7+
// of diagnostics we report. In the new trait solver especially, but even in the old trait
8+
// solver through things like defining opaque type usages, this `can_equate` call was not
9+
// properly taking the param-env of the goals, resulting in nested obligations that had
10+
// empty param-envs. If one of these nested obligations was a `ConstParamHasTy` goal, then
11+
// we would ICE, since those goals are particularly strict about the param-env they're
12+
// evaluated in.
13+
14+
// This is morally a fix for <https://github.com/rust-lang/rust/issues/139314>, but that
15+
// repro uses details about how defining usages in the `check_opaque_well_formed` code
16+
// can spring out of type equality, and will likely stop failing soon coincidentally once
17+
// we start using `PostBorrowck` mode in that check.
18+
19+
trait Foo: Baz<()> {}
20+
trait Baz<T> {}
21+
22+
trait IdentityWithConstArgGoal<const N: usize> {
23+
type Assoc;
24+
}
25+
impl<T, const N: usize> IdentityWithConstArgGoal<N> for T {
26+
type Assoc = T;
27+
}
28+
29+
fn unsatisfied<T, const N: usize>()
30+
where
31+
T: Foo,
32+
T: Baz<<T as IdentityWithConstArgGoal<N>>::Assoc>,
33+
{
34+
}
35+
36+
fn test<const N: usize>() {
37+
unsatisfied::<(), N>();
38+
//~^ ERROR the trait bound `(): Foo` is not satisfied
39+
}
40+
41+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `(): Foo` is not satisfied
2+
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:37:19
3+
|
4+
LL | unsatisfied::<(), N>();
5+
| ^^ the trait `Foo` is not implemented for `()`
6+
|
7+
help: this trait has no implementations, consider adding one
8+
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:19:1
9+
|
10+
LL | trait Foo: Baz<()> {}
11+
| ^^^^^^^^^^^^^^^^^^
12+
note: required by a bound in `unsatisfied`
13+
--> $DIR/const-param-has-ty-goal-in-error-implies.rs:31:8
14+
|
15+
LL | fn unsatisfied<T, const N: usize>()
16+
| ----------- required by a bound in this function
17+
LL | where
18+
LL | T: Foo,
19+
| ^^^ required by this bound in `unsatisfied`
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)