Skip to content

Commit 71e5ccc

Browse files
Fix extract_type_alias with const generics
This fixes SourceAnalyzer::type_of_type to replace const errors in types with their resolved value. The new helper fold_tys_and_consts is mostly the same as fold_tys, with an extra callback for Consts.
1 parent 7a7d9f1 commit 71e5ccc

3 files changed

Lines changed: 110 additions & 6 deletions

File tree

crates/hir-ty/src/next_solver/fold.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,40 @@ pub fn fold_tys<'db, T: TypeFoldable<DbInterner<'db>>>(
159159
t.fold_with(&mut Folder { interner, callback })
160160
}
161161

162+
pub fn fold_tys_and_consts<'db, T: TypeFoldable<DbInterner<'db>>>(
163+
interner: DbInterner<'db>,
164+
t: T,
165+
ty_callback: impl FnMut(Ty<'db>) -> Ty<'db>,
166+
const_callback: impl FnMut(Const<'db>) -> Const<'db>,
167+
) -> T {
168+
struct Folder<'db, F, G> {
169+
interner: DbInterner<'db>,
170+
ty_callback: F,
171+
const_callback: G,
172+
}
173+
impl<'db, F, G> TypeFolder<DbInterner<'db>> for Folder<'db, F, G>
174+
where
175+
F: FnMut(Ty<'db>) -> Ty<'db>,
176+
G: FnMut(Const<'db>) -> Const<'db>,
177+
{
178+
fn cx(&self) -> DbInterner<'db> {
179+
self.interner
180+
}
181+
182+
fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
183+
let t = t.super_fold_with(self);
184+
(self.ty_callback)(t)
185+
}
186+
187+
fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
188+
let c = c.super_fold_with(self);
189+
(self.const_callback)(c)
190+
}
191+
}
192+
193+
t.fold_with(&mut Folder { interner, ty_callback, const_callback })
194+
}
195+
162196
impl<'db> DbInterner<'db> {
163197
/// Replaces all regions bound by the given `Binder` with the
164198
/// results returned by the closure; the closure is expected to

crates/hir/src/source_analyzer.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -356,22 +356,50 @@ impl<'db> SourceAnalyzer<'db> {
356356
&& let Some(store) = self.store()
357357
{
358358
let mut inferred_types = vec![];
359+
let mut inferred_consts = vec![];
359360
TypeRef::walk(type_ref, store, &mut |type_ref_or_expr_id| {
360361
use hir_def::hir::TypeRefOrExprId::*;
361362
match type_ref_or_expr_id {
362363
TypeRefId(type_ref_id) => {
363364
if matches!(store[type_ref_id], TypeRef::Placeholder) {
364-
inferred_types.push(infer.type_of_type_placeholder(type_ref_id));
365+
if let Some(const_) =
366+
infer.const_of_const_placeholder(type_ref_or_expr_id)
367+
{
368+
inferred_consts.push(Some(const_));
369+
} else {
370+
inferred_types.push(infer.type_of_type_placeholder(type_ref_id));
371+
}
372+
}
373+
}
374+
ExprId(expr_id) => {
375+
if matches!(store[expr_id], Expr::Underscore) {
376+
inferred_consts
377+
.push(infer.const_of_const_placeholder(type_ref_or_expr_id));
365378
}
366379
}
367-
ExprId(_) => {}
368380
}
369381
});
370382
let mut inferred_types = inferred_types.into_iter();
371-
372-
let substituted_ty = hir_ty::next_solver::fold::fold_tys(interner, ty, |ty| {
373-
if ty.is_ty_error() { inferred_types.next().flatten().unwrap_or(ty) } else { ty }
374-
});
383+
let mut inferred_consts = inferred_consts.into_iter();
384+
385+
let substituted_ty = hir_ty::next_solver::fold::fold_tys_and_consts(
386+
interner,
387+
ty,
388+
|ty| {
389+
if ty.is_ty_error() {
390+
inferred_types.next().flatten().unwrap_or(ty)
391+
} else {
392+
ty
393+
}
394+
},
395+
|const_| {
396+
if const_.is_error() {
397+
inferred_consts.next().flatten().unwrap_or(const_)
398+
} else {
399+
const_
400+
}
401+
},
402+
);
375403

376404
// Only used the result if the placeholder and unknown type counts matched
377405
let success =

crates/ide-assists/src/handlers/extract_type_alias.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,48 @@ fn main() {
427427
)
428428
}
429429

430+
#[test]
431+
fn inferred_array_length() {
432+
check_assist(
433+
extract_type_alias,
434+
r#"
435+
fn main() {
436+
let a: $0[i32; _]$0 = [1, 2, 3];
437+
}
438+
"#,
439+
r#"
440+
type $0Type = [i32; 3];
441+
442+
fn main() {
443+
let a: Type = [1, 2, 3];
444+
}
445+
"#,
446+
)
447+
}
448+
449+
#[test]
450+
fn inferred_generic_const_parameter() {
451+
check_assist(
452+
extract_type_alias,
453+
r#"
454+
struct Wrap<const N: usize>([i32; N]);
455+
456+
fn main() {
457+
let wrap: $0Wrap<_>$0 = Wrap([1, 2, 3]);
458+
}
459+
"#,
460+
r#"
461+
struct Wrap<const N: usize>([i32; N]);
462+
463+
type $0Type = Wrap<3>;
464+
465+
fn main() {
466+
let wrap: Type = Wrap([1, 2, 3]);
467+
}
468+
"#,
469+
)
470+
}
471+
430472
#[test]
431473
fn inferred_type() {
432474
check_assist(

0 commit comments

Comments
 (0)