Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 54eae59

Browse files
Rollup merge of #140306 - lcnr:specialization-new, r=compiler-errors
handle specialization in the new trait solver fixes rust-lang/trait-system-refactor-initiative#187 also fixes the regression in `plonky2_field` from rust-lang/trait-system-refactor-initiative#188 cc #111994 r? ```@compiler-errors```
2 parents f2f4152 + 009db53 commit 54eae59

20 files changed

+290
-51
lines changed

‎compiler/rustc_middle/src/ty/context.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
590590
self.defaultness(def_id).has_value()
591591
}
592592

593+
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
594+
self.specializes((impl_def_id, victim_def_id))
595+
}
596+
593597
fn impl_is_default(self, impl_def_id: DefId) -> bool {
594598
self.defaultness(impl_def_id).is_default()
595599
}

‎compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs‎

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_type_ir::{
1010
};
1111
use tracing::{debug, instrument};
1212

13+
use super::has_only_region_constraints;
1314
use super::trait_goals::TraitGoalProvenVia;
1415
use crate::delegate::SolverDelegate;
1516
use crate::solve::inspect::ProbeKind;
@@ -771,6 +772,69 @@ where
771772
}
772773
})
773774
}
775+
}
776+
777+
pub(super) enum AllowInferenceConstraints {
778+
Yes,
779+
No,
780+
}
781+
782+
impl<D, I> EvalCtxt<'_, D>
783+
where
784+
D: SolverDelegate<Interner = I>,
785+
I: Interner,
786+
{
787+
/// Check whether we can ignore impl candidates due to specialization.
788+
///
789+
/// This is only necessary for `feature(specialization)` and seems quite ugly.
790+
pub(super) fn filter_specialized_impls(
791+
&mut self,
792+
allow_inference_constraints: AllowInferenceConstraints,
793+
candidates: &mut Vec<Candidate<I>>,
794+
) {
795+
match self.typing_mode() {
796+
TypingMode::Coherence => return,
797+
TypingMode::Analysis { .. }
798+
| TypingMode::Borrowck { .. }
799+
| TypingMode::PostBorrowckAnalysis { .. }
800+
| TypingMode::PostAnalysis => {}
801+
}
802+
803+
let mut i = 0;
804+
'outer: while i < candidates.len() {
805+
let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
806+
i += 1;
807+
continue;
808+
};
809+
810+
for (j, c) in candidates.iter().enumerate() {
811+
if i == j {
812+
continue;
813+
}
814+
815+
let CandidateSource::Impl(other_def_id) = c.source else {
816+
continue;
817+
};
818+
819+
// See if we can toss out `victim` based on specialization.
820+
//
821+
// While this requires us to know *for sure* that the `lhs` impl applies
822+
// we still use modulo regions here. This is fine as specialization currently
823+
// assumes that specializing impls have to be always applicable, meaning that
824+
// the only allowed region constraints may be constraints also present on the default impl.
825+
if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
826+
|| has_only_region_constraints(c.result)
827+
{
828+
if self.cx().impl_specializes(other_def_id, victim_def_id) {
829+
candidates.remove(i);
830+
continue 'outer;
831+
}
832+
}
833+
}
834+
835+
i += 1;
836+
}
837+
}
774838

775839
/// Assemble and merge candidates for goals which are related to an underlying trait
776840
/// goal. Right now, this is normalizes-to and host effect goals.
@@ -857,7 +921,7 @@ where
857921
}
858922
}
859923
TraitGoalProvenVia::Misc => {
860-
let candidates =
924+
let mutcandidates =
861925
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
862926

863927
// Prefer "orphaned" param-env normalization predicates, which are used
@@ -871,6 +935,13 @@ where
871935
return Ok(response);
872936
}
873937

938+
// We drop specialized impls to allow normalization via a final impl here. In case
939+
// the specializing impl has different inference constraints from the specialized
940+
// impl, proving the trait goal is already ambiguous, so we never get here. This
941+
// means we can just ignore inference constraints and don't have to special-case
942+
// constraining the normalized-to `term`.
943+
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
944+
874945
let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
875946
if let Some(response) = self.try_merge_responses(&responses) {
876947
Ok(response)

‎compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_type_ir::{
1616
};
1717
use tracing::{instrument, trace};
1818

19+
use super::has_only_region_constraints;
1920
use crate::coherence;
2021
use crate::delegate::SolverDelegate;
2122
use crate::solve::inspect::{self, ProofTreeBuilder};
@@ -476,13 +477,8 @@ where
476477
Ok(response) => response,
477478
};
478479

