Skip to content

Commit 0334b64

Browse files
Rollup merge of rust-lang#113320 - oli-obk:eval_obligation_query, r=petrochenkov,BoxyUwU
Add some extra information to opaque type cycle errors Plus a bunch of cleanups. This should help users debug query cycles due to auto trait checking. We'll probably want to fix cycle errors in most (or all?) cases by looking at the current item's hidden types (new solver does this), and by delaying the auto trait checks to after typeck.
2 parents 5c7a7d9 + 9e98feb commit 0334b64

File tree

18 files changed

+443
-55
lines changed

18 files changed

+443
-55
lines changed

compiler/rustc_middle/src/traits/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,10 @@ pub enum SelectionError<'tcx> {
588588
/// Signaling that an error has already been emitted, to avoid
589589
/// multiple errors being shown.
590590
ErrorReporting,
591+
/// Computing an opaque type's hidden type caused an error (e.g. a cycle error).
592+
/// We can thus not know whether the hidden type implements an auto trait, so
593+
/// we should not presume anything about it.
594+
OpaqueTypeAutoTraitLeakageUnknown(DefId),
591595
}
592596

593597
#[derive(Clone, Debug, TypeVisitable, Lift)]

compiler/rustc_query_system/src/query/plumbing.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -126,33 +126,27 @@ where
126126

127127
#[cold]
128128
#[inline(never)]
129-
fn mk_cycle<Q, Qcx>(
130-
query: Q,
131-
qcx: Qcx,
132-
cycle_error: CycleError<Qcx::DepKind>,
133-
handler: HandleCycleError,
134-
) -> Q::Value
129+
fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value
135130
where
136131
Q: QueryConfig<Qcx>,
137132
Qcx: QueryContext,
138133
{
139134
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
140-
handle_cycle_error(query, qcx, &cycle_error, error, handler)
135+
handle_cycle_error(query, qcx, &cycle_error, error)
141136
}
142137

143138
fn handle_cycle_error<Q, Qcx>(
144139
query: Q,
145140
qcx: Qcx,
146141
cycle_error: &CycleError<Qcx::DepKind>,
147142
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
148-
handler: HandleCycleError,
149143
) -> Q::Value
150144
where
151145
Q: QueryConfig<Qcx>,
152146
Qcx: QueryContext,
153147
{
154148
use HandleCycleError::*;
155-
match handler {
149+
match query.handle_cycle_error() {
156150
Error => {
157151
error.emit();
158152
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle)
@@ -277,7 +271,7 @@ where
277271
&qcx.current_query_job(),
278272
span,
279273
);
280-
(mk_cycle(query, qcx, error, query.handle_cycle_error()), None)
274+
(mk_cycle(query, qcx, error), None)
281275
}
282276

283277
#[inline(always)]
@@ -314,7 +308,7 @@ where
314308

315309
(v, Some(index))
316310
}
317-
Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None),
311+
Err(cycle) => (mk_cycle(query, qcx, cycle), None),
318312
}
319313
}
320314

compiler/rustc_query_system/src/values.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
66
}
77

88
impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
9-
default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo<D>]) -> T {
9+
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T {
1010
tcx.sess().abort_if_errors();
1111
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
1212
// non-trivial to define it earlier.
13-
panic!("Value::from_cycle_error called without errors");
13+
panic!(
14+
"<{} as Value>::from_cycle_error called without errors: {cycle:#?}",
15+
std::any::type_name::<T>()
16+
);
1417
}
1518
}

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

+48-10
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt;
3030
use rustc_infer::infer::{InferOk, TypeTrace};
3131
use rustc_middle::traits::select::OverflowError;
3232
use rustc_middle::traits::solve::Goal;
33-
use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
33+
use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
3434
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
3535
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3636
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
@@ -1152,6 +1152,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
11521152
}
11531153
}
11541154

1155+
SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
1156+
&obligation,
1157+
def_id,
1158+
),
1159+
11551160
TraitNotObjectSafe(did) => {
11561161
let violations = self.tcx.object_safety_violations(did);
11571162
report_object_safety_error(self.tcx, span, did, violations)
@@ -1170,16 +1175,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
11701175
}
11711176

11721177
// Already reported in the query.
1173-
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => {
1174-
// FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token.
1175-
self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
1176-
return;
1177-
}
1178+
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
11781179
// Already reported.
1179-
Overflow(OverflowError::Error(_)) => {
1180-
self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
1181-
return;
1182-
}
1180+
Overflow(OverflowError::Error(_)) => return,
1181+
11831182
Overflow(_) => {
11841183
bug!("overflow should be handled before the `report_selection_error` path");
11851184
}
@@ -1471,6 +1470,12 @@ trait InferCtxtPrivExt<'tcx> {
14711470
terr: TypeError<'tcx>,
14721471
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
14731472

1473+
fn report_opaque_type_auto_trait_leakage(
1474+
&self,
1475+
obligation: &PredicateObligation<'tcx>,
1476+
def_id: DefId,
1477+
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
1478+
14741479
fn report_type_parameter_mismatch_error(
14751480
&self,
14761481
obligation: &PredicateObligation<'tcx>,
@@ -3192,6 +3197,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
31923197
)
31933198
}
31943199

