Skip to content

Commit b771de3

Browse files
committed
Auto merge of rust-lang#15179 - ponyii:fix/default-values-of-const-params-are-ignored, r=HKalbasi
the "add missing members" assists: implemented substitution of default values of const params To achieve this, I've made `hir::ConstParamData` store the default values
2 parents 7ca45dc + 68e8379 commit b771de3

18 files changed

+265
-103
lines changed

crates/hir-def/src/generics.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{
2525
lower::LowerCtx,
2626
nameres::{DefMap, MacroSubNs},
2727
src::{HasChildSource, HasSource},
28-
type_ref::{LifetimeRef, TypeBound, TypeRef},
28+
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
2929
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
3030
LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
3131
};
@@ -49,7 +49,7 @@ pub struct LifetimeParamData {
4949
pub struct ConstParamData {
5050
pub name: Name,
5151
pub ty: Interned<TypeRef>,
52-
pub has_default: bool,
52+
pub default: Option<ConstRef>,
5353
}
5454

5555
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
@@ -76,7 +76,7 @@ impl TypeOrConstParamData {
7676
pub fn has_default(&self) -> bool {
7777
match self {
7878
TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
79-
TypeOrConstParamData::ConstParamData(it) => it.has_default,
79+
TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
8080
}
8181
}
8282

@@ -307,7 +307,7 @@ impl GenericParams {
307307
let param = ConstParamData {
308308
name,
309309
ty: Interned::new(ty),
310-
has_default: const_param.default_val().is_some(),
310+
default: ConstRef::from_const_param(lower_ctx, &const_param),
311311
};
312312
let idx = self.type_or_consts.alloc(param.into());
313313
add_param_attrs(idx.into(), ast::GenericParam::ConstParam(const_param));

crates/hir-def/src/hir/type_ref.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,17 @@ impl ConstRef {
393393
Self::Scalar(LiteralConstRef::Unknown)
394394
}
395395

396+
pub(crate) fn from_const_param(
397+
lower_ctx: &LowerCtx<'_>,
398+
param: &ast::ConstParam,
399+
) -> Option<Self> {
400+
let default = param.default_val();
401+
match default {
402+
Some(_) => Some(Self::from_const_arg(lower_ctx, default)),
403+
None => None,
404+
}
405+
}
406+
396407
pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a {
397408
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef);
398409
impl fmt::Display for Display<'_> {

crates/hir-ty/src/lib.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ use hir_expand::name;
5252
use la_arena::{Arena, Idx};
5353
use mir::{MirEvalError, VTableMap};
5454
use rustc_hash::FxHashSet;
55+
use syntax::ast::{make, ConstArg};
5556
use traits::FnTrait;
5657
use triomphe::Arc;
5758
use utils::Generics;
5859

5960
use crate::{
60-
consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
61+
consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable,
62+
utils::generics,
6163
};
6264

6365
pub use autoderef::autoderef;
@@ -719,3 +721,16 @@ where
719721
value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
720722
collector.placeholders.into_iter().collect()
721723
}
724+
725+
pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstArg> {
726+
if let ConstValue::Concrete(c) = &konst.interned().value {
727+
match c.interned {
728+
ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
729+
return Some(cid.source(db.upcast()));
730+
}
731+
ConstScalar::Unknown => return None,
732+
_ => (),
733+
}
734+
}
735+
Some(make::expr_const_value(konst.display(db).to_string().as_str()))
736+
}

crates/hir-ty/src/lower.rs

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,19 @@ impl<'a> TyLoweringContext<'a> {
212212
self.lower_ty_ext(type_ref).0
213213
}
214214

215+
pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const {
216+
const_or_path_to_chalk(
217+
self.db,
218+
self.resolver,
219+
self.owner,
220+
const_type,
221+
const_ref,
222+
self.type_param_mode,
223+
|| self.generics(),
224+
self.in_binders,
225+
)
226+
}
227+
215228
fn generics(&self) -> Generics {
216229
generics(
217230
self.db.upcast(),
@@ -241,17 +254,7 @@ impl<'a> TyLoweringContext<'a> {
241254
}
242255
TypeRef::Array(inner, len) => {
243256
let inner_ty = self.lower_ty(inner);
244-
let const_len = const_or_path_to_chalk(
245-
self.db,
246-
self.resolver,
247-
self.owner,
248-
TyBuilder::usize(),
249-
len,
250-
self.type_param_mode,
251-
|| self.generics(),
252-
self.in_binders,
253-
);
254-
257+
let const_len = self.lower_const(len, TyBuilder::usize());
255258
TyKind::Array(inner_ty, const_len).intern(Interner)
256259
}
257260
TypeRef::Slice(inner) => {
@@ -846,18 +849,7 @@ impl<'a> TyLoweringContext<'a> {
846849
arg,
847850
&mut (),
848851
|_, type_ref| self.lower_ty(type_ref),
849-
|_, c, ty| {
850-
const_or_path_to_chalk(
851-
self.db,
852-
self.resolver,
853-
self.owner,
854-
ty,
855-
c,
856-
self.type_param_mode,
857-
|| self.generics(),
858-
self.in_binders,
859-
)
860-
},
852+
|_, const_ref, ty| self.lower_const(const_ref, ty),
861853
) {
862854
had_explicit_args = true;
863855
substs.push(x);
@@ -1603,24 +1595,35 @@ pub(crate) fn generic_defaults_query(
16031595
.iter()
16041596
.enumerate()
16051597
.map(|(idx, (id, p))| {
1606-
let p = match p {
1607-
TypeOrConstParamData::TypeParamData(p) => p,
1608-
TypeOrConstParamData::ConstParamData(_) => {
1609-
// FIXME: implement const generic defaults
1610-
let val = unknown_const_as_generic(
1611-
db.const_param_ty(ConstParamId::from_unchecked(id)),
1598+
match p {
1599+
TypeOrConstParamData::TypeParamData(p) => {
1600+
let mut ty = p
1601+
.default
1602+
.as_ref()
1603+
.map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
1604+
// Each default can only refer to previous parameters.
1605+
// Type variable default referring to parameter coming
1606+
// after it is forbidden (FIXME: report diagnostic)
1607+
ty = fallback_bound_vars(ty, idx, parent_start_idx);
1608+
crate::make_binders(db, &generic_params, ty.cast(Interner))
1609+
}
1610+
TypeOrConstParamData::ConstParamData(p) => {
1611+
let mut val = p.default.as_ref().map_or_else(
1612+
|| {
1613+
unknown_const_as_generic(
1614+
db.const_param_ty(ConstParamId::from_unchecked(id)),
1615+
)
1616+
},
1617+
|c| {
1618+
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
1619+
c.cast(Interner)
1620+
},
16121621
);
1613-
return make_binders(db, &generic_params, val);
1622+
// Each default can only refer to previous parameters, see above.
1623+
val = fallback_bound_vars(val, idx, parent_start_idx);
1624+
make_binders(db, &generic_params, val)
16141625
}
1615-
};
1616-
let mut ty =
1617-
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
1618-
1619-
// Each default can only refer to previous parameters.
1620-
// Type variable default referring to parameter coming
1621-
// after it is forbidden (FIXME: report diagnostic)
1622-
ty = fallback_bound_vars(ty, idx, parent_start_idx);
1623-
crate::make_binders(db, &generic_params, ty.cast(Interner))
1626+
}
16241627
})
16251628
// FIXME: use `Arc::from_iter` when it becomes available
16261629
.collect::<Vec<_>>(),

crates/hir/src/lib.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ use hir_ty::{
6363
all_super_traits, autoderef,
6464
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
6565
diagnostics::BodyValidationDiagnostic,
66+
known_const_to_ast,
6667
layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding},
6768
method_resolution::{self, TyFingerprint},
6869
mir::{self, interpret_mir},
6970
primitive::UintTy,
7071
traits::FnTrait,
71-
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
72+
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
7273
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
7374
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
7475
WhereClause,
@@ -3128,12 +3129,8 @@ impl TypeParam {
31283129
}
31293130

31303131
pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
3131-
let params = db.generic_defaults(self.id.parent());
3132-
let local_idx = hir_ty::param_idx(db, self.id.into())?;
3132+
let ty = generic_arg_from_param(db, self.id.into())?;
31333133
let resolver = self.id.parent().resolver(db.upcast());
3134-
let ty = params.get(local_idx)?.clone();
3135-
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
3136-
let ty = ty.substitute(Interner, &subst);
31373134
match ty.data(Interner) {
31383135
GenericArgData::Ty(it) => {
31393136
Some(Type::new_with_resolver_inner(db, &resolver, it.clone()))
@@ -3195,6 +3192,19 @@ impl ConstParam {
31953192
pub fn ty(self, db: &dyn HirDatabase) -> Type {
31963193
Type::new(db, self.id.parent(), db.const_param_ty(self.id))
31973194
}
3195+
3196+
pub fn default(self, db: &dyn HirDatabase) -> Option<ast::ConstArg> {
3197+
let arg = generic_arg_from_param(db, self.id.into())?;
3198+
known_const_to_ast(arg.constant(Interner)?, db)
3199+
}
3200+
}
3201+
3202+
fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> {
3203+
let params = db.generic_defaults(id.parent);
3204+
let local_idx = hir_ty::param_idx(db, id)?;
3205+
let ty = params.get(local_idx)?.clone();
3206+
let subst = TyBuilder::placeholder_subst(db, id.parent);
3207+
Some(ty.substitute(Interner, &subst))
31983208
}
31993209

32003210
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]

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

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () {
422422
check_assist(
423423
add_missing_default_members,
424424
r#"
425-
struct Bar<const: N: bool> {
425+
struct Bar<const N: usize> {
426426
bar: [i32, N]
427427
}
428428
@@ -439,7 +439,7 @@ impl<const X: usize, Y, Z> Foo<X, Z> for S<Y> {
439439
$0
440440
}"#,
441441
r#"
442-
struct Bar<const: N: bool> {
442+
struct Bar<const N: usize> {
443443
bar: [i32, N]
444444
}
445445
@@ -483,6 +483,107 @@ impl<X> Foo<42, {20 + 22}, X> for () {
483483
)
484484
}
485485

486+
#[test]
487+
fn test_const_substitution_with_defaults() {
488+
check_assist(
489+
add_missing_default_members,
490+
r#"
491+
trait Foo<T, const N: usize = 42, const M: bool = false, const P: char = 'a'> {
492+
fn get_n(&self) -> usize { N }
493+
fn get_m(&self) -> bool { M }
494+
fn get_p(&self) -> char { P }
495+
fn get_array(&self, arg: &T) -> [bool; N] { [M; N] }
496+
}
497+
498+
impl<X> Foo<X> for () {
499+
$0
500+
}"#,
501+
r#"
502+
trait Foo<T, const N: usize = 42, const M: bool = false, const P: char = 'a'> {
503+
fn get_n(&self) -> usize { N }
504+
fn get_m(&self) -> bool { M }
505+
fn get_p(&self) -> char { P }
506+
fn get_array(&self, arg: &T) -> [bool; N] { [M; N] }
507+
}
508+
509+
impl<X> Foo<X> for () {
510+
$0fn get_n(&self) -> usize { 42 }
511+
512+
fn get_m(&self) -> bool { false }
513+
514+
fn get_p(&self) -> char { 'a' }
515+
516+
fn get_array(&self, arg: &X) -> [bool; 42] { [false; 42] }
517+
}"#,
518+
);
519+
}
520+
521+
#[test]
522+
fn test_const_substitution_with_defaults_2() {
523+
check_assist(
524+
add_missing_impl_members,
525+
r#"
526+
mod m {
527+
pub const LEN: usize = 42;
528+
pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
529+
fn get_t(&self) -> T;
530+
}
531+
}
532+
533+
impl m::Foo for () {
534+
$0
535+
}"#,
536+
r#"
537+
mod m {
538+
pub const LEN: usize = 42;
539+
pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
540+
fn get_t(&self) -> T;
541+
}
542+
}
543+
544+
impl m::Foo for () {
545+
fn get_t(&self) -> [bool; m::LEN] {
546+
${0:todo!()}
547+
}
548+
}"#,
549+
)
550+
}
551+
552+
#[test]
553+
fn test_const_substitution_with_defaults_3() {
554+
check_assist(
555+
add_missing_default_members,
556+
r#"
557+
mod m {
558+
pub const VAL: usize = 0;
559+
560+
pub trait Foo<const N: usize = {40 + 2}, const M: usize = {VAL + 1}> {
561+
fn get_n(&self) -> usize { N }
562+
fn get_m(&self) -> usize { M }
563+
}
564+
}
565+
566+
impl m::Foo for () {
567+
$0
568+
}"#,
569+
r#"
570+
mod m {
571+
pub const VAL: usize = 0;
572+
573+
pub trait Foo<const N: usize = {40 + 2}, const M: usize = {VAL + 1}> {
574+
fn get_n(&self) -> usize { N }
575+
fn get_m(&self) -> usize { M }
576+
}
577+
}
578+
579+
impl m::Foo for () {
580+
$0fn get_n(&self) -> usize { {40 + 2} }
581+
582+
fn get_m(&self) -> usize { {m::VAL + 1} }
583+
}"#,
584+
)
585+
}
586+
486587
#[test]
487588
fn test_cursor_after_empty_impl_def() {
488589
check_assist(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ impl FunctionBody {
810810
(true, konst.body(), Some(sema.to_def(&konst)?.ty(sema.db)))
811811
},
812812
ast::ConstParam(cp) => {
813-
(true, cp.default_val(), Some(sema.to_def(&cp)?.ty(sema.db)))
813+
(true, cp.default_val()?.expr(), Some(sema.to_def(&cp)?.ty(sema.db)))
814814
},
815815
ast::ConstBlockPat(cbp) => {
816816
let expr = cbp.block_expr().map(ast::Expr::BlockExpr);

crates/ide-db/src/imports/import_assets.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use hir::{
66
use itertools::Itertools;
77
use rustc_hash::FxHashSet;
88
use syntax::{
9-
ast::{self, HasName},
9+
ast::{self, make, HasName},
1010
utils::path_to_string_stripping_turbo_fish,
1111
AstNode, SyntaxNode,
1212
};
@@ -607,7 +607,7 @@ impl ImportCandidate {
607607
fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<Self> {
608608
if sema
609609
.scope(name.syntax())?
610-
.speculative_resolve(&ast::make::ext::ident_path(&name.text()))
610+
.speculative_resolve(&make::ext::ident_path(&name.text()))
611611
.is_some()
612612
{
613613
return None;

0 commit comments

Comments
 (0)