479-
let has_changed = if !response.value.var_values.is_identity_modulo_regions()
480-
|| !response.value.external_constraints.opaque_types.is_empty()
481-
{
482-
HasChanged::Yes
483-
} else {
484-
HasChanged::No
485-
};
480+
let has_changed =
481+
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
486482

487483
let (normalization_nested_goals, certainty) =
488484
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ fn has_no_inference_or_external_constraints<I: Interner>(
7070
&& normalization_nested_goals.is_empty()
7171
}
7272

73+
fn has_only_region_constraints<I: Interner>(response: ty::Canonical<I, Response<I>>) -> bool {
74+
let ExternalConstraintsData {
75+
region_constraints: _,
76+
ref opaque_types,
77+
ref normalization_nested_goals,
78+
} = *response.value.external_constraints;
79+
response.value.var_values.is_identity_modulo_regions()
80+
&& opaque_types.is_empty()
81+
&& normalization_nested_goals.is_empty()
82+
}
83+
7384
impl<'a, D, I> EvalCtxt<'a, D>
7485
where
7586
D: SolverDelegate<Interner = I>,

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,18 +213,35 @@ where
213213
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
214214
};
215215

216-
// In case the associated item is hidden due to specialization, we have to
217-
// return ambiguity this would otherwise be incomplete, resulting in
218-
// unsoundness during coherence (#105782).
219216
let target_item_def_id = match ecx.fetch_eligible_assoc_item(
220217
goal_trait_ref,
221218
goal.predicate.def_id(),
222219
impl_def_id,
223220
) {
224221
Ok(Some(target_item_def_id)) => target_item_def_id,
225222
Ok(None) => {
226-
return ecx
227-
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
223+
match ecx.typing_mode() {
224+
// In case the associated item is hidden due to specialization, we have to
225+
// return ambiguity this would otherwise be incomplete, resulting in
226+
// unsoundness during coherence (#105782).
227+
ty::TypingMode::Coherence => {
228+
return ecx.evaluate_added_goals_and_make_canonical_response(
229+
Certainty::AMBIGUOUS,
230+
);
231+
}
232+
// Outside of coherence, we treat the associated item as rigid instead.
233+
ty::TypingMode::Analysis { .. }
234+
| ty::TypingMode::Borrowck { .. }
235+
| ty::TypingMode::PostBorrowckAnalysis { .. }
236+
| ty::TypingMode::PostAnalysis => {
237+
ecx.structurally_instantiate_normalizes_to_term(
238+
goal,
239+
goal.predicate.alias,
240+
);
241+
return ecx
242+
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
243+
}
244+
};
228245
}
229246
Err(guar) => return error_response(ecx, guar),
230247
};

‎compiler/rustc_next_trait_solver/src/solve/trait_goals.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tracing::{instrument, trace};
1313

1414
use crate::delegate::SolverDelegate;
1515
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16-
use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
16+
use crate::solve::assembly::{self, AllowInferenceConstraints,AssembleCandidatesFrom, Candidate};
1717
use crate::solve::inspect::ProbeKind;
1818
use crate::solve::{
1919
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
@@ -1338,6 +1338,8 @@ where
13381338
};
13391339
}
13401340

1341+
self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1342+
13411343
// If there are *only* global where bounds, then make sure to return that this
13421344
// is still reported as being proven-via the param-env so that rigid projections
13431345
// operate correctly. Otherwise, drop all global where-bounds before merging the

‎compiler/rustc_type_ir/src/interner.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ pub trait Interner:
286286

287287
fn has_item_definition(self, def_id: Self::DefId) -> bool;
288288

289+
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool;
290+
289291
fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
290292

291293
fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/prefer-specializing-impl-over-default.rs:5:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/prefer-specializing-impl-over-default.rs:5:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
warning: 1 warning emitted
12+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
#![feature(specialization)]
6+
//~^ WARN the feature `specialization` is incomplete
7+
8+
trait WithAssoc: 'static {
9+
type Assoc;
10+
}
11+
impl<T: 'static> WithAssoc for (T,) {
12+
type Assoc = ();
13+
}
14+
15+
struct GenericArray<U: WithAssoc>(U::Assoc);
16+
17+
trait AbiExample {
18+
fn example();
19+
}
20+
impl<U: WithAssoc> AbiExample for GenericArray<U> {
21+
fn example() {}
22+
}
23+
impl<T> AbiExample for T {
24+
default fn example() {}
25+
}
26+
27+
fn main() {
28+
let _ = GenericArray::<((),)>::example();
29+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /