Skip to content

Commit cf1a456

Browse files
committed
Implement trait impl method label integrity check
1 parent a2c2040 commit cf1a456

File tree

9 files changed

+165
-23
lines changed

9 files changed

+165
-23
lines changed

crates/hir-analysis/src/ty/def_analysis.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,14 +1066,16 @@ impl<'db> ImplTraitMethodAnalyzer<'db> {
10661066
let mut subst = self.implementor.subst_table(self.db);
10671067

10681068
let mut is_err = false;
1069+
let hir_impl_method = impl_method.hir_func(self.db);
1070+
let hir_expected_method = expected_method.0.hir_func(self.db);
10691071

10701072
// Checks if the number of parameters are the same.
10711073
let method_params = impl_method.params(self.db);
10721074
let expected_params = expected_method.0.params(self.db);
10731075
if method_params.len() != expected_params.len() {
10741076
self.diags.push(
10751077
ImplDiag::method_param_num_mismatch(
1076-
impl_method.hir_func(self.db).lazy_span().name().into(),
1078+
hir_impl_method.lazy_span().name().into(),
10771079
expected_params.len(),
10781080
method_params.len(),
10791081
)
@@ -1094,8 +1096,7 @@ impl<'db> ImplTraitMethodAnalyzer<'db> {
10941096
let given_kind = method_param.kind(self.db);
10951097

10961098
if expected_kind != given_kind {
1097-
let span = impl_method
1098-
.hir_func(self.db)
1099+
let span = hir_impl_method
10991100
.lazy_span()
11001101
.generic_params()
11011102
.param(idx)
@@ -1120,11 +1121,7 @@ impl<'db> ImplTraitMethodAnalyzer<'db> {
11201121
if expected_arg_tys.len() != method_arg_tys.len() {
11211122
self.diags.push(
11221123
ImplDiag::method_arg_num_mismatch(
1123-
impl_method
1124-
.hir_func(self.db)
1125-
.lazy_span()
1126-
.params_moved()
1127-
.into(),
1124+
hir_impl_method.lazy_span().params_moved().into(),
11281125
expected_arg_tys.len(),
11291126
method_arg_tys.len(),
11301127
)
@@ -1137,6 +1134,48 @@ impl<'db> ImplTraitMethodAnalyzer<'db> {
11371134
return;
11381135
}
11391136

1137+
// Checks if the argument labels are the same.
1138+
for (idx, (expected_param, method_param)) in expected_method
1139+
.0
1140+
.hir_params(self.db)
1141+
.iter()
1142+
.zip(impl_method.hir_params(self.db))
1143+
.enumerate()
1144+
{
1145+
let Some(expected_label) = expected_param
1146+
.label
1147+
.or_else(|| expected_param.name.to_opt())
1148+
else {
1149+
continue;
1150+
};
1151+
1152+
let Some(method_label) = method_param.label.or_else(|| method_param.name.to_opt())
1153+
else {
1154+
continue;
1155+
};
1156+
1157+
if expected_label != method_label {
1158+
let primary = hir_impl_method.lazy_span().params_moved().param(idx).into();
1159+
let sub = hir_expected_method
1160+
.lazy_span()
1161+
.params_moved()
1162+
.param(idx)
1163+
.into();
1164+
1165+
self.diags.push(
1166+
ImplDiag::method_arg_label_mismatch(
1167+
self.db,
1168+
primary,
1169+
sub,
1170+
expected_label,
1171+
method_label,
1172+
)
1173+
.into(),
1174+
);
1175+
is_err = true;
1176+
}
1177+
}
1178+
11401179
// Checks if the argument types are the same.
11411180
for (idx, (expected_arg_ty, &method_arg_ty)) in
11421181
expected_arg_tys.iter().zip(method_arg_tys).enumerate()

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

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use common::diagnostics::{
55
};
66
use hir::{
77
diagnostics::DiagnosticVoucher,
8-
hir_def::{IdentId, ImplTrait, Trait, TypeAlias as HirTypeAlias},
8+
hir_def::{FuncParamName, IdentId, ImplTrait, Trait, TypeAlias as HirTypeAlias},
99
span::{DynLazySpan, LazySpan},
1010
HirDb, SpannedHirDb,
1111
};
@@ -692,6 +692,12 @@ pub enum ImplDiag {
692692
given: usize,
693693
},
694694

695+
MethodArgLabelMismatch {
696+
primary: DynLazySpan,
697+
definition: DynLazySpan,
698+
message: String,
699+
},
700+
695701
MethodArgTyMismatch {
696702
primary: DynLazySpan,
697703
message: String,
@@ -782,6 +788,26 @@ impl ImplDiag {
782788
Self::MethodArgTyMismatch { primary, message }
783789
}
784790

791+
pub fn method_arg_label_mismatch(
792+
db: &dyn HirAnalysisDb,
793+
primary: DynLazySpan,
794+
definition: DynLazySpan,
795+
expected: FuncParamName,
796+
given: FuncParamName,
797+
) -> Self {
798+
let message = format!(
799+
"expected `{}` label, but the given label is `{}`",
800+
expected.pretty_print(db.as_hir_db()),
801+
given.pretty_print(db.as_hir_db())
802+
);
803+
804+
Self::MethodArgLabelMismatch {
805+
primary,
806+
definition,
807+
message,
808+
}
809+
}
810+
785811
pub fn method_ret_type_mismatch(
786812
db: &dyn HirAnalysisDb,
787813
primary: DynLazySpan,
@@ -855,10 +881,11 @@ impl ImplDiag {
855881
Self::MethodTypeParamNumMismatch { .. } => 3,
856882
Self::MethodTypeParamKindMismatch { .. } => 4,
857883
Self::MethodArgNumMismatch { .. } => 5,
858-
Self::MethodArgTyMismatch { .. } => 6,
859-
Self::MethodRetTyMismatch { .. } => 7,
860-
Self::MethodStricterBound { .. } => 8,
861-
Self::InvalidSelfType { .. } => 9,
884+
Self::MethodArgLabelMismatch { .. } => 6,
885+
Self::MethodArgTyMismatch { .. } => 7,
886+
Self::MethodRetTyMismatch { .. } => 8,
887+
Self::MethodStricterBound { .. } => 9,
888+
Self::InvalidSelfType { .. } => 10,
862889
}
863890
}
864891

@@ -891,6 +918,11 @@ impl ImplDiag {
891918
"trait method argument number mismatch".to_string()
892919
}
893920

921+
Self::MethodArgLabelMismatch { .. } => {
922+
"given argument label doesn't match the expected label required by trait"
923+
.to_string()
924+
}
925+
894926
Self::MethodArgTyMismatch { .. } => {
895927
"given argument type doesn't match the expected type required by trait".to_string()
896928
}
@@ -1002,6 +1034,21 @@ impl ImplDiag {
10021034
)]
10031035
}
10041036

1037+
Self::MethodArgLabelMismatch {
1038+
primary,
1039+
definition,
1040+
message,
1041+
} => {
1042+
vec![
1043+
SubDiagnostic::new(LabelStyle::Primary, message.clone(), primary.resolve(db)),
1044+
SubDiagnostic::new(
1045+
LabelStyle::Secondary,
1046+
"argument label is defined here".to_string(),
1047+
definition.resolve(db),
1048+
),
1049+
]
1050+
}
1051+
10051052
Self::MethodArgTyMismatch { primary, message } => {
10061053
vec![SubDiagnostic::new(
10071054
LabelStyle::Primary,

crates/hir-analysis/src/ty/ty_def.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use hir::{
77
kw,
88
prim_ty::{IntTy as HirIntTy, PrimTy as HirPrimTy, UintTy as HirUintTy},
99
scope_graph::ScopeId,
10-
Contract, Enum, Func, IdentId, IngotId, ItemKind, Partial, Struct,
11-
TypeAlias as HirTypeAlias, TypeId as HirTyId, VariantKind,
10+
Contract, Enum, Func, FuncParam as HirFuncParam, IdentId, IngotId, ItemKind, Partial,
11+
Struct, TypeAlias as HirTypeAlias, TypeId as HirTyId, VariantKind,
1212
},
1313
span::DynLazySpan,
1414
};
@@ -414,6 +414,15 @@ impl FuncDef {
414414
pub(super) fn constraints(self, db: &dyn HirAnalysisDb) -> ConstraintListId {
415415
collect_func_def_constraints(db, self)
416416
}
417+
418+
pub(super) fn hir_params(self, db: &dyn HirAnalysisDb) -> &[HirFuncParam] {
419+
const EMPTY: &[HirFuncParam] = &[];
420+
self.hir_func(db)
421+
.params(db.as_hir_db())
422+
.to_opt()
423+
.map(|list| list.data(db.as_hir_db()).as_ref())
424+
.unwrap_or(EMPTY)
425+
}
417426
}
418427

419428
/// This struct represents a field of an ADT. If the ADT is an enum, this

crates/hir/src/hir_def/params.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ impl FuncParamName {
133133
pub fn is_self(&self) -> bool {
134134
self.ident() == Some(kw::SELF)
135135
}
136+
137+
pub fn pretty_print(&self, db: &dyn HirDb) -> String {
138+
match self {
139+
FuncParamName::Ident(name) => name.data(db).to_string(),
140+
FuncParamName::Underscore => "_".to_string(),
141+
}
142+
}
136143
}
137144

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

crates/uitest/fixtures/ty/def/invalid_self_ty.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ source: crates/uitest/tests/ty.rs
33
expression: diags
44
input_file: crates/uitest/fixtures/ty/def/invalid_self_ty.fe
55
---
6-
error[6-0009]: invalid type for `self` argument
6+
error[6-0010]: invalid type for `self` argument
77
┌─ invalid_self_ty.fe:2:18
88
99
2fn foo(self: i32)
1010
│ ^^^ type of `self` must starts with `Self`, but the given type is `i32`
1111

12-
error[6-0009]: invalid type for `self` argument
12+
error[6-0010]: invalid type for `self` argument
1313
┌─ invalid_self_ty.fe:6:18
1414
1515
6fn foo(self: i32) {}
1616
│ ^^^ type of `self` must starts with `Self` or `Option<T>`, but the given type is `i32`
1717

18-
error[6-0009]: invalid type for `self` argument
18+
error[6-0010]: invalid type for `self` argument
1919
┌─ invalid_self_ty.fe:16:22
2020
2121
16fn method1(self: i32) {}
2222
│ ^^^ type of `self` must starts with `Self` or `Option`, but the given type is `i32`
2323

24-
error[6-0009]: invalid type for `self` argument
24+
error[6-0010]: invalid type for `self` argument
2525
┌─ invalid_self_ty.fe:20:22
2626
2727
20fn method2(self: i32) {}

crates/uitest/fixtures/ty/trait_impl/impl_method_arg_mismatch.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ error[6-0005]: trait method argument number mismatch
99
10fn foo<T, U>(self, t: (T, U)) {}
1010
^^^^^^^^^^^^^^^^^ expected 3 arguments here, but 2 given
1111

12-
error[6-0006]: given argument type doesn't match the expected type required by trait
12+
error[6-0007]: given argument type doesn't match the expected type required by trait
1313
┌─ impl_method_arg_mismatch.fe:6:30
1414
1515
6fn foo<T, U>(self, t: T, u: i32) {}
1616
│ ^^^^^^ expected `U` type, but the given type is `i32`
1717

18-
error[6-0006]: given argument type doesn't match the expected type required by trait
18+
error[6-0007]: given argument type doesn't match the expected type required by trait
1919
┌─ impl_method_arg_mismatch.fe:26:15
2020
2121
26fn foo<T>(x: Self<T>) {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pub trait Foo {
2+
fn foo(self, x y: i32, _: u32, z: u32)
3+
}
4+
5+
impl Foo for i32 {
6+
fn foo(self, y: i32, x: u32, _: u32) {}
7+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
source: crates/uitest/tests/ty.rs
3+
expression: diags
4+
input_file: crates/uitest/fixtures/ty/trait_impl/impl_method_label_mismatch.fe
5+
---
6+
error[6-0006]: given argument label doesn't match the expected label required by trait
7+
┌─ impl_method_label_mismatch.fe:6:18
8+
9+
2fn foo(self, x y: i32, _: u32, z: u32)
10+
-------- argument label is defined here
11+
·
12+
6fn foo(self, y: i32, x: u32, _: u32) {}
13+
^^^^^^ expected `x` label, but the given label is `y`
14+
15+
error[6-0006]: given argument label doesn't match the expected label required by trait
16+
┌─ impl_method_label_mismatch.fe:6:26
17+
18+
2fn foo(self, x y: i32, _: u32, z: u32)
19+
------ argument label is defined here
20+
·
21+
6fn foo(self, y: i32, x: u32, _: u32) {}
22+
^^^^^^ expected `_` label, but the given label is `x`
23+
24+
error[6-0006]: given argument label doesn't match the expected label required by trait
25+
┌─ impl_method_label_mismatch.fe:6:34
26+
27+
2fn foo(self, x y: i32, _: u32, z: u32)
28+
------ argument label is defined here
29+
·
30+
6fn foo(self, y: i32, x: u32, _: u32) {}
31+
^^^^^^ expected `z` label, but the given label is `_`
32+
33+

crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ source: crates/uitest/tests/ty.rs
33
expression: diags
44
input_file: crates/uitest/fixtures/ty/trait_impl/impl_method_stricter_bound.fe
55
---
6-
error[6-0008]: impl method has stricter bound than the declared method in the trait
6+
error[6-0009]: impl method has stricter bound than the declared method in the trait
77
┌─ impl_method_stricter_bound.fe:9:8
88
99
9fn foo<T: Bar + Baz, U: Bar>(self, t: T, u: U) {}
1010
^^^ method has stricter bounds than the declared method in the trait: `T: Bar`, `T: Baz`, `U: Bar`
1111

12-
error[6-0008]: impl method has stricter bound than the declared method in the trait
12+
error[6-0009]: impl method has stricter bound than the declared method in the trait
1313
┌─ impl_method_stricter_bound.fe:18:8
1414
1515
18fn foo<U>(self, t: T, u: U)

0 commit comments

Comments
 (0)