Skip to content

Commit d7912ad

Browse files
Properly support opaques
By letting the solver take control of them (reveal them when needed and define them when needed), by providing them in the `TypingMode` plus few helpers.
1 parent b4de9df commit d7912ad

File tree

27 files changed

+739
-501
lines changed

27 files changed

+739
-501
lines changed

crates/hir-ty/src/autoderef.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn autoderef<'db>(
3838
env: Arc<TraitEnvironment<'db>>,
3939
ty: Canonical<'db, Ty<'db>>,
4040
) -> impl Iterator<Item = Ty<'db>> + use<'db> {
41-
let mut table = InferenceTable::new(db, env);
41+
let mut table = InferenceTable::new(db, env, None);
4242
let ty = table.instantiate_canonical(ty);
4343
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty);
4444
let mut v = Vec::new();

crates/hir-ty/src/infer.rs

Lines changed: 33 additions & 261 deletions
Large diffs are not rendered by default.

crates/hir-ty/src/infer/coerce.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ use crate::{
6060
next_solver::{
6161
Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper,
6262
Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed,
63-
GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty,
64-
TyKind,
63+
GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
6564
infer::{
6665
InferCtxt, InferOk, InferResult,
6766
relate::RelateResult,
@@ -223,24 +222,6 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
223222
}
224223
}
225224

226-
// If we are coercing into a TAIT, coerce into its proxy inference var, instead.
227-
// FIXME(next-solver): This should not be here. This is not how rustc does thing, and it also not allows us
228-
// to normalize opaques defined in our scopes. Instead, we should properly register
229-
// `TypingMode::Analysis::defining_opaque_types_and_generators`, and rely on the solver to reveal
230-
// them for us (we'll also need some global-like registry for the values, something we cannot
231-
// really implement, therefore we can really support only RPITs and ITIAT or the new `#[define_opaque]`
232-
// TAIT, not the old global TAIT).
233-
let mut b = b;
234-
if let Some(tait_table) = &self.table.tait_coercion_table
235-
&& let TyKind::Alias(rustc_type_ir::Opaque, opaque_ty) = b.kind()
236-
&& let SolverDefId::InternedOpaqueTyId(opaque_ty_id) = opaque_ty.def_id
237-
&& !matches!(a.kind(), TyKind::Infer(..) | TyKind::Alias(rustc_type_ir::Opaque, _))
238-
&& let Some(ty) = tait_table.get(&opaque_ty_id)
239-
{
240-
b = self.table.shallow_resolve(*ty);
241-
}
242-
let b = b;
243-
244225
// Coercing *from* an unresolved inference variable means that
245226
// we have no information about the source type. This will always
246227
// ultimately fall back to some form of subtyping.
@@ -1528,7 +1509,7 @@ fn coerce<'db>(
15281509
env: Arc<TraitEnvironment<'db>>,
15291510
tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
15301511
) -> Result<(Vec<Adjustment<'db>>, Ty<'db>), TypeError<DbInterner<'db>>> {
1531-
let mut table = InferenceTable::new(db, env);
1512+
let mut table = InferenceTable::new(db, env, None);
15321513
let interner = table.interner();
15331514
let ((ty1_with_vars, ty2_with_vars), vars) = table.infer_ctxt.instantiate_canonical(tys);
15341515

