Skip to content

Commit 9632b38

Browse files
authored
Merge pull request #19479 from ChayimFriedman2/generic-mismatch
feat: Add two new diagnostics: one for mismatch in generic arguments count, and another for mismatch in their kind
2 parents 669a308 + 7b8200b commit 9632b38

23 files changed

+1243
-405
lines changed

crates/hir-def/src/expr_store.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ use crate::{
3535
};
3636

3737
pub use self::body::{Body, BodySourceMap};
38-
pub use self::lower::hir_segment_to_ast_segment;
38+
pub use self::lower::{
39+
hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment,
40+
};
3941

4042
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
4143
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

crates/hir-def/src/expr_store/lower.rs

+32
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ impl ExprCollector<'_> {
788788
node: ast::GenericArgList,
789789
impl_trait_lower_fn: &mut impl FnMut(ThinVec<TypeBound>) -> TypeRef,
790790
) -> Option<GenericArgs> {
791+
// This needs to be kept in sync with `hir_generic_arg_to_ast()`.
791792
let mut args = Vec::new();
792793
let mut bindings = Vec::new();
793794
for generic_arg in node.generic_args() {
@@ -797,6 +798,7 @@ impl ExprCollector<'_> {
797798
args.push(GenericArg::Type(type_ref));
798799
}
799800
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
801+
// This needs to be kept in sync with `hir_assoc_type_binding_to_ast()`.
800802
if assoc_type_arg.param_list().is_some() {
801803
// We currently ignore associated return type bounds.
802804
continue;
@@ -3228,3 +3230,33 @@ enum ArgumentType {
32283230
Format(FormatTrait),
32293231
Usize,
32303232
}
3233+
3234+
/// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR.
3235+
pub fn hir_assoc_type_binding_to_ast(
3236+
segment_args: &ast::GenericArgList,
3237+
binding_idx: u32,
3238+
) -> Option<ast::AssocTypeArg> {
3239+
segment_args
3240+
.generic_args()
3241+
.filter_map(|arg| match arg {
3242+
ast::GenericArg::AssocTypeArg(it) => Some(it),
3243+
_ => None,
3244+
})
3245+
.filter(|binding| binding.param_list().is_none() && binding.name_ref().is_some())
3246+
.nth(binding_idx as usize)
3247+
}
3248+
3249+
/// This function find the AST generic argument from the one in the HIR. Does not support the `Self` argument.
3250+
pub fn hir_generic_arg_to_ast(
3251+
args: &ast::GenericArgList,
3252+
arg_idx: u32,
3253+
has_self_arg: bool,
3254+
) -> Option<ast::GenericArg> {
3255+
args.generic_args()
3256+
.filter(|arg| match arg {
3257+
ast::GenericArg::AssocTypeArg(_) => false,
3258+
ast::GenericArg::LifetimeArg(arg) => arg.lifetime().is_some(),
3259+
ast::GenericArg::ConstArg(_) | ast::GenericArg::TypeArg(_) => true,
3260+
})
3261+
.nth(arg_idx as usize - has_self_arg as usize)
3262+
}

crates/hir-def/src/expr_store/lower/path.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,8 @@ pub(super) fn lower_path(
152152
args: iter::once(self_type)
153153
.chain(it.args.iter().cloned())
154154
.collect(),
155-
156155
has_self_type: true,
157-
bindings: it.bindings.clone(),
158-
parenthesized: it.parenthesized,
156+
..it
159157
},
160158
None => GenericArgs {
161159
args: Box::new([self_type]),

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

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ impl GenericParamData {
138138

139139
impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
140140

141+
#[derive(Debug, Clone, Copy)]
141142
pub enum GenericParamDataRef<'a> {
142143
TypeParamData(&'a TypeParamData),
143144
ConstParamData(&'a ConstParamData),

crates/hir-ty/src/builder.rs

+19-20
Original file line numberDiff line numberDiff line change
@@ -306,29 +306,28 @@ impl TyBuilder<hir_def::AdtId> {
306306
// Note that we're building ADT, so we never have parent generic parameters.
307307
let defaults = db.generic_defaults(self.data.into());
308308

309-
for default_ty in &defaults[self.vec.len()..] {
310-
// NOTE(skip_binders): we only check if the arg type is error type.
311-
if let Some(x) = default_ty.skip_binders().ty(Interner) {
312-
if x.is_unknown() {
313-
self.vec.push(fallback().cast(Interner));
314-
continue;
309+
if let Some(defaults) = defaults.get(self.vec.len()..) {
310+
for default_ty in defaults {
311+
// NOTE(skip_binders): we only check if the arg type is error type.
312+
if let Some(x) = default_ty.skip_binders().ty(Interner) {
313+
if x.is_unknown() {
314+
self.vec.push(fallback().cast(Interner));
315+
continue;
316+
}
315317
}
318+
// Each default can only depend on the previous parameters.
319+
self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner));
316320
}
317-
// Each default can only depend on the previous parameters.
318-
let subst_so_far = Substitution::from_iter(
319-
Interner,
320-
self.vec
321-
.iter()
322-
.cloned()
323-
.chain(self.param_kinds[self.vec.len()..].iter().map(|it| match it {
324-
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
325-
ParamKind::Lifetime => error_lifetime().cast(Interner),
326-
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
327-
}))
328-
.take(self.param_kinds.len()),
329-
);
330-
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
331321
}
322+
323+
// The defaults may be missing if no param has default, so fill that.
324+
let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
325+
ParamKind::Type => fallback().cast(Interner),
326+
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
327+
ParamKind::Lifetime => error_lifetime().cast(Interner),
328+
});
329+
self.vec.extend(filler.casted(Interner));
330+
332331
self
333332
}
334333

crates/hir-ty/src/db.rs

+3
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
200200
def: GenericDefId,
201201
) -> (GenericDefaults, Diagnostics);
202202

203+
/// This returns an empty list if no parameter has default.
204+
///
205+
/// The binders of the returned defaults are only up to (not including) this parameter.
203206
#[salsa::invoke(crate::lower::generic_defaults_query)]
204207
#[salsa::transparent]
205208
fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults;

crates/hir-ty/src/display.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,7 @@ fn generic_args_sans_defaults<'ga>(
16401640
Some(default_parameter) => {
16411641
// !is_err(default_parameter.skip_binders())
16421642
// &&
1643-
arg != &default_parameter.clone().substitute(Interner, &parameters)
1643+
arg != &default_parameter.clone().substitute(Interner, &parameters[..i])
16441644
}
16451645
}
16461646
};

crates/hir-ty/src/generics.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use hir_def::{
2121
},
2222
};
2323
use itertools::chain;
24-
use stdx::TupleExt;
2524
use triomphe::Arc;
2625

2726
use crate::{Interner, Substitution, db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx};
@@ -76,10 +75,13 @@ impl Generics {
7675
self.iter_parent().map(|(id, _)| id)
7776
}
7877

79-
pub(crate) fn iter_self_type_or_consts_id(
78+
pub(crate) fn iter_self_type_or_consts(
8079
&self,
81-
) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
82-
self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head)
80+
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> + '_
81+
{
82+
let mut toc = self.params.iter_type_or_consts();
83+
let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten();
84+
chain!(trait_self_param, toc)
8385
}
8486

8587
/// Iterate over the parent params followed by self params.
@@ -107,7 +109,7 @@ impl Generics {
107109
}
108110

109111
/// Iterator over types and const params of parent.
110-
fn iter_parent(
112+
pub(crate) fn iter_parent(
111113
&self,
112114
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
113115
self.parent_generics().into_iter().flat_map(|it| {
@@ -129,6 +131,10 @@ impl Generics {
129131
self.params.len()
130132
}
131133

134+
pub(crate) fn len_lifetimes_self(&self) -> usize {
135+
self.params.len_lifetimes()
136+
}
137+
132138
/// (parent total, self param, type params, const params, impl trait list, lifetimes)
133139
pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) {
134140
let mut self_param = false;
@@ -144,7 +150,7 @@ impl Generics {
144150
TypeOrConstParamData::ConstParamData(_) => const_params += 1,
145151
});
146152

147-
let lifetime_params = self.params.iter_lt().count();
153+
let lifetime_params = self.params.len_lifetimes();
148154

149155
let parent_len = self.parent_generics().map_or(0, Generics::len);
150156
(parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params)

crates/hir-ty/src/infer.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use chalk_ir::{
3434
};
3535
use either::Either;
3636
use hir_def::{
37-
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, GenericDefId, ImplId, ItemContainerId,
38-
Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
37+
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId,
38+
ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
3939
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
4040
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
4141
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -55,8 +55,9 @@ use triomphe::Arc;
5555

5656
use crate::{
5757
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
58-
ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
59-
PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
58+
ImplTraitIdx, InEnvironment, IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId,
59+
ParamLoweringMode, PathLoweringDiagnostic, ProjectionTy, Substitution, TraitEnvironment, Ty,
60+
TyBuilder, TyExt,
6061
db::HirDatabase,
6162
fold_tys,
6263
generics::Generics,
@@ -66,7 +67,7 @@ use crate::{
6667
expr::ExprIsRead,
6768
unify::InferenceTable,
6869
},
69-
lower::{ImplTraitLoweringMode, diagnostics::TyLoweringDiagnostic},
70+
lower::{GenericArgsPosition, ImplTraitLoweringMode, diagnostics::TyLoweringDiagnostic},
7071
mir::MirSpan,
7172
to_assoc_type_id,
7273
traits::FnTrait,
@@ -275,6 +276,20 @@ pub enum InferenceDiagnostic {
275276
node: ExprOrPatId,
276277
diag: PathLoweringDiagnostic,
277278
},
279+
MethodCallIncorrectGenericsLen {
280+
expr: ExprId,
281+
provided_count: u32,
282+
expected_count: u32,
283+
kind: IncorrectGenericsLenKind,
284+
def: GenericDefId,
285+
},
286+
MethodCallIncorrectGenericsOrder {
287+
expr: ExprId,
288+
param_id: GenericParamId,
289+
arg_idx: u32,
290+
/// Whether the `GenericArgs` contains a `Self` arg.
291+
has_self_arg: bool,
292+
},
278293
}
279294

280295
/// A mismatch between an expected and an inferred type.
@@ -909,6 +924,7 @@ impl<'a> InferenceContext<'a> {
909924
let mut param_tys =
910925
self.with_ty_lowering(&data.store, InferenceTyDiagnosticSource::Signature, |ctx| {
911926
ctx.type_param_mode(ParamLoweringMode::Placeholder);
927+
ctx.in_fn_signature = true;
912928
data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
913929
});
914930

@@ -953,8 +969,9 @@ impl<'a> InferenceContext<'a> {
953969
InferenceTyDiagnosticSource::Signature,
954970
|ctx| {
955971
ctx.type_param_mode(ParamLoweringMode::Placeholder)
956-
.impl_trait_mode(ImplTraitLoweringMode::Opaque)
957-
.lower_ty(return_ty)
972+
.impl_trait_mode(ImplTraitLoweringMode::Opaque);
973+
ctx.in_fn_signature = true;
974+
ctx.lower_ty(return_ty)
958975
},
959976
);
960977
let return_ty = self.insert_type_vars(return_ty);
@@ -1513,7 +1530,7 @@ impl<'a> InferenceContext<'a> {
15131530
InferenceTyDiagnosticSource::Body,
15141531
self.generic_def,
15151532
);
1516-
let mut path_ctx = ctx.at_path(path, node);
1533+
let mut path_ctx = ctx.at_path(path, node, GenericArgsPosition::Value);
15171534
let (resolution, unresolved) = if value_ns {
15181535
let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
15191536
return (self.err_ty(), None);

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use hir_def::expr_store::path::Path;
1212
use hir_def::{hir::ExprOrPatId, resolver::Resolver};
1313
use la_arena::{Idx, RawIdx};
1414

15+
use crate::lower::GenericArgsPosition;
1516
use crate::{
1617
InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringContext, TyLoweringDiagnostic,
1718
db::HirDatabase,
@@ -74,6 +75,7 @@ impl<'a> InferenceTyLoweringContext<'a> {
7475
&'b mut self,
7576
path: &'b Path,
7677
node: ExprOrPatId,
78+
position: GenericArgsPosition,
7779
) -> PathLoweringContext<'b, 'a> {
7880
let on_diagnostic = PathDiagnosticCallback {
7981
data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }),
@@ -83,13 +85,14 @@ impl<'a> InferenceTyLoweringContext<'a> {
8385
.push(InferenceDiagnostic::PathDiagnostic { node: data.node, diag });
8486
},
8587
};
86-
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
88+
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path, position)
8789
}
8890

8991
#[inline]
9092
pub(super) fn at_path_forget_diagnostics<'b>(
9193
&'b mut self,
9294
path: &'b Path,
95+
position: GenericArgsPosition,
9396
) -> PathLoweringContext<'b, 'a> {
9497
let on_diagnostic = PathDiagnosticCallback {
9598
data: Either::Right(PathDiagnosticCallbackData {
@@ -98,7 +101,7 @@ impl<'a> InferenceTyLoweringContext<'a> {
98101
}),
99102
callback: |_data, _, _diag| {},
100103
};
101-
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
104+
PathLoweringContext::new(&mut self.ctx, on_diagnostic, path, position)
102105
}
103106

104107
#[inline]

0 commit comments

Comments
 (0)