Skip to content

Commit 52c6ec3

Browse files
Add two new diagnostics: one for mismatch in generic arguments count, and another for mismatch in their kind
Also known as E0747 and E0107. And by the way, rewrite how we lower generic arguments and deduplicate it between paths and method calls. The new version is taken almost straight from rustc. This commit also changes the binders of `generic_defaults()`, to only include the binders of the arguments up to (and not including) the current argument. This make it easier to handle it in the rewritten lowering of generic args. It's also how rustc does it.
1 parent 2b4b483 commit 52c6ec3

22 files changed

+1236
-404
lines changed

crates/hir-def/src/expr_store.rs

Lines changed: 3 additions & 1 deletion
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

Lines changed: 32 additions & 0 deletions
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

Lines changed: 1 addition & 3 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 19 additions & 20 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 12 additions & 6 deletions
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

Lines changed: 25 additions & 8 deletions
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

Lines changed: 5 additions & 2 deletions
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)