Skip to content

Commit bf53598

Browse files
More precisely detect cycle errors from type_of on opaque
1 parent e7b3c94 commit bf53598

21 files changed

+241
-288
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub fn provide(providers: &mut Providers) {
5656
resolve_bound_vars::provide(providers);
5757
*providers = Providers {
5858
type_of: type_of::type_of,
59+
type_of_opaque: type_of::type_of_opaque,
5960
item_bounds: item_bounds::item_bounds,
6061
explicit_item_bounds: item_bounds::explicit_item_bounds,
6162
generics_of: generics_of::generics_of,

compiler/rustc_hir_analysis/src/collect/type_of.rs

+99-77
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use rustc_errors::{Applicability, StashKey};
22
use rustc_hir as hir;
3-
use rustc_hir::def_id::LocalDefId;
3+
use rustc_hir::def_id::{DefId, LocalDefId};
44
use rustc_hir::HirId;
5+
use rustc_middle::query::plumbing::CyclePlaceholder;
56
use rustc_middle::ty::print::with_forced_trimmed_paths;
67
use rustc_middle::ty::util::IntTypeExt;
78
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
@@ -388,86 +389,62 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
388389
}
389390
},
390391

391-
Node::Item(item) => {
392-
match item.kind {
393-
ItemKind::Static(ty, .., body_id) => {
394-
if is_suggestable_infer_ty(ty) {
395-
infer_placeholder_type(
396-
tcx,
397-
def_id,
398-
body_id,
399-
ty.span,
400-
item.ident,
401-
"static variable",
402-
)
403-
} else {
404-
icx.to_ty(ty)
405-
}
406-
}
407-
ItemKind::Const(ty, _, body_id) => {
408-
if is_suggestable_infer_ty(ty) {
409-
infer_placeholder_type(
410-
tcx, def_id, body_id, ty.span, item.ident, "constant",
411-
)
412-
} else {
413-
icx.to_ty(ty)
414-
}
415-
}
416-
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
417-
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
418-
spans if spans.len() > 0 => {
419-
let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
420-
span: spans.into(),
421-
note: (),
422-
});
423-
Ty::new_error(tcx, guar)
424-
}
425-
_ => icx.to_ty(*self_ty),
426-
},
427-
ItemKind::Fn(..) => {
428-
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
429-
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
430-
}
431-
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
432-
let def = tcx.adt_def(def_id);
433-
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
434-
Ty::new_adt(tcx, def, args)
392+
Node::Item(item) => match item.kind {
393+
ItemKind::Static(ty, .., body_id) => {
394+
if is_suggestable_infer_ty(ty) {
395+
infer_placeholder_type(
396+
tcx,
397+
def_id,
398+
body_id,
399+
ty.span,
400+
item.ident,
401+
"static variable",
402+
)
403+
} else {
404+
icx.to_ty(ty)
435405
}
436-
ItemKind::OpaqueTy(OpaqueTy {
437-
origin: hir::OpaqueTyOrigin::TyAlias { .. },
438-
..
439-
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
440-
// Opaque types desugared from `impl Trait`.
441-
ItemKind::OpaqueTy(&OpaqueTy {
442-
origin:
443-
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
444-
in_trait,
445-
..
446-
}) => {
447-
if in_trait && !tcx.defaultness(owner).has_value() {
448-
span_bug!(
449-
tcx.def_span(def_id),
450-
"tried to get type of this RPITIT with no definition"
451-
);
452-
}
453-
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
406+
}
407+
ItemKind::Const(ty, _, body_id) => {
408+
if is_suggestable_infer_ty(ty) {
409+
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
410+
} else {
411+
icx.to_ty(ty)
454412
}
455-
ItemKind::Trait(..)
456-
| ItemKind::TraitAlias(..)
457-
| ItemKind::Macro(..)
458-
| ItemKind::Mod(..)
459-
| ItemKind::ForeignMod { .. }
460-
| ItemKind::GlobalAsm(..)
461-
| ItemKind::ExternCrate(..)
462-
| ItemKind::Use(..) => {
463-
span_bug!(
464-
item.span,
465-
"compute_type_of_item: unexpected item type: {:?}",
466-
item.kind
467-
);
413+
}
414+
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
415+
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
416+
spans if spans.len() > 0 => {
417+
let guar = tcx
418+
.sess
419+
.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
420+
Ty::new_error(tcx, guar)
468421
}
422+
_ => icx.to_ty(*self_ty),
423+
},
424+
ItemKind::Fn(..) => {
425+
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
426+
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
469427
}
470-
}
428+
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
429+
let def = tcx.adt_def(def_id);
430+
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
431+
Ty::new_adt(tcx, def, args)
432+
}
433+
ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
434+
|CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
435+
|ty| ty.instantiate_identity(),
436+
),
437+
ItemKind::Trait(..)
438+
| ItemKind::TraitAlias(..)
439+
| ItemKind::Macro(..)
440+
| ItemKind::Mod(..)
441+
| ItemKind::ForeignMod { .. }
442+
| ItemKind::GlobalAsm(..)
443+
| ItemKind::ExternCrate(..)
444+
| ItemKind::Use(..) => {
445+
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
446+
}
447+
},
471448

