Skip to content

Commit 830aeb6

Browse files
Use a query rather than recomputing the tail repeatedly
1 parent ccdfd31 commit 830aeb6

File tree

13 files changed

+234
-90
lines changed

13 files changed

+234
-90
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+3-23
Original file line numberDiff line numberDiff line change
@@ -937,27 +937,7 @@ fn check_impl_items_against_trait<'tcx>(
937937

938938
let trait_def = tcx.trait_def(trait_ref.def_id);
939939

940-
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
941-
942-
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
943-
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
944-
let param_env = tcx.param_env(impl_id);
945-
946-
let self_is_guaranteed_unsized = tcx
947-
.struct_tail_raw(
948-
trait_ref.self_ty(),
949-
|ty| {
950-
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
951-
Ty::new_error_with_message(
952-
tcx,
953-
tcx.def_span(impl_id),
954-
"struct tail should be computable",
955-
)
956-
})
957-
},
958-
|| (),
959-
)
960-
.is_guaranteed_unsized_raw();
940+
let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id);
961941

962942
for &impl_item in impl_item_refs {
963943
let ty_impl_item = tcx.associated_item(impl_item);
@@ -988,7 +968,7 @@ fn check_impl_items_against_trait<'tcx>(
988968
}
989969
}
990970

991-
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
971+
if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) {
992972
tcx.emit_node_span_lint(
993973
rustc_lint_defs::builtin::DEAD_CODE,
994974
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
@@ -1023,7 +1003,7 @@ fn check_impl_items_against_trait<'tcx>(
10231003
if !is_implemented
10241004
&& tcx.defaultness(impl_id).is_final()
10251005
// unsized types don't need to implement methods that have `Self: Sized` bounds.
1026-
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
1006+
&& !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id))
10271007
{
10281008
missing_items.push(tcx.associated_item(trait_item_id));
10291009
}

compiler/rustc_middle/src/query/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,13 @@ rustc_queries! {
10261026
separate_provide_extern
10271027
}
10281028

1029+
/// Given an `impl_def_id`, return true if the self type is guaranteed to be unsized due
1030+
/// to either being one of the built-in unsized types (str/slice/dyn) or to be a struct
1031+
/// whose tail is one of those types.
1032+
query impl_self_is_guaranteed_unsized(impl_def_id: DefId) -> bool {
1033+
desc { |tcx| "computing whether `{}` has a guaranteed unsized self type", tcx.def_path_str(impl_def_id) }
1034+
}
1035+
10291036
/// Maps a `DefId` of a type to a list of its inherent impls.
10301037
/// Contains implementations of methods that are inherent to a type.
10311038
/// Methods in these implementations don't need to be exported.

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
437437
)
438438
}
439439

440+
fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool {
441+
self.impl_self_is_guaranteed_unsized(impl_def_id)
442+
}
443+
440444
fn has_target_features(self, def_id: DefId) -> bool {
441445
!self.codegen_fn_attrs(def_id).target_features.is_empty()
442446
}

compiler/rustc_middle/src/ty/sty.rs

-37
Original file line numberDiff line numberDiff line change
@@ -2029,43 +2029,6 @@ impl<'tcx> Ty<'tcx> {
20292029
pub fn is_known_rigid(self) -> bool {
20302030
self.kind().is_known_rigid()
20312031
}
2032-
2033-
/// Returns true if the type is guaranteed to be one of the three built-in unsized types:
2034-
/// `dyn Trait`/`[T]`/`str`. This function is *raw* because it does not compute the struct
2035-
/// tail of the type, so you are responsible for doing that yourself.
2036-
// NOTE: Keep this in sync with `rustc_type_ir`'s copy.
2037-
pub fn is_guaranteed_unsized_raw(self) -> bool {
2038-
match self.kind() {
2039-
Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
2040-
Bool
2041-
| Char
2042-
| Int(_)
2043-
| Uint(_)
2044-
| Float(_)
2045-
| Adt(_, _)
2046-
| Foreign(_)
2047-
| Array(_, _)
2048-
| Pat(_, _)
2049-
| RawPtr(_, _)
2050-
| Ref(_, _, _)
2051-
| FnDef(_, _)
2052-
| FnPtr(_, _)
2053-
| UnsafeBinder(_)
2054-
| Closure(_, _)
2055-
| CoroutineClosure(_, _)
2056-
| Coroutine(_, _)
2057-
| CoroutineWitness(_, _)
2058-
| Never
2059-
| Tuple(_)
2060-
| Alias(_, _)
2061-
| Param(_)
2062-
| Bound(_, _)
2063-
| Placeholder(_)
2064-
| Infer(_)
2065-
| Error(_)
2066-
| Dynamic(_, _, ty::DynStar) => false,
2067-
}
2068-
}
20692032
}
20702033

