Auto merge of #16630 - ShoyuVanilla:fix-closure-kind-inference, r=Veykril
fix: Wrong closure kind deduction for closures with predicates Completes #16472, fixes #16421 The changed closure kind deduction is mostly simlar to `rustc_hir_typeck/src/closure.rs`. Porting closure sig deduction from it seems possible too and I'm considering doing it with another PR
This commit is contained in:
commit
a3236be9d7
@ -5,7 +5,7 @@ use std::{cmp, convert::Infallible, mem};
|
||||
use chalk_ir::{
|
||||
cast::Cast,
|
||||
fold::{FallibleTypeFolder, TypeFoldable},
|
||||
AliasEq, AliasTy, BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind, WhereClause,
|
||||
BoundVar, DebruijnIndex, FnSubst, Mutability, TyKind,
|
||||
};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
@ -22,13 +22,14 @@ use stdx::never;
|
||||
|
||||
use crate::{
|
||||
db::{HirDatabase, InternedClosure},
|
||||
from_placeholder_idx, make_binders,
|
||||
from_chalk_trait_id, from_placeholder_idx, make_binders,
|
||||
mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
|
||||
static_lifetime, to_chalk_trait_id,
|
||||
traits::FnTrait,
|
||||
utils::{self, generics, Generics},
|
||||
Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, FnAbi, FnPointer,
|
||||
FnSig, Interner, Substitution, Ty, TyExt,
|
||||
utils::{self, elaborate_clause_supertraits, generics, Generics},
|
||||
Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy,
|
||||
DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty,
|
||||
TyExt, WhereClause,
|
||||
};
|
||||
|
||||
use super::{Expectation, InferenceContext};
|
||||
@ -47,6 +48,15 @@ impl InferenceContext<'_> {
|
||||
None => return,
|
||||
};
|
||||
|
||||
if let TyKind::Closure(closure_id, _) = closure_ty.kind(Interner) {
|
||||
if let Some(closure_kind) = self.deduce_closure_kind_from_expectations(&expected_ty) {
|
||||
self.result
|
||||
.closure_info
|
||||
.entry(*closure_id)
|
||||
.or_insert_with(|| (Vec::new(), closure_kind));
|
||||
}
|
||||
}
|
||||
|
||||
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
||||
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
||||
|
||||
@ -65,6 +75,60 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
// Closure kind deductions are mostly from `rustc_hir_typeck/src/closure.rs`.
|
||||
// Might need to port closure sig deductions too.
|
||||
fn deduce_closure_kind_from_expectations(&mut self, expected_ty: &Ty) -> Option<FnTrait> {
|
||||
match expected_ty.kind(Interner) {
|
||||
TyKind::Alias(AliasTy::Opaque(OpaqueTy { .. })) | TyKind::OpaqueType(..) => {
|
||||
let clauses = expected_ty
|
||||
.impl_trait_bounds(self.db)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|b| b.into_value_and_skipped_binders().0);
|
||||
self.deduce_closure_kind_from_predicate_clauses(clauses)
|
||||
}
|
||||
TyKind::Dyn(dyn_ty) => dyn_ty.principal().and_then(|trait_ref| {
|
||||
self.fn_trait_kind_from_trait_id(from_chalk_trait_id(trait_ref.trait_id))
|
||||
}),
|
||||
TyKind::InferenceVar(ty, chalk_ir::TyVariableKind::General) => {
|
||||
let clauses = self.clauses_for_self_ty(*ty);
|
||||
self.deduce_closure_kind_from_predicate_clauses(clauses.into_iter())
|
||||
}
|
||||
TyKind::Function(_) => Some(FnTrait::Fn),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn deduce_closure_kind_from_predicate_clauses(
|
||||
&self,
|
||||
clauses: impl DoubleEndedIterator<Item = WhereClause>,
|
||||
) -> Option<FnTrait> {
|
||||
let mut expected_kind = None;
|
||||
|
||||
for clause in elaborate_clause_supertraits(self.db, clauses.rev()) {
|
||||
let trait_id = match clause {
|
||||
WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(projection), ..
|
||||
}) => Some(projection.trait_(self.db)),
|
||||
WhereClause::Implemented(trait_ref) => {
|
||||
Some(from_chalk_trait_id(trait_ref.trait_id))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(closure_kind) =
|
||||
trait_id.and_then(|trait_id| self.fn_trait_kind_from_trait_id(trait_id))
|
||||
{
|
||||
// `FnX`'s variants order is opposite from rustc, so use `cmp::max` instead of `cmp::min`
|
||||
expected_kind = Some(
|
||||
expected_kind
|
||||
.map_or_else(|| closure_kind, |current| cmp::max(current, closure_kind)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
expected_kind
|
||||
}
|
||||
|
||||
fn deduce_sig_from_dyn_ty(&self, dyn_ty: &DynTy) -> Option<FnPointer> {
|
||||
// Search for a predicate like `<$self as FnX<Args>>::Output == Ret`
|
||||
|
||||
@ -111,6 +175,10 @@ impl InferenceContext<'_> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn fn_trait_kind_from_trait_id(&self, trait_id: hir_def::TraitId) -> Option<FnTrait> {
|
||||
FnTrait::from_lang_item(self.db.lang_attr(trait_id.into())?)
|
||||
}
|
||||
}
|
||||
|
||||
// The below functions handle capture and closure kind (Fn, FnMut, ..)
|
||||
@ -962,8 +1030,14 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
}
|
||||
self.restrict_precision_for_unsafe();
|
||||
// closure_kind should be done before adjust_for_move_closure
|
||||
let closure_kind = self.closure_kind();
|
||||
// `closure_kind` should be done before adjust_for_move_closure
|
||||
// If there exists pre-deduced kind of a closure, use it instead of one determined by capture, as rustc does.
|
||||
// rustc also does diagnostics here if the latter is not a subtype of the former.
|
||||
let closure_kind = self
|
||||
.result
|
||||
.closure_info
|
||||
.get(&closure)
|
||||
.map_or_else(|| self.closure_kind(), |info| info.1);
|
||||
match capture_by {
|
||||
CaptureBy::Value => self.adjust_for_move_closure(),
|
||||
CaptureBy::Ref => (),
|
||||
|
@ -10,15 +10,16 @@ use chalk_solve::infer::ParameterEnaVariableExt;
|
||||
use either::Either;
|
||||
use ena::unify::UnifyKey;
|
||||
use hir_expand::name;
|
||||
use smallvec::SmallVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
||||
use crate::{
|
||||
consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
|
||||
to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
|
||||
DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar,
|
||||
Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
|
||||
TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
|
||||
DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
|
||||
InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
|
||||
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
|
||||
};
|
||||
|
||||
impl InferenceContext<'_> {
|
||||
@ -31,6 +32,72 @@ impl InferenceContext<'_> {
|
||||
{
|
||||
self.table.canonicalize(t)
|
||||
}
|
||||
|
||||
pub(super) fn clauses_for_self_ty(
|
||||
&mut self,
|
||||
self_ty: InferenceVar,
|
||||
) -> SmallVec<[WhereClause; 4]> {
|
||||
self.table.resolve_obligations_as_possible();
|
||||
|
||||
let root = self.table.var_unification_table.inference_var_root(self_ty);
|
||||
let pending_obligations = mem::take(&mut self.table.pending_obligations);
|
||||
let obligations = pending_obligations
|
||||
.iter()
|
||||
.filter_map(|obligation| match obligation.value.value.goal.data(Interner) {
|
||||
GoalData::DomainGoal(DomainGoal::Holds(
|
||||
clause @ WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(projection),
|
||||
..
|
||||
}),
|
||||
)) => {
|
||||
let projection_self = projection.self_type_parameter(self.db);
|
||||
let uncanonical = chalk_ir::Substitute::apply(
|
||||
&obligation.free_vars,
|
||||
projection_self,
|
||||
Interner,
|
||||
);
|
||||
if matches!(
|
||||
self.resolve_ty_shallow(&uncanonical).kind(Interner),
|
||||
TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root,
|
||||
) {
|
||||
Some(chalk_ir::Substitute::apply(
|
||||
&obligation.free_vars,
|
||||
clause.clone(),
|
||||
Interner,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
GoalData::DomainGoal(DomainGoal::Holds(
|
||||
clause @ WhereClause::Implemented(trait_ref),
|
||||
)) => {
|
||||
let trait_ref_self = trait_ref.self_type_parameter(Interner);
|
||||
let uncanonical = chalk_ir::Substitute::apply(
|
||||
&obligation.free_vars,
|
||||
trait_ref_self,
|
||||
Interner,
|
||||
);
|
||||
if matches!(
|
||||
self.resolve_ty_shallow(&uncanonical).kind(Interner),
|
||||
TyKind::InferenceVar(iv, TyVariableKind::General) if *iv == root,
|
||||
) {
|
||||
Some(chalk_ir::Substitute::apply(
|
||||
&obligation.free_vars,
|
||||
clause.clone(),
|
||||
Interner,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
self.table.pending_obligations = pending_obligations;
|
||||
|
||||
obligations
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -702,25 +702,25 @@ fn test() {
|
||||
51..58 'loop {}': !
|
||||
56..58 '{}': ()
|
||||
72..171 '{ ... x); }': ()
|
||||
78..81 'foo': fn foo<&(i32, &str), i32, impl Fn(&(i32, &str)) -> i32>(&(i32, &str), impl Fn(&(i32, &str)) -> i32) -> i32
|
||||
78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32
|
||||
78..105 'foo(&(...y)| x)': i32
|
||||
82..91 '&(1, "a")': &(i32, &str)
|
||||
83..91 '(1, "a")': (i32, &str)
|
||||
84..85 '1': i32
|
||||
87..90 '"a"': &str
|
||||
93..104 '|&(x, y)| x': impl Fn(&(i32, &str)) -> i32
|
||||
93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32
|
||||
94..101 '&(x, y)': &(i32, &str)
|
||||
95..101 '(x, y)': (i32, &str)
|
||||
96..97 'x': i32
|
||||
99..100 'y': &str
|
||||
103..104 'x': i32
|
||||
142..145 'foo': fn foo<&(i32, &str), &i32, impl Fn(&(i32, &str)) -> &i32>(&(i32, &str), impl Fn(&(i32, &str)) -> &i32) -> &i32
|
||||
142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32
|
||||
142..168 'foo(&(...y)| x)': &i32
|
||||
146..155 '&(1, "a")': &(i32, &str)
|
||||
147..155 '(1, "a")': (i32, &str)
|
||||
148..149 '1': i32
|
||||
151..154 '"a"': &str
|
||||
157..167 '|(x, y)| x': impl Fn(&(i32, &str)) -> &i32
|
||||
157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32
|
||||
158..164 '(x, y)': (i32, &str)
|
||||
159..160 'x': &i32
|
||||
162..163 'y': &&str
|
||||
|
@ -862,7 +862,7 @@ fn main() {
|
||||
123..126 'S()': S<i32>
|
||||
132..133 's': S<i32>
|
||||
132..144 's.g(|_x| {})': ()
|
||||
136..143 '|_x| {}': impl Fn(&i32)
|
||||
136..143 '|_x| {}': impl FnOnce(&i32)
|
||||
137..139 '_x': &i32
|
||||
141..143 '{}': ()
|
||||
150..151 's': S<i32>
|
||||
|
@ -2190,9 +2190,9 @@ fn main() {
|
||||
149..151 'Ok': extern "rust-call" Ok<(), ()>(()) -> Result<(), ()>
|
||||
149..155 'Ok(())': Result<(), ()>
|
||||
152..154 '()': ()
|
||||
167..171 'test': fn test<(), (), impl Fn() -> impl Future<Output = Result<(), ()>>, impl Future<Output = Result<(), ()>>>(impl Fn() -> impl Future<Output = Result<(), ()>>)
|
||||
167..171 'test': fn test<(), (), impl FnMut() -> impl Future<Output = Result<(), ()>>, impl Future<Output = Result<(), ()>>>(impl FnMut() -> impl Future<Output = Result<(), ()>>)
|
||||
167..228 'test(|... })': ()
|
||||
172..227 '|| asy... }': impl Fn() -> impl Future<Output = Result<(), ()>>
|
||||
172..227 '|| asy... }': impl FnMut() -> impl Future<Output = Result<(), ()>>
|
||||
175..227 'async ... }': impl Future<Output = Result<(), ()>>
|
||||
191..205 'return Err(())': !
|
||||
198..201 'Err': extern "rust-call" Err<(), ()>(()) -> Result<(), ()>
|
||||
@ -2886,6 +2886,43 @@ fn f() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closure_kind_with_predicates() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: fn
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
struct X<T: FnOnce()>(T);
|
||||
|
||||
fn f1() -> impl FnOnce() {
|
||||
|| {}
|
||||
// ^^^^^ impl FnOnce()
|
||||
}
|
||||
|
||||
fn f2(c: impl FnOnce<(), Output = i32>) {}
|
||||
|
||||
fn test {
|
||||
let x1 = X(|| {});
|
||||
let c1 = x1.0;
|
||||
// ^^ impl FnOnce()
|
||||
|
||||
let c2 = || {};
|
||||
// ^^ impl Fn()
|
||||
let x2 = X(c2);
|
||||
let c3 = x2.0
|
||||
// ^^ impl Fn()
|
||||
|
||||
let c4 = f1();
|
||||
// ^^ impl FnOnce() + ?Sized
|
||||
|
||||
f2(|| { 0 });
|
||||
// ^^^^^^^^ impl FnOnce() -> i32
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_macro_should_work_for_associated_type() {
|
||||
check_types(
|
||||
|
@ -1333,9 +1333,9 @@ fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
134..165 '{ ...(C)) }': (impl Fn(&str, T), Bar<u8>)
|
||||
140..163 '(|inpu...ar(C))': (impl Fn(&str, T), Bar<u8>)
|
||||
141..154 '|input, t| {}': impl Fn(&str, T)
|
||||
134..165 '{ ...(C)) }': (impl FnOnce(&str, T), Bar<u8>)
|
||||
140..163 '(|inpu...ar(C))': (impl FnOnce(&str, T), Bar<u8>)
|
||||
141..154 '|input, t| {}': impl FnOnce(&str, T)
|
||||
142..147 'input': &str
|
||||
149..150 't': T
|
||||
152..154 '{}': ()
|
||||
@ -1963,20 +1963,20 @@ fn test() {
|
||||
163..167 '1u32': u32
|
||||
174..175 'x': Option<u32>
|
||||
174..190 'x.map(...v + 1)': Option<u32>
|
||||
180..189 '|v| v + 1': impl Fn(u32) -> u32
|
||||
180..189 '|v| v + 1': impl FnOnce(u32) -> u32
|
||||
181..182 'v': u32
|
||||
184..185 'v': u32
|
||||
184..189 'v + 1': u32
|
||||
188..189 '1': u32
|
||||
196..197 'x': Option<u32>
|
||||
196..212 'x.map(... 1u64)': Option<u64>
|
||||
202..211 '|_v| 1u64': impl Fn(u32) -> u64
|
||||
202..211 '|_v| 1u64': impl FnOnce(u32) -> u64
|
||||
203..205 '_v': u32
|
||||
207..211 '1u64': u64
|
||||
222..223 'y': Option<i64>
|
||||
239..240 'x': Option<u32>
|
||||
239..252 'x.map(|_v| 1)': Option<i64>
|
||||
245..251 '|_v| 1': impl Fn(u32) -> i64
|
||||
245..251 '|_v| 1': impl FnOnce(u32) -> i64
|
||||
246..248 '_v': u32
|
||||
250..251 '1': i64
|
||||
"#]],
|
||||
@ -2062,17 +2062,17 @@ fn test() {
|
||||
312..314 '{}': ()
|
||||
330..489 '{ ... S); }': ()
|
||||
340..342 'x1': u64
|
||||
345..349 'foo1': fn foo1<S, u64, impl Fn(S) -> u64>(S, impl Fn(S) -> u64) -> u64
|
||||
345..349 'foo1': fn foo1<S, u64, impl FnOnce(S) -> u64>(S, impl FnOnce(S) -> u64) -> u64
|
||||
345..368 'foo1(S...hod())': u64
|
||||
350..351 'S': S
|
||||
353..367 '|s| s.method()': impl Fn(S) -> u64
|
||||
353..367 '|s| s.method()': impl FnOnce(S) -> u64
|
||||
354..355 's': S
|
||||
357..358 's': S
|
||||
357..367 's.method()': u64
|
||||
378..380 'x2': u64
|
||||
383..387 'foo2': fn foo2<S, u64, impl Fn(S) -> u64>(impl Fn(S) -> u64, S) -> u64
|
||||
383..387 'foo2': fn foo2<S, u64, impl FnOnce(S) -> u64>(impl FnOnce(S) -> u64, S) -> u64
|
||||
383..406 'foo2(|...(), S)': u64
|
||||
388..402 '|s| s.method()': impl Fn(S) -> u64
|
||||
388..402 '|s| s.method()': impl FnOnce(S) -> u64
|
||||
389..390 's': S
|
||||
392..393 's': S
|
||||
392..402 's.method()': u64
|
||||
@ -2081,14 +2081,14 @@ fn test() {
|
||||
421..422 'S': S
|
||||
421..446 'S.foo1...hod())': u64
|
||||
428..429 'S': S
|
||||
431..445 '|s| s.method()': impl Fn(S) -> u64
|
||||
431..445 '|s| s.method()': impl FnOnce(S) -> u64
|
||||
432..433 's': S
|
||||
435..436 's': S
|
||||
435..445 's.method()': u64
|
||||
456..458 'x4': u64
|
||||
461..462 'S': S
|
||||
461..486 'S.foo2...(), S)': u64
|
||||
468..482 '|s| s.method()': impl Fn(S) -> u64
|
||||
468..482 '|s| s.method()': impl FnOnce(S) -> u64
|
||||
469..470 's': S
|
||||
472..473 's': S
|
||||
472..482 's.method()': u64
|
||||
@ -2562,9 +2562,9 @@ fn main() {
|
||||
72..74 '_v': F
|
||||
117..120 '{ }': ()
|
||||
132..163 '{ ... }); }': ()
|
||||
138..148 'f::<(), _>': fn f<(), impl Fn(&())>(impl Fn(&()))
|
||||
138..148 'f::<(), _>': fn f<(), impl FnOnce(&())>(impl FnOnce(&()))
|
||||
138..160 'f::<()... z; })': ()
|
||||
149..159 '|z| { z; }': impl Fn(&())
|
||||
149..159 '|z| { z; }': impl FnOnce(&())
|
||||
150..151 'z': &()
|
||||
153..159 '{ z; }': ()
|
||||
155..156 'z': &()
|
||||
@ -2749,9 +2749,9 @@ fn main() {
|
||||
983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
|
||||
983..1000 'Vec::<...:new()': Vec<i32>
|
||||
983..1012 'Vec::<...iter()': IntoIter<i32>
|
||||
983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, impl Fn(i32) -> Option<u32>>
|
||||
983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, impl FnMut(i32) -> Option<u32>>
|
||||
983..1101 'Vec::<... y; })': ()
|
||||
1029..1074 '|x| if...None }': impl Fn(i32) -> Option<u32>
|
||||
1029..1074 '|x| if...None }': impl FnMut(i32) -> Option<u32>
|
||||
1030..1031 'x': i32
|
||||
1033..1074 'if x >...None }': Option<u32>
|
||||
1036..1037 'x': i32
|
||||
@ -2764,7 +2764,7 @@ fn main() {
|
||||
1049..1057 'x as u32': u32
|
||||
1066..1074 '{ None }': Option<u32>
|
||||
1068..1072 'None': Option<u32>
|
||||
1090..1100 '|y| { y; }': impl Fn(u32)
|
||||
1090..1100 '|y| { y; }': impl FnMut(u32)
|
||||
1091..1092 'y': u32
|
||||
1094..1100 '{ y; }': ()
|
||||
1096..1097 'y': u32
|
||||
@ -3101,8 +3101,8 @@ fn foo() {
|
||||
232..236 'None': Option<i32>
|
||||
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
|
||||
281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
|
||||
294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
|
||||
300..307 '|ps| {}': impl Fn(&Option<i32>)
|
||||
294..308 '&mut (|ps| {})': &mut impl FnOnce(&Option<i32>)
|
||||
300..307 '|ps| {}': impl FnOnce(&Option<i32>)
|
||||
301..303 'ps': &Option<i32>
|
||||
305..307 '{}': ()
|
||||
316..317 'f': Box<dyn FnOnce(&Option<i32>)>
|
||||
|
@ -218,6 +218,15 @@ impl FnTrait {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_lang_item(lang_item: LangItem) -> Option<Self> {
|
||||
match lang_item {
|
||||
LangItem::FnOnce => Some(FnTrait::FnOnce),
|
||||
LangItem::FnMut => Some(FnTrait::FnMut),
|
||||
LangItem::Fn => Some(FnTrait::Fn),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind {
|
||||
match self {
|
||||
FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce,
|
||||
|
@ -112,6 +112,52 @@ impl Iterator for SuperTraits<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn elaborate_clause_supertraits(
|
||||
db: &dyn HirDatabase,
|
||||
clauses: impl Iterator<Item = WhereClause>,
|
||||
) -> ClauseElaborator<'_> {
|
||||
let mut elaborator = ClauseElaborator { db, stack: Vec::new(), seen: FxHashSet::default() };
|
||||
elaborator.extend_deduped(clauses);
|
||||
|
||||
elaborator
|
||||
}
|
||||
|
||||
pub(super) struct ClauseElaborator<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
stack: Vec<WhereClause>,
|
||||
seen: FxHashSet<WhereClause>,
|
||||
}
|
||||
|
||||
impl<'a> ClauseElaborator<'a> {
|
||||
fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) {
|
||||
self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone())))
|
||||
}
|
||||
|
||||
fn elaborate_supertrait(&mut self, clause: &WhereClause) {
|
||||
if let WhereClause::Implemented(trait_ref) = clause {
|
||||
direct_super_trait_refs(self.db, trait_ref, |t| {
|
||||
let clause = WhereClause::Implemented(t);
|
||||
if self.seen.insert(clause.clone()) {
|
||||
self.stack.push(clause);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ClauseElaborator<'_> {
|
||||
type Item = WhereClause;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(next) = self.stack.pop() {
|
||||
self.elaborate_supertrait(&next);
|
||||
Some(next)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
|
||||
let resolver = trait_.resolver(db);
|
||||
let generic_params = db.generic_params(trait_.into());
|
||||
|
Loading…
x
Reference in New Issue
Block a user