Skip to content

Commit 5c29fd3

Browse files
compiler-errorslcnr
authored andcommitted
Incompletely prefer opaque type bounds when self type bottoms out in infer
1 parent d6692fb commit 5c29fd3

File tree

14 files changed

+313
-13
lines changed

14 files changed

+313
-13
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
651651
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
652652
}
653653

654-
let trait_impls = tcx.trait_impls_of(trait_def_id);
654+
#[allow(rustc::usage_of_type_ir_traits)]
655+
self.for_each_blanket_impl(trait_def_id, f)
656+
}
657+
fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) {
658+
let trait_impls = self.trait_impls_of(trait_def_id);
655659
for &impl_def_id in trait_impls.blanket_impls() {
656660
f(impl_def_id);
657661
}

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

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem;
1111
use rustc_type_ir::search_graph::CandidateHeadUsages;
1212
use rustc_type_ir::solve::SizedTraitKind;
1313
use rustc_type_ir::{
14-
self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
15-
TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate,
14+
self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
15+
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
16+
elaborate,
1617
};
1718
use tracing::{debug, instrument};
1819

@@ -187,6 +188,7 @@ where
187188
ecx: &mut EvalCtxt<'_, D>,
188189
goal: Goal<I, Self>,
189190
impl_def_id: I::ImplId,
191+
finalize: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
190192
) -> Result<Candidate<I>, NoSolution>;
191193

192194
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
@@ -397,14 +399,15 @@ where
397399
return (candidates, failed_candidate_info);
398400
};
399401

402+
let goal: Goal<I, G> = goal
403+
.with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
404+
400405
if normalized_self_ty.is_ty_var() {
401406
debug!("self type has been normalized to infer");
402-
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
407+
self.try_assemble_bounds_via_registered_opaque(goal, &mut candidates);
403408
return (candidates, failed_candidate_info);
404409
}
405410

406-
let goal: Goal<I, G> = goal
407-
.with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
408411
// Vars that show up in the rest of the goal substs may have been constrained by
409412
// normalizing the self type as well, since type variables are not uniquified.
410413
let goal = self.resolve_vars_if_possible(goal);
@@ -485,7 +488,9 @@ where
485488
return;
486489
}
487490

488-
match G::consider_impl_candidate(self, goal, impl_def_id) {
491+
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
492+
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
493+
}) {
489494
Ok(candidate) => candidates.push(candidate),
490495
Err(NoSolution) => (),
491496
}
@@ -943,6 +948,88 @@ where
943948
}
944949
}
945950

951+
/// If the self type is the hidden type of an opaque, try to assemble
952+
/// candidates for it by consider its item bounds. This is used to
953+
/// incompletely guide type inference when handling non-defining uses
954+
/// in the defining scope.
955+
fn try_assemble_bounds_via_registered_opaque<G: GoalKind<D>>(
956+
&mut self,
957+
goal: Goal<I, G>,
958+
candidates: &mut Vec<Candidate<I>>,
959+
) {
960+
let self_ty = goal.predicate.self_ty();
961+
let mut is_hidden_type_of_alias = false;
962+
for alias_ty in self.find_sup_as_registered_opaque(self_ty) {
963+
debug!("self ty is sub unified with {alias_ty:?}");
964+
is_hidden_type_of_alias = true;
965+
for item_bound in self
966+
.cx()
967+
.item_self_bounds(alias_ty.def_id)
968+
.iter_instantiated(self.cx(), alias_ty.args)
969+
{
970+
let assumption =
971+
item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
972+
candidates.extend(G::probe_and_match_goal_against_assumption(
973+
self,
974+
CandidateSource::AliasBound,
975+
goal,
976+
assumption,
977+
|ecx| {
978+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
979+
},
980+
));
981+
}
982+
983+
struct ReplaceOpaque<I: Interner> {
984+
cx: I,
985+
alias_ty: ty::AliasTy<I>,
986+
self_ty: I::Ty,
987+
}
988+
impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> {
989+
fn cx(&self) -> I {
990+
self.cx
991+
}
992+
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
993+
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
994+
if alias_ty == self.alias_ty {
995+
return self.self_ty;
996+
}
997+
}
998+
ty.super_fold_with(self)
999+
}
1000+
}
1001+
}
1002+
1003+
if is_hidden_type_of_alias && candidates.is_empty() {
1004+
let cx = self.cx();
1005+
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
1006+
// For every `default impl`, there's always a non-default `impl`
1007+
// that will *also* apply. There's no reason to register a candidate
1008+
// for this impl, since it is *not* proof that the trait goal holds.
1009+
if cx.impl_is_default(impl_def_id) {
1010+
return;
1011+
}
1012+
1013+
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
1014+
if ecx.shallow_resolve(self_ty).is_ty_var() {
1015+
ecx.evaluate_added_goals_and_make_canonical_response(
1016+
certainty.and(Certainty::AMBIGUOUS),
1017+
)
1018+
} else {
1019+
Err(NoSolution)
1020+
}
1021+
}) {
1022+
Ok(candidate) => candidates.push(candidate),
1023+
Err(NoSolution) => (),
1024+
}
1025+
});
1026+
}
1027+
1028+
if candidates.is_empty() {
1029+
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
1030+
}
1031+
}
1032+
9461033
/// Assemble and merge candidates for goals which are related to an underlying trait
9471034
/// goal. Right now, this is normalizes-to and host effect goals.
9481035
///

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ where
124124
ecx: &mut EvalCtxt<'_, D>,
125125
goal: Goal<I, Self>,
126126
impl_def_id: I::ImplId,
127+
finalize: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
127128
) -> Result<Candidate<I>, NoSolution> {
128129
let cx = ecx.cx();
129130

@@ -175,7 +176,7 @@ where
175176
});
176177
ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
177178

