Skip to content

Commit a30ad3a

Browse files
Don't resolve generic instances if they may be shadowed by dyn
1 parent 55ce976 commit a30ad3a

8 files changed

+144
-20
lines changed

compiler/rustc_middle/src/ty/sty.rs

+27
Original file line numberDiff line numberDiff line change
@@ -2945,6 +2945,33 @@ impl<'tcx> Ty<'tcx> {
29452945
_ => false,
29462946
}
29472947
}
2948+
2949+
pub fn is_known_rigid(self) -> bool {
2950+
match self.kind() {
2951+
Bool
2952+
| Char
2953+
| Int(_)
2954+
| Uint(_)
2955+
| Float(_)
2956+
| Adt(_, _)
2957+
| Foreign(_)
2958+
| Str
2959+
| Array(_, _)
2960+
| Slice(_)
2961+
| RawPtr(_)
2962+
| Ref(_, _, _)
2963+
| FnDef(_, _)
2964+
| FnPtr(_)
2965+
| Dynamic(_, _, _)
2966+
| Closure(_, _)
2967+
| Generator(_, _, _)
2968+
| GeneratorWitness(_)
2969+
| GeneratorWitnessMIR(_, _)
2970+
| Never
2971+
| Tuple(_) => true,
2972+
Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false,
2973+
}
2974+
}
29482975
}
29492976

29502977
/// Extra information about why we ended up with a particular variance.

compiler/rustc_ty_utils/src/instance.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,34 @@ fn resolve_associated_item<'tcx>(
141141
false
142142
}
143143
};
144-
145144
if !eligible {
146145
return Ok(None);
147146
}
148147

148+
// HACK: We may have overlapping `dyn Trait` built-in impls and
149+
// user-provided blanket impls. Detect that case here, and return
150+
// ambiguity.
151+
//
152+
// This should not affect totally monomorphized contexts, only
153+
// resolve calls that happen polymorphically, such as the mir-inliner
154+
// and const-prop (and also some lints).
155+
let self_ty = rcvr_args.type_at(0);
156+
if !self_ty.is_known_rigid() {
157+
let predicates = tcx
158+
.predicates_of(impl_data.impl_def_id)
159+
.instantiate(tcx, impl_data.args)
160+
.predicates;
161+
let sized_def_id = tcx.lang_items().sized_trait();
162+
// If we find a `Self: Sized` bound on the item, then we know
163+
// that `dyn Trait` can certainly never apply here.
164+
if !predicates.into_iter().filter_map(ty::Clause::as_trait_clause).any(|clause| {
165+
Some(clause.def_id()) == sized_def_id
166+
&& clause.skip_binder().self_ty() == self_ty
167+
}) {
168+
return Ok(None);
169+
}
170+
}
171+
149172
// Any final impl is required to define all associated items.
150173
if !leaf_def.item.defaultness(tcx).has_value() {
151174
let guard = tcx.sess.delay_span_bug(

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

+1-18
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
}

tests/mir-opt/dont_inline_type_id.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ struct A<T: ?Sized + 'static> {
1010
}
1111

1212
// EMIT_MIR dont_inline_type_id.call.Inline.diff
13-
fn call<T: ?Sized + 'static>(s: &T) -> TypeId {
13+
pub fn call<T: ?Sized + 'static>(s: &T) -> TypeId {
1414
s.type_id()
1515
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
- // MIR for `call` before Inline
2+
+ // MIR for `call` after Inline
3+
4+
fn call(_1: &T) -> i32 {
5+
debug s => _1;
6+
let mut _0: i32;
7+
let mut _2: &T;
8+
+ scope 1 (inlined <T as Foo>::bar) {
9+
+ debug self => _2;
10+
+ }
11+
12+
bb0: {
13+
StorageLive(_2);
14+
_2 = &(*_1);
15+
- _0 = <T as Foo>::bar(move _2) -> [return: bb1, unwind unreachable];
16+
- }
17+
-
18+
- bb1: {
19+
+ _0 = const 0_i32;
20+
StorageDead(_2);
21+
return;
22+
}
23+
}
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// unit-test: Inline
2+
// compile-flags: --crate-type=lib -C panic=abort
3+
4+
trait Foo {
5+
fn bar(&self) -> i32;
6+
}
7+
8+
impl<T> Foo for T {
9+
fn bar(&self) -> i32 {
10+
0
11+
}
12+
}
13+
14+
// EMIT_MIR inline_generically_if_sized.call.Inline.diff
15+
pub fn call<T>(s: &T) -> i32 {
16+
s.bar()
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// run-pass
2+
3+
#![feature(inline_const)]
4+
5+
// Makes sure we don't propagate generic instances of `Self: ?Sized` blanket impls.
6+
// This is relevant when we have an overlapping impl and builtin dyn instance.
7+
// See <https://github.com/rust-lang/rust/pull/114941> for more context.
8+
9+
trait Trait {
10+
fn foo(&self) -> &'static str;
11+
}
12+
13+
impl<T: ?Sized> Trait for T {
14+
fn foo(&self) -> &'static str {
15+
std::any::type_name::<T>()
16+
}
17+
}
18+
19+
fn bar<T: ?Sized>() -> fn(&T) -> &'static str {
20+
const { Trait::foo as fn(&T) -> &'static str }
21+
// If const prop were to propagate the instance
22+
}
23+
24+
fn main() {
25+
assert_eq!("i32", bar::<dyn Trait>()(&1i32));
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-pass
2+
3+
// Makes sure we don't propagate generic instances of `Self: ?Sized` blanket impls.
4+
// This is relevant when we have an overlapping impl and builtin dyn instance.
5+
// See <https://github.com/rust-lang/rust/pull/114941> for more context.
6+
7+
trait Trait {
8+
fn foo(&self) -> &'static str;
9+
}
10+
11+
impl<T: ?Sized> Trait for T {
12+
fn foo(&self) -> &'static str {
13+
std::any::type_name::<T>()
14+
}
15+
}
16+
17+
const fn bar<T: ?Sized>() -> fn(&T) -> &'static str {
18+
Trait::foo
19+
// If const prop were to propagate the instance
20+
}
21+
22+
fn main() {
23+
assert_eq!("i32", bar::<dyn Trait>()(&1i32));
24+
}

0 commit comments

Comments
 (0)