Skip to content

Commit d63962c

Browse files
FML
1 parent 582360d commit d63962c

File tree

10 files changed

+162
-61
lines changed

10 files changed

+162
-61
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,10 @@ rustc_queries! {
840840
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
841841
separate_provide_extern
842842
}
843+
query impl_may_be_shadowed_by_trait_object(impl_id: DefId) -> bool {
844+
desc { |tcx| "determining if `{}` is allowed to be shadowed by a `dyn Trait` object", tcx.def_path_str(impl_id) }
845+
cache_on_disk_if { true }
846+
}
843847

844848
query issue33140_self_ty(key: DefId) -> Option<ty::EarlyBinder<ty::Ty<'tcx>>> {
845849
desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) }

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -601,22 +601,23 @@ fn fetch_eligible_assoc_item_def<'tcx>(
601601
let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
602602
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
603603

604-
let eligible = if node_item.is_final() {
605-
// Non-specializable items are always projectable.
606-
true
607-
} else {
608-
// Only reveal a specializable default if we're past type-checking
609-
// and the obligation is monomorphic, otherwise passes such as
610-
// transmute checking and polymorphic MIR optimizations could
611-
// get a result which isn't correct for all monomorphizations.
612-
if param_env.reveal() == Reveal::All {
613-
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
614-
!poly_trait_ref.still_further_specializable()
604+
let eligible =
605+
if node_item.is_final() && !ecx.tcx().impl_may_be_shadowed_by_trait_object(impl_def_id) {
606+
// Non-specializable items are always projectable.
607+
true
615608
} else {
616-
debug!(?node_item.item.def_id, "not eligible due to default");
617-
false
618-
}
619-
};
609+
// Only reveal a specializable default if we're past type-checking
610+
// and the obligation is monomorphic, otherwise passes such as
611+
// transmute checking and polymorphic MIR optimizations could
612+
// get a result which isn't correct for all monomorphizations.
613+
if param_env.reveal() == Reveal::All {
614+
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
615+
!poly_trait_ref.still_further_specializable()
616+
} else {
617+
debug!(?node_item.item.def_id, "not eligible due to default");
618+
false
619+
}
620+
};
620621

621622
if eligible { Ok(Some(node_item)) } else { Ok(None) }
622623
}

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,7 +1745,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
17451745
specialization_graph::assoc_def(selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id)
17461746
.map_err(|ErrorGuaranteed { .. }| ())?;
17471747

