Skip to content

Commit 2aed770

Browse files
compiler-errorslcnr
authored andcommitted
Incompletely prefer opaque type bounds when self type bottoms out in infer
1 parent fefce3c commit 2aed770

File tree

13 files changed

+273
-13
lines changed

13 files changed

+273
-13
lines changed

compiler/rustc_middle/src/ty/context.rs

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

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

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

Lines changed: 92 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,87 @@ 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+
is_hidden_type_of_alias = true;
964+
for item_bound in self
965+
.cx()
966+
.item_self_bounds(alias_ty.def_id)
967+
.iter_instantiated(self.cx(), alias_ty.args)
968+
{
969+
let assumption =
970+
item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
971+
candidates.extend(G::probe_and_match_goal_against_assumption(
972+
self,
973+
CandidateSource::AliasBound,
974+
goal,
975+
assumption,
976+
|ecx| {
977+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
978+
},
979+
));
980+
}
981+
982+
struct ReplaceOpaque<I: Interner> {
983+
cx: I,
984+
alias_ty: ty::AliasTy<I>,
985+
self_ty: I::Ty,
986+
}
987+
impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> {
988+
fn cx(&self) -> I {
989+
self.cx
990+
}
991+
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
992+
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
993+
if alias_ty == self.alias_ty {
994+
return self.self_ty;
995+
}
996+
}
997+
ty.super_fold_with(self)
998+
}
999+
}
1000+
}
1001+
1002+
if is_hidden_type_of_alias && candidates.is_empty() {
1003+
let cx = self.cx();
1004+
cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
1005+
// For every `default impl`, there's always a non-default `impl`
1006+
// that will *also* apply. There's no reason to register a candidate
1007+
// for this impl, since it is *not* proof that the trait goal holds.
1008+
if cx.impl_is_default(impl_def_id) {
1009+
return;
1010+
}
1011+
1012+
match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
1013+
if ecx.shallow_resolve(self_ty).is_ty_var() {
1014+
ecx.evaluate_added_goals_and_make_canonical_response(
1015+
certainty.and(Certainty::AMBIGUOUS),
1016+
)
1017+
} else {
1018+
Err(NoSolution)
1019+
}
1020+
}) {
1021+
Ok(candidate) => candidates.push(candidate),
1022+
Err(NoSolution) => (),
1023+
}
1024+
});
1025+
}
1026+
1027+
if candidates.is_empty() {
1028+
candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
1029+
}
1030+
}
1031+
9461032
/// Assemble and merge candidates for goals which are related to an underlying trait
9471033
/// goal. Right now, this is normalizes-to and host effect goals.
9481034
///

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
@@ -1047,6 +1047,10 @@ where
10471047
self.delegate.resolve_vars_if_possible(value)
10481048
}
10491049

1050+
pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty {
1051+
self.delegate.shallow_resolve(ty)
1052+
}
1053+
10501054
pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
10511055
if let ty::ReVar(vid) = r.kind() {
10521056
self.delegate.opportunistic_resolve_lt_var(vid)
@@ -1163,6 +1167,33 @@ where
11631167
) -> bool {
11641168
may_use_unstable_feature(&**self.delegate, param_env, symbol)
11651169
}
1170+
1171+
pub(crate) fn find_sup_as_registered_opaque(
1172+
&self,
1173+
self_ty: I::Ty,
1174+
) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> {
1175+
let delegate = self.delegate;
1176+
delegate
1177+
.clone_opaque_types_lookup_table()
1178+
.into_iter()
1179+
.chain(delegate.clone_duplicate_opaque_types())
1180+
.filter_map(move |(key, hidden_ty)| {
1181+
if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() {
1182+
if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() {
1183+
if delegate.sub_unification_table_root_var(self_vid)
1184+
== delegate.sub_unification_table_root_var(hidden_vid)
1185+
{
1186+
return Some(ty::AliasTy::new_from_args(
1187+
delegate.cx(),
1188+
key.def_id.into(),
1189+
key.args,
1190+
));
1191+
}
1192+
}
1193+
}
1194+
None
1195+
})
1196+
}
11661197
}
11671198

11681199
/// 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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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.
7+
8+
fn foo() -> impl Sized {
9+
let y = Default::default();
10+
if false {
11+
return From::from(y);
12+
}
13+
14+
let _: u16 = y;
15+
1u32
16+
}
17+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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.
7+
8+
fn foo() -> impl Sized {
9+
if false {
10+
return From::from(1u16);
11+
}
12+
13+
1u32
14+
}
15+
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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#196.
7+
fn iterator(b: bool) -> impl Iterator<Item = String> {
8+
if b {
9+
// We need to eagerly figure out the type of `i` here by using
10+
// the `<opaque as IntoIterator>::Item` obligation. This means
11+
// we not only have to consider item bounds, but also blanket impls.
12+
for i in iterator(false) {
13+
i.len();
14+
}
15+
}
16+
17+
vec![].into_iter()
18+
}
19+
fn main() {}

0 commit comments

Comments
 (0)