Skip to content

Commit 64b58dd

Browse files
Pass correct param-env to error_implies
1 parent d5b4c2e commit 64b58dd

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)