crates/hir-ty/src/infer/expr.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,11 @@ impl<'db> InferenceContext<'_, 'db> {
14581458
) -> Ty<'db> {
14591459
let coerce_ty = expected.coercion_target_type(&mut self.table);
14601460
let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
1461-
let prev_env = block_id.map(|block_id| {
1461+
let prev_state = block_id.map(|block_id| {
14621462
let prev_env = self.table.trait_env.clone();
14631463
TraitEnvironment::with_block(&mut self.table.trait_env, block_id);
1464-
prev_env
1464+
let prev_block = self.table.infer_ctxt.interner.block.replace(block_id);
1465+
(prev_env, prev_block)
14651466
});
14661467

14671468
let (break_ty, ty) =
@@ -1576,8 +1577,9 @@ impl<'db> InferenceContext<'_, 'db> {
15761577
}
15771578
});
15781579
self.resolver.reset_to_guard(g);
1579-
if let Some(prev_env) = prev_env {
1580+
if let Some((prev_env, prev_block)) = prev_state {
15801581
self.table.trait_env = prev_env;
1582+
self.table.infer_ctxt.interner.block = prev_block;
15811583
}
15821584

15831585
break_ty.unwrap_or(ty)
@@ -1689,10 +1691,11 @@ impl<'db> InferenceContext<'_, 'db> {
16891691
// work out while people are typing
16901692
let canonicalized_receiver = self.canonicalize(receiver_ty);
16911693
let resolved = method_resolution::lookup_method(
1692-
self.db,
16931694
&canonicalized_receiver,
1694-
self.table.trait_env.clone(),
1695-
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
1695+
&mut self.table,
1696+
Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
1697+
.as_ref()
1698+
.left_or_else(|&it| it),
16961699
VisibleFromModule::Filter(self.resolver.module()),
16971700
name,
16981701
);
@@ -1844,10 +1847,11 @@ impl<'db> InferenceContext<'_, 'db> {
18441847
let canonicalized_receiver = self.canonicalize(receiver_ty);
18451848

18461849
let resolved = method_resolution::lookup_method(
1847-
self.db,
18481850
&canonicalized_receiver,
1849-
self.table.trait_env.clone(),
1850-
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
1851+
&mut self.table,
1852+
Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
1853+
.as_ref()
1854+
.left_or_else(|&it| it),
18511855
VisibleFromModule::Filter(self.resolver.module()),
18521856
method_name,
18531857
);
@@ -1892,9 +1896,10 @@ impl<'db> InferenceContext<'_, 'db> {
18921896

18931897
let assoc_func_with_same_name = method_resolution::iterate_method_candidates(
18941898
&canonicalized_receiver,
1895-
self.db,
1896-
self.table.trait_env.clone(),
1897-
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
1899+
&mut self.table,
1900+
Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
1901+
.as_ref()
1902+
.left_or_else(|&it| it),
18981903
VisibleFromModule::Filter(self.resolver.module()),
18991904
Some(method_name),
19001905
method_resolution::LookupMode::Path,

crates/hir-ty/src/infer/opaques.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//! Defining opaque types via inference.
2+
3+
use rustc_type_ir::TypeVisitableExt;
4+
use tracing::{debug, instrument};
5+
6+
use crate::{
7+
infer::InferenceContext,
8+
next_solver::{
9+
EarlyBinder, OpaqueTypeKey, SolverDefId, TypingMode,
10+
infer::{opaque_types::OpaqueHiddenType, traits::ObligationCause},
11+
},
12+
};
13+
14+
impl<'db> InferenceContext<'_, 'db> {
15+
/// This takes all the opaque type uses during HIR typeck. It first computes
16+
/// the concrete hidden type by iterating over all defining uses.
17+
///
18+
/// A use during HIR typeck is defining if all non-lifetime arguments are
19+
/// unique generic parameters and the hidden type does not reference any
20+
/// inference variables.
21+
///
22+
/// It then uses these defining uses to guide inference for all other uses.
23+
#[instrument(level = "debug", skip(self))]
24+
pub(super) fn handle_opaque_type_uses(&mut self) {
25+
// We clone the opaques instead of stealing them here as they are still used for
26+
// normalization in the next generation trait solver.
27+
let opaque_types: Vec<_> = self.table.infer_ctxt.clone_opaque_types();
28+
29+
self.compute_definition_site_hidden_types(opaque_types);
30+
}
31+
}
32+
33+
#[expect(unused, reason = "rustc has this")]
34+
#[derive(Copy, Clone, Debug)]
35+
enum UsageKind<'db> {
36+
None,
37+
NonDefiningUse(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>),
38+
UnconstrainedHiddenType(OpaqueHiddenType<'db>),
39+
HasDefiningUse(OpaqueHiddenType<'db>),
40+
}
41+
42+
impl<'db> UsageKind<'db> {
43+
fn merge(&mut self, other: UsageKind<'db>) {
44+
match (&*self, &other) {
45+
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
46+
(UsageKind::None, _) => *self = other,
47+
// When mergining non-defining uses, prefer earlier ones. This means
48+
// the error happens as early as possible.
49+
(
50+
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
51+
UsageKind::NonDefiningUse(..),
52+
) => {}
53+
// When merging unconstrained hidden types, we prefer later ones. This is
54+
// used as in most cases, the defining use is the final return statement
55+
// of our function, and other uses with defining arguments are likely not
56+
// intended to be defining.
57+
(
58+
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
59+
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
60+
) => *self = other,
61+
}
62+
}
63+
}
64+
65+
impl<'db> InferenceContext<'_, 'db> {
66+
fn compute_definition_site_hidden_types(
67+
&mut self,
68+
mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>,
69+
) {
70+
for entry in opaque_types.iter_mut() {
71+
*entry = self.table.infer_ctxt.resolve_vars_if_possible(*entry);
72+
}
73+
debug!(?opaque_types);
74+
75+
let interner = self.interner();
76+
let TypingMode::Analysis { defining_opaque_types_and_generators } =
77+
self.table.infer_ctxt.typing_mode()
78+
else {
79+
unreachable!();
80+
};
81+
82+
for def_id in defining_opaque_types_and_generators {
83+
let def_id = match def_id {
84+
SolverDefId::InternedOpaqueTyId(it) => it,
85+
_ => continue,
86+
};
87+
88+
// We do actually need to check this the second pass (we can't just
89+
// store this), because we can go from `UnconstrainedHiddenType` to
90+
// `HasDefiningUse` (because of fallback)
91+
let mut usage_kind = UsageKind::None;
92+
for &(opaque_type_key, hidden_type) in &opaque_types {
93+
if opaque_type_key.def_id != def_id.into() {
94+
continue;
95+
}
96+
97+
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
98+
99+
if let UsageKind::HasDefiningUse(..) = usage_kind {
100+
break;
101+
}
102+
}
103+
104+
if let UsageKind::HasDefiningUse(ty) = usage_kind {
105+
for &(opaque_type_key, hidden_type) in &opaque_types {
106+
if opaque_type_key.def_id != def_id.into() {
107+
continue;
108+
}
109+
110+
let expected =
111+
EarlyBinder::bind(ty.ty).instantiate(interner, opaque_type_key.args);
112+
self.demand_eqtype(expected, hidden_type.ty);
113+
}
114+
115+
self.result.type_of_opaque.insert(def_id, ty.ty);
116+
117+
continue;
118+
}
119+
120+
self.result.type_of_opaque.insert(def_id, self.types.error);
121+
}
122+
}
123+
124+
#[tracing::instrument(skip(self), ret)]
125+
fn consider_opaque_type_use(
126+
&self,
127+
opaque_type_key: OpaqueTypeKey<'db>,
128+
hidden_type: OpaqueHiddenType<'db>,
129+
) -> UsageKind<'db> {
130+
// We ignore uses of the opaque if they have any inference variables
131+
// as this can frequently happen with recursive calls.
132+
//
133+
// See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
134+
if hidden_type.ty.has_non_region_infer() {
135+
return UsageKind::UnconstrainedHiddenType(hidden_type);
136+
}
137+
138+
let cause = ObligationCause::new();
139+
let at = self.table.infer_ctxt.at(&cause, self.table.trait_env.env);
140+
let hidden_type = match at.deeply_normalize(hidden_type) {
141+
Ok(hidden_type) => hidden_type,
142+
Err(_errors) => OpaqueHiddenType { ty: self.types.error },
143+
};
144+
UsageKind::HasDefiningUse(hidden_type)
145+
}
146+
}

crates/hir-ty/src/infer/path.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,10 @@ impl<'db> InferenceContext<'_, 'db> {
310310
let mut not_visible = None;
311311
let res = method_resolution::iterate_method_candidates(
312312
&canonical_ty,
313-
self.db,
314-
self.table.trait_env.clone(),
315-
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
313+
&mut self.table,
314+
Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
315+
.as_ref()
316+
.left_or_else(|&it| it),
316317
VisibleFromModule::Filter(self.resolver.module()),
317318
Some(name),
318319
method_resolution::LookupMode::Path,

0 commit comments

Comments
 (0)