178-
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
179+
finalize(ecx, certainty)
179180
})
180181
}
181182

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,10 @@ where
10601060
self.delegate.resolve_vars_if_possible(value)
10611061
}
10621062

1063+
pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty {
1064+
self.delegate.shallow_resolve(ty)
1065+
}
1066+
10631067
pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
10641068
if let ty::ReVar(vid) = r.kind() {
10651069
self.delegate.opportunistic_resolve_lt_var(vid)
@@ -1176,6 +1180,33 @@ where
11761180
) -> bool {
11771181
may_use_unstable_feature(&**self.delegate, param_env, symbol)
11781182
}
1183+
1184+
pub(crate) fn find_sup_as_registered_opaque(
1185+
&self,
1186+
self_ty: I::Ty,
1187+
) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> {
1188+
let delegate = self.delegate;
1189+
delegate
1190+
.clone_opaque_types_lookup_table()
1191+
.into_iter()
1192+
.chain(delegate.clone_duplicate_opaque_types())
1193+
.filter_map(move |(key, hidden_ty)| {
1194+
if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() {
1195+
if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() {
1196+
if delegate.sub_unification_table_root_var(self_vid)
1197+
== delegate.sub_unification_table_root_var(hidden_vid)
1198+
{
1199+
return Some(ty::AliasTy::new_from_args(
1200+
delegate.cx(),
1201+
key.def_id.into(),
1202+
key.args,
1203+
));
1204+
}
1205+
}
1206+
}
1207+
None
1208+
})
1209+
}
11791210
}
11801211

11811212
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ where
194194
ecx: &mut EvalCtxt<'_, D>,
195195
goal: Goal<I, NormalizesTo<I>>,
196196
impl_def_id: I::ImplId,
197+
finalize: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
197198
) -> Result<Candidate<I>, NoSolution> {
198199
let cx = ecx.cx();
199200

@@ -314,8 +315,7 @@ where
314315
// nested goal for consistency.
315316
ty::TypingMode::Coherence => {
316317
ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous));
317-
return ecx
318-
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
318+
return finalize(ecx, Certainty::Yes);
319319
}
320320
ty::TypingMode::Analysis { .. }
321321
| ty::TypingMode::Borrowck { .. }
@@ -325,8 +325,7 @@ where
325325
goal,
326326
goal.predicate.alias,
327327
);
328-
return ecx
329-
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
328+
return finalize(ecx, Certainty::Yes);
330329
}
331330
}
332331
} else {

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ where
5555
ecx: &mut EvalCtxt<'_, D>,
5656
goal: Goal<I, TraitPredicate<I>>,
5757
impl_def_id: I::ImplId,
58+
finalize: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
5859
) -> Result<Candidate<I>, NoSolution> {
5960
let cx = ecx.cx();
6061

@@ -112,7 +113,7 @@ where
112113
.map(|pred| goal.with(cx, pred)),
113114
);
114115

115-
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
116+
finalize(ecx, maximal_certainty)
116117
})
117118
}
118119

compiler/rustc_type_ir/src/interner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ pub trait Interner:
347347
self_ty: Self::Ty,
348348
f: impl FnMut(Self::ImplId),
349349
);
350+
fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId));
350351

351352
fn has_item_definition(self, def_id: Self::DefId) -> bool;
352353

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/avoid-inference-constraints-from-blanket-2.rs:23:18
3+
|
4+
LL | let _: u32 = x;
5+
| --- ^ expected `u32`, found `u64`
6+
| |
7+
| expected due to this
8+
|
9+
help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
10+
|
11+
LL | let _: u32 = x.try_into().unwrap();
12+
| ++++++++++++++++++++
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[current] check-pass
5+
6+
// Regression test for trait-system-refactor-initiative#205. Avoid
7+
// constraining other impl arguments when applying blanket impls.
8+
9+
// FIXME(-Znext-solver): This currently incompletely constrains the
10+
// argument of `opaque: Trait<?x>` using the blanket impl of trait.
11+
// Ideally we don't do that.
12+
13+
trait Trait<T> {}
14+
15+
impl<T> Trait<u64> for T {}
16+
impl Trait<u32> for u64 {}
17+
18+
fn impls_trait<T: Trait<U>, U>(_: U) -> T {
19+
todo!()
20+
}
21+
22+
fn foo() -> impl Sized {
23+
let x = Default::default();
24+
if false {
25+
return impls_trait::<_, _>(x);
26+
}
27+
let _: u32 = x;
28+
//[next]~^ ERROR mismatched types
29+
1u64
30+
}
31+
fn main() {}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@ check-pass
5+
6+
// Regression test for trait-system-refactor-initiative#205. Avoid constraining
7+
// the opaque type when applying blanket impls.
8+
9+
trait Trait<T> {}
10+
11+
impl<T> Trait<T> for T {}
12+
impl Trait<u32> for u64 {}
13+
14+
fn impls_trait<T: Trait<U>, U>() -> T {
15+
todo!()
16+
}
17+
18+
fn foo() -> impl Sized {
19+
if false {
20+
return impls_trait::<_, u32>();
21+
}
22+
1u64
23+
}
24+
fn main() {}

0 commit comments

Comments
 (0)