1748-
if node_item.is_final() {
1748+
if node_item.is_final() && !selcx.tcx().impl_may_be_shadowed_by_trait_object(impl_data.impl_def_id) {
17491749
// Non-specializable items are always projectable.
17501750
true
17511751
} else {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use rustc_hir::def_id::DefId;
2+
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, RegionVariableOrigin, TyCtxtInferExt};
3+
use rustc_infer::traits::Obligation;
4+
use rustc_middle::traits::ObligationCause;
5+
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
6+
use rustc_span::DUMMY_SP;
7+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
8+
use rustc_trait_selection::traits::{elaborate, NormalizeExt, SelectionContext};
9+
10+
pub(crate) fn impl_may_be_shadowed_by_trait_object<'tcx>(
11+
tcx: TyCtxt<'tcx>,
12+
impl_def_id: DefId,
13+
) -> bool {
14+
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).expect("only called for trait impls");
15+
if !tcx.object_safety_violations(trait_def_id).is_empty() {
16+
return false;
17+
}
18+
19+
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).expect("only called for trait impls");
20+
if !matches!(
21+
impl_trait_ref.skip_binder().self_ty().kind(),
22+
ty::Param(..) | ty::Alias(..) | ty::Dynamic(..)
23+
) {
24+
return false;
25+
}
26+
27+
let infcx = tcx.infer_ctxt().intercrate(true).build();
28+
let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
29+
30+
let cause = &ObligationCause::dummy();
31+
let param_env = ty::ParamEnv::empty();
32+
33+
let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
34+
35+
let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args).predicates;
36+
let InferOk { value: (impl_trait_ref, impl_predicates), obligations: normalize_obligations } =
37+
infcx.at(cause, param_env).normalize((impl_trait_ref, impl_predicates));
38+
39+
let mut existential_predicates = vec![ty::Binder::dummy(ty::ExistentialPredicate::Trait(
40+
ty::ExistentialTraitRef::erase_self_ty(tcx, impl_trait_ref),
41+
))];
42+
43+
let principal_clause: ty::Clause<'tcx> = impl_trait_ref.to_predicate(tcx);
44+
existential_predicates.extend(
45+
elaborate(tcx, [principal_clause]).filter_map(|clause| clause.as_projection_clause()).map(
46+
|proj| {
47+
proj.map_bound(|proj| {
48+
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
49+
tcx, proj,
50+
))
51+
})
52+
},
53+
),
54+
);
55+
existential_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
56+
existential_predicates.dedup();
57+
let existential_predicates = tcx.mk_poly_existential_predicates(&existential_predicates);
58+
59+
let self_ty = Ty::new_dynamic(
60+
tcx,
61+
existential_predicates,
62+
infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)),
63+
ty::Dyn,
64+
);
65+
let InferOk { value: self_ty, obligations: normalize_obligations2 } =
66+
infcx.at(cause, param_env).normalize(self_ty);
67+
68+
let Ok(InferOk { value: (), obligations: eq_obligations }) =
69+
infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, self_ty, impl_trait_ref.self_ty())
70+
else {
71+
return false;
72+
};
73+
74+
let mut selcx = SelectionContext::new(&infcx);
75+
let impossible_obligation = impl_predicates
76+
.into_iter()
77+
.map(|clause| Obligation::new(tcx, cause.clone(), param_env, clause))
78+
.chain(normalize_obligations)
79+
.chain(normalize_obligations2)
80+
.chain(eq_obligations)
81+
.find(|obligation| {
82+
if infcx.next_trait_solver() {
83+
infcx.evaluate_obligation(&obligation).map_or(false, |result| !result.may_apply())
84+
} else {
85+
// We use `evaluate_root_obligation` to correctly track intercrate
86+
// ambiguity clauses. We cannot use this in the new solver.
87+
selcx.evaluate_root_obligation(&obligation).map_or(
88+
false, // Overflow has occurred, and treat the obligation as possibly holding.
89+
|result| !result.may_apply(),
90+
)
91+
}
92+
});
93+
94+
impossible_obligation.is_none()
95+
}

