Skip to content

Commit fafe9e7

Browse files
committed
Normalize consistently for specializations
1 parent bd928a0 commit fafe9e7

File tree

4 files changed

+104
-17
lines changed

4 files changed

+104
-17
lines changed

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

+22-17
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ pub fn translate_substs<'tcx>(
9999
return source_substs;
100100
}
101101

102-
fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
103-
|()| {
102+
fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl)
103+
.unwrap_or_else(|()| {
104104
bug!(
105105
"When translating substitutions from {source_impl:?} to {target_impl:?}, \
106106
the expected specialization failed to hold"
107107
)
108-
},
109-
)
108+
})
110109
}
111110
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
112111
};
@@ -153,20 +152,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
153152

154153
// Create an infcx, taking the predicates of impl1 as assumptions:
155154
let infcx = tcx.infer_ctxt().build();
156-
let impl1_trait_ref =
157-
match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
158-
Ok(impl1_trait_ref) => impl1_trait_ref,
159-
Err(_errors) => {
160-
tcx.sess.delay_span_bug(
161-
tcx.def_span(impl1_def_id),
162-
format!("failed to fully normalize {impl1_trait_ref}"),
163-
);
164-
impl1_trait_ref
165-
}
166-
};
167155

168156
// Attempt to prove that impl2 applies, given all of the above.
169-
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
157+
fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id).is_ok()
170158
}
171159

172160
/// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -178,13 +166,30 @@ fn fulfill_implication<'tcx>(
178166
infcx: &InferCtxt<'tcx>,
179167
param_env: ty::ParamEnv<'tcx>,
180168
source_trait_ref: ty::TraitRef<'tcx>,
169+
source_impl: DefId,
181170
target_impl: DefId,
182171
) -> Result<SubstsRef<'tcx>, ()> {
183172
debug!(
184173
"fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
185174
param_env, source_trait_ref, target_impl
186175
);
187176

177+
let source_trait_ref = match traits::fully_normalize(
178+
&infcx,
179+
ObligationCause::dummy(),
180+
param_env,
181+
source_trait_ref,
182+
) {
183+
Ok(source_trait_ref) => source_trait_ref,
184+
Err(_errors) => {
185+
infcx.tcx.sess.delay_span_bug(
186+
infcx.tcx.def_span(source_impl),
187+
format!("failed to fully normalize {source_trait_ref}"),
188+
);
189+
source_trait_ref
190+
}
191+
};
192+
188193
let source_trait = ImplSubject::Trait(source_trait_ref);
189194

190195
let selcx = &mut SelectionContext::new(&infcx);
@@ -194,7 +199,7 @@ fn fulfill_implication<'tcx>(
194199

195200
// do the impls unify? If not, no specialization.
196201
let Ok(InferOk { obligations: more_obligations, .. }) =
197-
infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
202+
infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait)
198203
else {
199204
debug!(
200205
"fulfill_implication: {:?} does not unify with {:?}",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Another regression test for #109815.
2+
3+
// check-pass
4+
5+
#![feature(min_specialization)]
6+
#![feature(rustc_attrs)]
7+
8+
#[rustc_specialization_trait]
9+
trait X {}
10+
trait Z {
11+
type Assoc: X;
12+
}
13+
struct A<T>(T);
14+
15+
impl X for () {}
16+
17+
impl<T: X> Z for A<T> {
18+
type Assoc = ();
19+
}
20+
21+
trait MyFrom<T> {
22+
fn from(other: T) -> Self;
23+
}
24+
25+
impl<T> MyFrom<()> for T {
26+
default fn from(other: ()) -> T {
27+
panic!();
28+
}
29+
}
30+
31+
impl<T: X> MyFrom<<A<T> as Z>::Assoc> for T {
32+
fn from(other: ()) -> T {
33+
panic!();
34+
}
35+
}
36+
37+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// A regression test for #109815.
2+
3+
#![feature(min_specialization)]
4+
#![feature(rustc_attrs)]
5+
6+
#[rustc_specialization_trait]
7+
trait X {}
8+
trait Y: X {}
9+
trait Z {
10+
type Assoc: Y;
11+
}
12+
struct A<T>(T);
13+
14+
impl<T: X> Z for A<T> {}
15+
//~^ ERROR not all trait items implemented
16+
17+
trait MyFrom<T> {
18+
fn from(other: T) -> Self;
19+
}
20+
21+
impl<T> MyFrom<T> for T {
22+
default fn from(other: T) -> T {
23+
other
24+
}
25+
}
26+
27+
impl<T: X> MyFrom<<A<T> as Z>::Assoc> for T {
28+
fn from(other: <A<T> as Z>::Assoc) -> T {
29+
other
30+
}
31+
}
32+
33+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0046]: not all trait items implemented, missing: `Assoc`
2+
--> $DIR/specialize_on_type_error.rs:14:1
3+
|
4+
LL | type Assoc: Y;
5+
| ------------- `Assoc` from trait
6+
...
7+
LL | impl<T: X> Z for A<T> {}
8+
| ^^^^^^^^^^^^^^^^^^^^^ missing `Assoc` in implementation
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)