20712034
impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ where
237237
// has a trivially false `Sized` predicate). If it's the latter, we cannot
238238
// delay a bug because we can have trivially false where clauses, so we
239239
// treat it as rigid.
240-
if goal_trait_ref.self_ty().is_guaranteed_unsized_raw() {
240+
if cx.impl_self_is_guaranteed_unsized(impl_def_id) {
241241
ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
242242
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
243243
} else {

compiler/rustc_trait_selection/src/traits/project.rs

+1-15
Original file line numberDiff line numberDiff line change
@@ -2007,21 +2007,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20072007
"confirm_impl_candidate: no associated type {:?} for {:?}",
20082008
assoc_ty.item.name, obligation.predicate
20092009
);
2010-
let tail = selcx.tcx().struct_tail_raw(
2011-
tcx.type_of(impl_def_id).instantiate(tcx, args),
2012-
|ty| {
2013-
normalize_with_depth_to(
2014-
selcx,
2015-
obligation.param_env,
2016-
obligation.cause.clone(),
2017-
obligation.recursion_depth + 1,
2018-
ty,
2019-
&mut nested,
2020-
)
2021-
},
2022-
|| {},
2023-
);
2024-
if tail.is_guaranteed_unsized_raw() {
2010+
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
20252011
// We treat this projection as rigid here, which is represented via
20262012
// `Projected::NoProgress`. This will ensure that the projection is
20272013
// checked for well-formedness, and it's either satisfied by a trivial

compiler/rustc_ty_utils/src/ty.rs

+57
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_hir as hir;
33
use rustc_hir::LangItem;
44
use rustc_hir::def::DefKind;
55
use rustc_index::bit_set::DenseBitSet;
6+
use rustc_infer::infer::TyCtxtInferExt;
67
use rustc_middle::bug;
78
use rustc_middle::query::Providers;
89
use rustc_middle::ty::{
@@ -312,6 +313,61 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe
312313
unsizing_params
313314
}
314315

316+
fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) -> bool {
317+
debug_assert_eq!(tcx.def_kind(impl_def_id), DefKind::Impl { of_trait: true });
318+
319+
let infcx = tcx.infer_ctxt().ignoring_regions().build(ty::TypingMode::non_body_analysis());
320+
321+
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
322+
let cause = traits::ObligationCause::dummy();
323+
let param_env = tcx.param_env(impl_def_id);
324+
325+
let tail = tcx.struct_tail_raw(
326+
tcx.type_of(impl_def_id).instantiate_identity(),
327+
|ty| {
328+
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
329+
Ty::new_error_with_message(
330+
tcx,
331+
tcx.def_span(impl_def_id),
332+
"struct tail should be computable",
333+
)
334+
})
335+
},
336+
|| (),
337+
);
338+
339+
match tail.kind() {
340+
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
341+
ty::Bool
342+
| ty::Char
343+
| ty::Int(_)
344+
| ty::Uint(_)
345+
| ty::Float(_)
346+
| ty::Adt(_, _)
347+
| ty::Foreign(_)
348+
| ty::Array(_, _)
349+
| ty::Pat(_, _)
350+
| ty::RawPtr(_, _)
351+
| ty::Ref(_, _, _)
352+
| ty::FnDef(_, _)
353+
| ty::FnPtr(_, _)
354+
| ty::UnsafeBinder(_)
355+
| ty::Closure(_, _)
356+
| ty::CoroutineClosure(_, _)
357+
| ty::Coroutine(_, _)
358+
| ty::CoroutineWitness(_, _)
359+
| ty::Never
360+
| ty::Tuple(_)
361+
| ty::Alias(_, _)
362+
| ty::Param(_)
363+
| ty::Bound(_, _)
364+
| ty::Placeholder(_)
365+
| ty::Infer(_)
366+
| ty::Error(_)
367+
| ty::Dynamic(_, _, ty::DynStar) => false,
368+
}
369+
}
370+
315371
pub(crate) fn provide(providers: &mut Providers) {
316372
*providers = Providers {
317373
asyncness,
@@ -320,6 +376,7 @@ pub(crate) fn provide(providers: &mut Providers) {
320376
param_env_normalized_for_post_analysis,
321377
defaultness,
322378
unsizing_params_for_adt,
379+
impl_self_is_guaranteed_unsized,
323380
..*providers
324381
};
325382
}

compiler/rustc_type_ir/src/interner.rs

+2
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ pub trait Interner:
255255
def_id: Self::DefId,
256256
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
257257

258+
fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool;
259+
258260
fn has_target_features(self, def_id: Self::DefId) -> bool;
259261

260262
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;

tests/ui/associated-types/impl-wf-cycle-4.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ trait Filter {
22
type ToMatch;
33
}
44

5-
impl<T> Filter for T //~ ERROR overflow evaluating the requirement
5+
impl<T> Filter for T //~ ERROR cycle detected when
66
where
77
T: Fn(Self::ToMatch),
88
{
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
1-
error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch`
1+
error[E0391]: cycle detected when computing normalized predicates of `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>`
22
--> $DIR/impl-wf-cycle-4.rs:5:1
33
|
44
LL | / impl<T> Filter for T
55
LL | | where
66
LL | | T: Fn(Self::ToMatch),
77
| |_________________________^
88
|
9-
note: required for `T` to implement `Filter`
10-
--> $DIR/impl-wf-cycle-4.rs:5:9
9+
note: ...which requires computing whether `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>` has a guaranteed unsized self type...
10+
--> $DIR/impl-wf-cycle-4.rs:5:1
1111
|
12-
LL | impl<T> Filter for T
13-
| ^^^^^^ ^
14-
LL | where
15-
LL | T: Fn(Self::ToMatch),
16-
| ----------------- unsatisfied trait bound introduced here
17-
note: associated types for the current `impl` cannot be restricted in `where` clauses
18-
--> $DIR/impl-wf-cycle-4.rs:7:11
12+
LL | / impl<T> Filter for T
13+
LL | | where
14+
LL | | T: Fn(Self::ToMatch),
15+
| |_________________________^
16+
= note: ...which again requires computing normalized predicates of `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>`, completing the cycle
17+
note: cycle used when checking that `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>` is well-formed
18+
--> $DIR/impl-wf-cycle-4.rs:5:1
1919
|
20-
LL | T: Fn(Self::ToMatch),
21-
| ^^^^^^^^^^^^^
20+
LL | / impl<T> Filter for T
21+
LL | | where
22+
LL | | T: Fn(Self::ToMatch),
23+
| |_________________________^
24+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
2225

2326
error: aborting due to 1 previous error
2427

25-
For more information about this error, try `rustc --explain E0275`.
28+
For more information about this error, try `rustc --explain E0391`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
2+
--> $DIR/trivial-unsized-projection-2.rs:22:12
3+
|
4+
LL | const FOO: <Tail as Bad>::Assert = todo!();
5+
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
8+
note: required because it appears within the type `Tail`
9+
--> $DIR/trivial-unsized-projection-2.rs:17:8
10+
|
11+
LL | struct Tail([()]);
12+
| ^^^^
13+
note: required by a bound in `Bad::Assert`
14+
--> $DIR/trivial-unsized-projection-2.rs:14:15
15+
|
16+
LL | type Assert
17+
| ------ required by a bound in this associated type
18+
LL | where
19+
LL | Self: Sized;
20+
| ^^^^^ required by this bound in `Bad::Assert`
21+
help: consider relaxing the implicit `Sized` restriction
22+
|
23+
LL | type Assert: ?Sized
24+
| ++++++++
25+
26+
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
27+
--> $DIR/trivial-unsized-projection-2.rs:22:12
28+
|
29+
LL | const FOO: <Tail as Bad>::Assert = todo!();
30+
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
31+
|
32+
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
33+
note: required because it appears within the type `Tail`
34+
--> $DIR/trivial-unsized-projection-2.rs:17:8
35+
|
36+
LL | struct Tail([()]);
37+
| ^^^^
38+
note: required by a bound in `Bad::Assert`
39+
--> $DIR/trivial-unsized-projection-2.rs:14:15
40+
|
41+
LL | type Assert
42+
| ------ required by a bound in this associated type
43+
LL | where
44+
LL | Self: Sized;
45+
| ^^^^^ required by this bound in `Bad::Assert`
46+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
47+
help: consider relaxing the implicit `Sized` restriction
48+
|
49+
LL | type Assert: ?Sized
50+
| ++++++++
51+
52+
error: aborting due to 2 previous errors
53+
54+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
2+
--> $DIR/trivial-unsized-projection-2.rs:22:12
3+
|
4+
LL | const FOO: <Tail as Bad>::Assert = todo!();
5+
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
8+
note: required because it appears within the type `Tail`
9+
--> $DIR/trivial-unsized-projection-2.rs:17:8
10+
|
11+
LL | struct Tail([()]);
12+
| ^^^^
13+
note: required by a bound in `Bad::Assert`
14+
--> $DIR/trivial-unsized-projection-2.rs:14:15
15+
|
16+
LL | type Assert
17+
| ------ required by a bound in this associated type
18+
LL | where
19+
LL | Self: Sized;
20+
| ^^^^^ required by this bound in `Bad::Assert`
21+
help: consider relaxing the implicit `Sized` restriction
22+
|
23+
LL | type Assert: ?Sized
24+
| ++++++++
25+
26+
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
27+
--> $DIR/trivial-unsized-projection-2.rs:22:12
28+
|
29+
LL | const FOO: <Tail as Bad>::Assert = todo!();
30+
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
31+
|
32+
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
33+
note: required because it appears within the type `Tail`
34+
--> $DIR/trivial-unsized-projection-2.rs:17:8
35+
|
36+
LL | struct Tail([()]);
37+
| ^^^^
38+
note: required by a bound in `Bad::Assert`
39+
--> $DIR/trivial-unsized-projection-2.rs:14:15
40+
|
41+
LL | type Assert
42+
| ------ required by a bound in this associated type
43+
LL | where
44+
LL | Self: Sized;
45+
| ^^^^^ required by this bound in `Bad::Assert`
46+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
47+
help: consider relaxing the implicit `Sized` restriction
48+
|
49+
LL | type Assert: ?Sized
50+
| ++++++++
51+
52+
error: aborting due to 2 previous errors
53+
54+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)