compiler/rustc_traits/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern crate rustc_middle;
1313
mod codegen;
1414
mod dropck_outlives;
1515
mod evaluate_obligation;
16+
mod impl_shadow;
1617
mod implied_outlives_bounds;
1718
mod normalize_erasing_regions;
1819
mod normalize_projection_ty;
@@ -31,4 +32,5 @@ pub fn provide(p: &mut Providers) {
3132
normalize_erasing_regions::provide(p);
3233
type_op::provide(p);
3334
p.codegen_select_candidate = codegen::codegen_select_candidate;
35+
p.impl_may_be_shadowed_by_trait_object = impl_shadow::impl_may_be_shadowed_by_trait_object;
3436
}

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ fn resolve_associated_item<'tcx>(
126126
// or a specialization because we can't resolve those unless we can `Reveal::All`.
127127
// NOTE: This should be kept in sync with the similar code in
128128
// `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`.
129-
let eligible = if leaf_def.is_final() {
129+
let eligible = if leaf_def.is_final()
130+
&& !infcx.tcx.impl_may_be_shadowed_by_trait_object(impl_data.impl_def_id)
131+
{
130132
// Non-specializable items are always projectable.
131133
true
132134
} else {

tests/mir-opt/dont_inline_type_id.call.Inline.diff

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,14 @@
55
debug s => _1;
66
let mut _0: std::any::TypeId;
77
let mut _2: &T;
8-
+ scope 1 (inlined <T as Any>::type_id) {
9-
+ debug self => _2;
10-
+ scope 2 (inlined TypeId::of::<T>) {
11-
+ let _3: u128;
12-
+ let mut _4: u128;
13-
+ scope 3 {
14-
+ debug t => _3;
15-
+ }
16-
+ }
17-
+ }
188

199
bb0: {
2010
StorageLive(_2);
2111
_2 = &(*_1);
22-
- _0 = <T as Any>::type_id(move _2) -> [return: bb1, unwind unreachable];
23-
+ StorageLive(_3);
24-
+ _3 = std::intrinsics::type_id::<T>() -> [return: bb1, unwind unreachable];
12+
_0 = <T as Any>::type_id(move _2) -> [return: bb1, unwind unreachable];
2513
}
2614

2715
bb1: {
28-
+ StorageLive(_4);
29-
+ _4 = _3;
30-
+ _0 = TypeId { t: move _4 };
31-
+ StorageDead(_4);
32-
+ StorageDead(_3);
3316
StorageDead(_2);
3417
return;
3518
}
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error[E0391]: cycle detected when computing layout of `core::option::Option<S>`
1+
error[E0277]: the size for values of type `<S as Mirror>::It` cannot be known at compilation time
2+
--> $DIR/issue-26548-recursion-via-normalize.rs:14:10
23
|
3-
= note: ...which requires computing layout of `S`...
4-
= note: ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
5-
= note: ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
6-
= note: cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
7-
= 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
4+
LL | struct S(Option<<S as Mirror>::It>);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `<S as Mirror>::It`
8+
note: required by a bound in `Option`
9+
--> $SRC_DIR/core/src/option.rs:LL:COL
810

911
error: aborting due to previous error
1012

11-
For more information about this error, try `rustc --explain E0391`.
13+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1-
error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
2-
--> $DIR/with-self-in-projection-output-bad.rs:45:21
1+
error[E0271]: type mismatch resolving `<u32 as Base>::Output == <u32 as ConstI32>::Out`
2+
--> $DIR/with-self-in-projection-output-bad.rs:39:6
33
|
4-
LL | type Output;
5-
| ----------- `Output` defined here
6-
...
7-
LL | let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32);
8-
| ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>`
9-
10-
error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified
11-
--> $DIR/with-self-in-projection-output-bad.rs:48:21
4+
LL | impl NormalizableHelper for u32
5+
| ^^^^^^^^^^^^^^^^^^ type mismatch resolving `<u32 as Base>::Output == <u32 as ConstI32>::Out`
6+
|
7+
note: expected this to be `<u32 as ConstI32>::Out`
8+
--> $DIR/with-self-in-projection-output-bad.rs:15:19
9+
|
10+
LL | type Output = i32;
11+
| ^^^
12+
= note: expected associated type `<u32 as ConstI32>::Out`
13+
found type `i32`
14+
= help: consider constraining the associated type `<u32 as ConstI32>::Out` to `i32`
15+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
16+
note: required by a bound in `NormalizableHelper`
17+
--> $DIR/with-self-in-projection-output-bad.rs:34:10
1218
|
13-
LL | type Output;
14-
| ----------- `Output` defined here
15-
...
16-
LL | let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32);
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>`
19+
LL | trait NormalizableHelper:
20+
| ------------------ required by a bound in this trait
21+
LL | Base<Output=<Self as ConstI32>::Out>
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `NormalizableHelper`
1823

19-
error: aborting due to 2 previous errors
24+
error: aborting due to previous error
2025

21-
For more information about this error, try `rustc --explain E0191`.
26+
For more information about this error, try `rustc --explain E0271`.

tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/illegal-upcast-from-impl.rs:13:18
3+
|
4+
LL | type Assoc = i32;
5+
| ^^^ cannot infer type for associated type `<T as Super>::Assoc`
6+
17
error[E0308]: mismatched types
28
--> $DIR/illegal-upcast-from-impl.rs:16:66
39
|
@@ -9,6 +15,7 @@ LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
915
= note: expected reference `&dyn Super<Assoc = i32>`
1016
found reference `&dyn Sub<Assoc = ()>`
1117

12-
error: aborting due to previous error
18+
error: aborting due to 2 previous errors
1319

14-
For more information about this error, try `rustc --explain E0308`.
20+
Some errors have detailed explanations: E0282, E0308.
21+
For more information about an error, try `rustc --explain E0282`.

0 commit comments

Comments
 (0)