3200+
fn report_opaque_type_auto_trait_leakage(
3201+
&self,
3202+
obligation: &PredicateObligation<'tcx>,
3203+
def_id: DefId,
3204+
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
3205+
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
3206+
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
3207+
format!("opaque type")
3208+
}
3209+
hir::OpaqueTyOrigin::TyAlias { .. } => {
3210+
format!("`{}`", self.tcx.def_path_debug_str(def_id))
3211+
}
3212+
};
3213+
let mut err = self.tcx.sess.struct_span_err(
3214+
obligation.cause.span,
3215+
format!("cannot check whether the hidden type of {name} satisfies auto traits"),
3216+
);
3217+
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
3218+
match self.defining_use_anchor {
3219+
DefiningAnchor::Bubble | DefiningAnchor::Error => {}
3220+
DefiningAnchor::Bind(bind) => {
3221+
err.span_note(
3222+
self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
3223+
"this item depends on auto traits of the hidden type, \
3224+
but may also be registering the hidden type. \
3225+
This is not supported right now. \
3226+
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
3227+
);
3228+
}
3229+
};
3230+
err
3231+
}
3232+
31953233
fn report_type_parameter_mismatch_error(
31963234
&self,
31973235
obligation: &PredicateObligation<'tcx>,

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
6767
}
6868

6969
AutoImplCandidate => {
70-
let data = self.confirm_auto_impl_candidate(obligation);
70+
let data = self.confirm_auto_impl_candidate(obligation)?;
7171
ImplSource::Builtin(data)
7272
}
7373

@@ -376,12 +376,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
376376
fn confirm_auto_impl_candidate(
377377
&mut self,
378378
obligation: &TraitObligation<'tcx>,
379-
) -> Vec<PredicateObligation<'tcx>> {
379+
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
380380
debug!(?obligation, "confirm_auto_impl_candidate");
381381

382382
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
383-
let types = self.constituent_types_for_ty(self_ty);
384-
self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)
383+
let types = self.constituent_types_for_ty(self_ty)?;
384+
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types))
385385
}
386386

387387
/// See `confirm_auto_impl_candidate`.

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -2271,8 +2271,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
22712271
fn constituent_types_for_ty(
22722272
&self,
22732273
t: ty::Binder<'tcx, Ty<'tcx>>,
2274-
) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
2275-
match *t.skip_binder().kind() {
2274+
) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
2275+
Ok(match *t.skip_binder().kind() {
22762276
ty::Uint(_)
22772277
| ty::Int(_)
22782278
| ty::Bool
@@ -2336,12 +2336,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
23362336
}
23372337

23382338
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
2339+
let ty = self.tcx().type_of(def_id);
2340+
if ty.skip_binder().references_error() {
2341+
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2342+
}
23392343
// We can resolve the `impl Trait` to its concrete type,
23402344
// which enforces a DAG between the functions requiring
23412345
// the auto trait bounds in question.
2342-
t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)])
2346+
t.rebind(vec![ty.subst(self.tcx(), substs)])
23432347
}
2344-
}
2348+
})
23452349
}
23462350

23472351
fn collect_predicates_for_types(

tests/ui/generator/layout-error.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ fn main() {
2424
type F = impl Future;
2525
// Check that statics are inhabited computes they layout.
2626
static POOL: Task<F> = Task::new();
27+
//~^ ERROR: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits
2728
Task::spawn(&POOL, || cb());
2829
}

tests/ui/generator/layout-error.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ error[E0425]: cannot find value `Foo` in this scope
44
LL | let a = Foo;
55
| ^^^ not found in this scope
66

7-
error: aborting due to previous error
7+
error: cannot check whether the hidden type of `layout_error[b009]::main::F::{opaque#0}` satisfies auto traits
8+
--> $DIR/layout-error.rs:26:18
9+
|
10+
LL | static POOL: Task<F> = Task::new();
11+
| ^^^^^^^
12+
|
13+
note: opaque type is declared here
14+
--> $DIR/layout-error.rs:24:14
15+
|
16+
LL | type F = impl Future;
17+
| ^^^^^^^^^^^
18+
note: required because it appears within the type `Task<F>`
19+
--> $DIR/layout-error.rs:9:12
20+
|
21+
LL | pub struct Task<F: Future>(F);
22+
| ^^^^
23+
= note: shared static variables must have a type that implements `Sync`
24+
25+
error: aborting due to 2 previous errors
826

927
For more information about this error, try `rustc --explain E0425`.

tests/ui/impl-trait/auto-trait-leak.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@ use std::rc::Rc;
33

44
fn send<T: Send>(_: T) {}
55

6-
fn main() {
7-
}
6+
fn main() {}
87

98
// Cycles should work as the deferred obligations are
109
// independently resolved and only require the concrete
1110
// return type, which can't depend on the obligation.
1211
fn cycle1() -> impl Clone {
1312
//~^ ERROR cycle detected
13+
//~| ERROR cycle detected
1414
send(cycle2().clone());
15+
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
1516

1617
Rc::new(Cell::new(5))
1718
}
1819

1920
fn cycle2() -> impl Clone {
2021
send(cycle1().clone());
22+
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
2123

2224
Rc::new(String::from("foo"))
2325
}

0 commit comments

Comments
 (0)