472449
Node::ForeignItem(foreign_item) => match foreign_item.kind {
473450
ForeignItemKind::Fn(..) => {
@@ -514,6 +491,51 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
514491
ty::EarlyBinder::bind(output)
515492
}
516493

494+
pub(super) fn type_of_opaque(
495+
tcx: TyCtxt<'_>,
496+
def_id: DefId,
497+
) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
498+
if let Some(def_id) = def_id.as_local() {
499+
use rustc_hir::*;
500+
501+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
502+
Ok(ty::EarlyBinder::bind(match tcx.hir().get(hir_id) {
503+
Node::Item(item) => match item.kind {
504+
ItemKind::OpaqueTy(OpaqueTy {
505+
origin: hir::OpaqueTyOrigin::TyAlias { .. },
506+
..
507+
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
508+
// Opaque types desugared from `impl Trait`.
509+
ItemKind::OpaqueTy(&OpaqueTy {
510+
origin:
511+
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
512+
in_trait,
513+
..
514+
}) => {
515+
if in_trait && !tcx.defaultness(owner).has_value() {
516+
span_bug!(
517+
tcx.def_span(def_id),
518+
"tried to get type of this RPITIT with no definition"
519+
);
520+
}
521+
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
522+
}
523+
_ => {
524+
span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
525+
}
526+
},
527+
528+
x => {
529+
bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
530+
}
531+
}))
532+
} else {
533+
// Foreign opaque type will go through the foreign provider
534+
// and load the type from metadata.
535+
Ok(tcx.type_of(def_id))
536+
}
537+
}
538+
517539
fn infer_placeholder_type<'a>(
518540
tcx: TyCtxt<'a>,
519541
def_id: LocalDefId,

compiler/rustc_middle/src/query/erase.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::mir;
2+
use crate::query::CyclePlaceholder;
23
use crate::traits;
34
use crate::ty::{self, Ty};
45
use std::mem::{size_of, transmute_copy, MaybeUninit};
@@ -142,6 +143,10 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
142143
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
143144
}
144145

146+
impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
147+
type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
148+
}
149+
145150
impl<T> EraseType for Option<&'_ T> {
146151
type Result = [u8; size_of::<Option<&'static ()>>()];
147152
}

compiler/rustc_middle/src/query/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::mir::interpret::{
2626
use crate::mir::interpret::{LitToConstError, LitToConstInput};
2727
use crate::mir::mono::CodegenUnit;
2828
use crate::query::erase::{erase, restore, Erase};
29-
use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
29+
use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery};
3030
use crate::thir;
3131
use crate::traits::query::{
3232
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@@ -243,6 +243,16 @@ rustc_queries! {
243243
feedable
244244
}
245245

246+
/// Specialized instance of `type_of` that detects cycles that are due to
247+
/// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
248+
/// to be handled separately, call `type_of` instead.
249+
query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
250+
desc { |tcx|
251+
"computing type of opaque `{path}`",
252+
path = tcx.def_path_str(key),
253+
}
254+
}
255+
246256
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
247257
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
248258
{

compiler/rustc_middle/src/query/plumbing.rs

+3
Original file line numberDiff line numberDiff line change
@@ -630,3 +630,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
630630
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
631631
}
632632
}
633+
634+
#[derive(Copy, Clone, Debug, HashStable)]
635+
pub struct CyclePlaceholder(pub ErrorGuaranteed);

compiler/rustc_middle/src/values.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::dep_graph::DepKind;
2+
use crate::query::plumbing::CyclePlaceholder;
23
use rustc_data_structures::fx::FxHashSet;
34
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
45
use rustc_hir as hir;
@@ -24,6 +25,16 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
2425
}
2526
}
2627

28+
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
29+
fn from_cycle_error(
30+
_tcx: TyCtxt<'tcx>,
31+
_: &[QueryInfo<DepKind>],
32+
guar: ErrorGuaranteed,
33+
) -> Self {
34+
Err(CyclePlaceholder(guar))
35+
}
36+
}
37+
2738
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
2839
fn from_cycle_error(
2940
tcx: TyCtxt<'tcx>,

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -2346,14 +2346,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
23462346
}
23472347

23482348
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
2349-
let ty = self.tcx().type_of(def_id);
2350-
if ty.skip_binder().references_error() {
2351-
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2352-
}
23532349
// We can resolve the `impl Trait` to its concrete type,
23542350
// which enforces a DAG between the functions requiring
23552351
// the auto trait bounds in question.
2356-
t.rebind(vec![ty.instantiate(self.tcx(), args)])
2352+
match self.tcx().type_of_opaque(def_id) {
2353+
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
2354+
Err(_) => {
2355+
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2356+
}
2357+
}
23572358
}
23582359
})
23592360
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// edition: 2021
2+
3+
// Makes sure we don't spew a bunch of unrelated opaque errors when the reason
4+
// for this error is just a missing struct field in `foo`.
5+
6+
async fn foo() {
7+
let y = Wrapper { };
8+
//~^ ERROR missing field `t` in initializer of `Wrapper<_>`
9+
}
10+
11+
struct Wrapper<T> { t: T }
12+
13+
fn is_send<T: Send>(_: T) {}
14+
15+
fn main() {
16+
is_send(foo());
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0063]: missing field `t` in initializer of `Wrapper<_>`
2+
--> $DIR/future-contains-err-issue-115188.rs:7:13
3+
|
4+
LL | let y = Wrapper { };
5+
| ^^^^^^^ missing `t`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0063`.

tests/ui/generator/layout-error.rs

-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,5 @@ 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
2827
Task::spawn(&POOL, || cb());
2928
}

tests/ui/generator/layout-error.stderr

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

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
7+
error: aborting due to previous error
268

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

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

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ fn cycle1() -> impl Clone {
1212
//~^ ERROR cycle detected
1313
//~| ERROR cycle detected
1414
send(cycle2().clone());
15-
//~^ ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
1615

1716
Rc::new(Cell::new(5))
1817
}

0 commit comments

Comments
 (0)