Skip to content

Commit 709ecdd

Browse files
committed
generic param conflict check
1 parent 94b5cd9 commit 709ecdd

8 files changed

Lines changed: 102 additions & 66 deletions

File tree

crates/hir-analysis/src/diagnostics.rs

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -559,35 +559,21 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> {
559559
.unwrap()
560560
.data(db);
561561

562-
let mut spans = idxs
562+
let spans = idxs
563563
.iter()
564564
.map(|i| parent.field_name_span(*i as usize).resolve(db));
565565

566566
let kind = parent.kind_name();
567567
let message = if let Some(name) = parent.name(db) {
568568
format!("duplicate field name in {kind} `{name}`")
569569
} else {
570-
"duplicate field name in {kind} definition".into()
570+
format!("duplicate field name in {kind} definition")
571571
};
572572

573573
CompleteDiagnostic {
574574
severity: Severity::Error,
575575
message,
576-
sub_diagnostics: {
577-
let mut subs = vec![SubDiagnostic::new(
578-
LabelStyle::Primary,
579-
format!("`{name}` is defined here"),
580-
spans.next().unwrap(),
581-
)];
582-
subs.extend(spans.map(|span| {
583-
SubDiagnostic::new(
584-
LabelStyle::Secondary,
585-
format! {"`{name}` is redefined here"},
586-
span,
587-
)
588-
}));
589-
subs
590-
},
576+
sub_diagnostics: duplicate_name_subdiags(name, spans),
591577
notes: vec![],
592578
error_code,
593579
}
@@ -604,7 +590,7 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> {
604590
.name
605591
.unwrap()
606592
.data(db);
607-
let mut spans = idxs.iter().map(|i| {
593+
let spans = idxs.iter().map(|i| {
608594
enum_
609595
.lazy_span()
610596
.variants()
@@ -614,21 +600,35 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> {
614600
CompleteDiagnostic {
615601
severity: Severity::Error,
616602
message,
617-
sub_diagnostics: {
618-
let mut subs = vec![SubDiagnostic::new(
619-
LabelStyle::Primary,
620-
format!("`{name}` is defined here"),
621-
spans.next().unwrap(),
622-
)];
623-
subs.extend(spans.map(|span| {
624-
SubDiagnostic::new(
625-
LabelStyle::Secondary,
626-
format! {"`{name}` is redefined here"},
627-
span,
628-
)
629-
}));
630-
subs
631-
},
603+
sub_diagnostics: duplicate_name_subdiags(name, spans),
604+
notes: vec![],
605+
error_code,
606+
}
607+
}
608+
609+
Self::DuplicateGenericParamName(adt, idxs) => {
610+
let message = if let Some(name) = adt.name(db) {
611+
format!(
612+
"duplicate generic parameter name in {} `{}`",
613+
adt.kind_name(),
614+
name.data(db)
615+
)
616+
} else {
617+
format!(
618+
"duplicate generic parameter name in {} definition",
619+
adt.kind_name()
620+
)
621+
};
622+
623+
let gen = adt.generic_owner().unwrap();
624+
let name = gen.params(db).data(db)[0].name().unwrap().data(db);
625+
let spans = idxs
626+
.iter()
627+
.map(|i| gen.params_span().param(*i as usize).resolve(db));
628+
CompleteDiagnostic {
629+
severity: Severity::Error,
630+
message,
631+
sub_diagnostics: duplicate_name_subdiags(name, spans),
632632
notes: vec![],
633633
error_code,
634634
}
@@ -736,6 +736,26 @@ impl<'db> DiagnosticVoucher<'db> for TyLowerDiag<'db> {
736736
}
737737
}
738738

739+
fn duplicate_name_subdiags<I>(name: &str, spans: I) -> Vec<SubDiagnostic>
740+
where
741+
I: Iterator<Item = Option<Span>>,
742+
{
743+
let mut spans = spans;
744+
let mut subs = vec![SubDiagnostic::new(
745+
LabelStyle::Primary,
746+
format!("`{}` is defined here", name),
747+
spans.next().unwrap(),
748+
)];
749+
subs.extend(spans.map(|span| {
750+
SubDiagnostic::new(
751+
LabelStyle::Secondary,
752+
format!("`{}` is redefined here", name),
753+
span,
754+
)
755+
}));
756+
subs
757+
}
758+
739759
impl<'db> DiagnosticVoucher<'db> for BodyDiag<'db> {
740760
fn to_complete(&self, db: &'db dyn SpannedHirAnalysisDb) -> CompleteDiagnostic {
741761
let error_code = GlobalErrorCode::new(DiagnosticPass::TyCheck, self.local_code());

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub struct AdtDef<'db> {
8484
}
8585

8686
impl<'db> AdtDef<'db> {
87-
pub(crate) fn name(self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> {
87+
pub(crate) fn name(self, db: &'db dyn HirAnalysisDb) -> Option<IdentId<'db>> {
8888
self.adt_ref(db).name(db)
8989
}
9090

@@ -234,14 +234,13 @@ impl<'db> AdtRef<'db> {
234234
}
235235
}
236236

237-
pub fn name(self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> {
237+
pub fn name(self, db: &'db dyn HirAnalysisDb) -> Option<IdentId<'db>> {
238238
match self {
239239
AdtRef::Enum(e) => e.name(db),
240240
AdtRef::Struct(s) => s.name(db),
241241
AdtRef::Contract(c) => c.name(db),
242242
}
243243
.to_opt()
244-
.unwrap_or_else(|| IdentId::new(db, "<unknown>".to_string()))
245244
}
246245

247246
pub fn kind_name(self) -> &'static str {

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub fn analyze_adt<'db>(
7070
db: &'db dyn HirAnalysisDb,
7171
adt_ref: AdtRef<'db>,
7272
) -> Vec<TyDiagCollection<'db>> {
73-
let dupes = match adt_ref {
73+
let mut dupes = match adt_ref {
7474
AdtRef::Struct(x) => check_duplicate_field_names(db, FieldParent::Struct(x)),
7575
AdtRef::Contract(x) => check_duplicate_field_names(db, FieldParent::Contract(x)),
7676
AdtRef::Enum(enum_) => {
@@ -88,6 +88,20 @@ pub fn analyze_adt<'db>(
8888
}
8989
};
9090

91+
if let Some(go) = adt_ref.generic_owner() {
92+
let mut dupe_check = FxHashMap::<IdentId<'db>, SmallVec<[u16; 4]>>::default();
93+
94+
for (i, param) in go.params(db).data(db).iter().enumerate() {
95+
if let Some(name) = param.name().to_opt() {
96+
dupe_check.entry(name).or_default().push(i as u16);
97+
}
98+
}
99+
100+
dupes.extend(dupe_check.into_iter().filter_map(|(_name, idxs)| {
101+
(idxs.len() > 1).then_some(TyLowerDiag::DuplicateGenericParamName(adt_ref, idxs).into())
102+
}));
103+
}
104+
91105
let analyzer = DefAnalyzer::for_adt(db, adt_ref);
92106
let mut diags = analyzer.analyze();
93107
diags.extend(dupes);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{
2+
adt_def::AdtRef,
23
def_analysis::AdtCycleMember,
34
func_def::FuncDef,
45
trait_def::{TraitDef, TraitInstId},
@@ -103,6 +104,8 @@ pub enum TyLowerDiag<'db> {
103104
},
104105
DuplicateFieldName(FieldParent<'db>, SmallVec<[u16; 4]>),
105106
DuplicateVariantName(Enum<'db>, SmallVec<[u16; 4]>),
107+
DuplicateGenericParamName(AdtRef<'db>, SmallVec<[u16; 4]>),
108+
106109
InvalidConstParamTy(DynLazySpan<'db>),
107110
RecursiveConstParamTy(DynLazySpan<'db>),
108111

@@ -149,6 +152,7 @@ impl TyLowerDiag<'_> {
149152
Self::TooManyGenericArgs { .. } => 16,
150153
Self::DuplicateFieldName(..) => 17,
151154
Self::DuplicateVariantName(..) => 18,
155+
Self::DuplicateGenericParamName(..) => 19,
152156
}
153157
}
154158
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,10 @@ impl<'db> TyBase<'db> {
987987
}
988988
.to_string(),
989989

990-
Self::Adt(adt) => adt.name(db).data(db).to_string(),
990+
Self::Adt(adt) => adt
991+
.name(db)
992+
.map(|i| i.data(db).to_string())
993+
.unwrap_or_else(|| "<unknown>".to_string()),
991994

992995
Self::Func(func) => format!("fn {}", func.name(db).data(db)),
993996
}

crates/uitest/fixtures/name_resolution/conflict_generics.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ source: crates/uitest/tests/name_resolution.rs
33
expression: diags
44
input_file: fixtures/name_resolution/conflict_generics.fe
55
---
6-
error[2-0001]: `T` conflicts with other definitions
7-
┌─ conflict_generics.fe:1:16
8-
9-
1pub struct MyS<T, U, T> {
10-
^ - `T` is redefined here
11-
│ │
12-
`T` is defined here
13-
146
error[2-0004]: `T` is ambiguous
157
┌─ conflict_generics.fe:2:8
168
@@ -20,3 +12,11 @@ error[2-0004]: `T` is ambiguous
2012
candidate 1
2113
2x: T,
2214
^ `T` is ambiguous
15+
16+
error[3-0019]: duplicate generic parameter name in struct `MyS`
17+
┌─ conflict_generics.fe:1:16
18+
19+
1pub struct MyS<T, U, T> {
20+
^ - `T` is redefined here
21+
│ │
22+
`T` is defined here
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
---
22
source: crates/uitest/tests/ty.rs
33
expression: diags
4-
input_file: crates/uitest/fixtures/ty/def/duplicated_arg_name.fe
4+
input_file: fixtures/ty/def/duplicated_arg_name.fe
55
---
6-
error[3-0008]: duplicated argument name in function definition is not allowed
6+
error[3-0008]: duplicate argument name in function definition
77
┌─ duplicated_arg_name.fe:1:22
88
99
1 │ pub fn foo(x: i32, y x: u64) {}
10-
- ^ duplicated argument name `x`
10+
- ^ duplicate argument name `x`
1111
│ │
1212
conflict with this argument name
1313

14-
error[3-0008]: duplicated argument name in function definition is not allowed
14+
error[3-0008]: duplicate argument name in function definition
1515
┌─ duplicated_arg_name.fe:4:24
1616
1717
4 │ fn foo(x y: i32, z y: i32) {}
18-
- ^ duplicated argument name `y`
18+
- ^ duplicate argument name `y`
1919
│ │
2020
conflict with this argument name
2121

22-
error[3-0008]: duplicated argument name in function definition is not allowed
22+
error[3-0008]: duplicate argument name in function definition
2323
┌─ duplicated_arg_name.fe:8:24
2424
2525
8 │ fn foo(x y: i32, z y: i32) {}
26-
- ^ duplicated argument name `y`
26+
- ^ duplicate argument name `y`
2727
│ │
2828
conflict with this argument name
29-
30-

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
---
22
source: crates/uitest/tests/ty.rs
33
expression: diags
4-
input_file: crates/uitest/fixtures/ty/def/not_star_kind.fe
4+
input_file: fixtures/ty/def/not_star_kind.fe
55
---
6-
error[2-0001]: `foo` conflicts with other definitions
7-
┌─ not_star_kind.fe:28:4
8-
9-
28fn foo(gen: Gen) {}
10-
^^^ `foo` is defined here
11-
29
12-
30fn foo(gen: Gen<i32>) -> Gen {}
13-
│ --- `foo` is redefined here
14-
156
error[2-0002]: `T` is not found
167
┌─ not_star_kind.fe:21:10
178
@@ -78,4 +69,11 @@ error[3-0000]: expected `*` kind in this context
7869
30 │ fn foo(gen: Gen<i32>) -> Gen {}
7970
│ ^^^ expected `*` kind here
8071

81-
72+
error[3-0100]: conflicting definitions of `foo`
73+
┌─ not_star_kind.fe:28:4
74+
75+
28 │ fn foo(gen: Gen) {}
76+
│ ^^^ `foo` is defined here
77+
29 │
78+
30 │ fn foo(gen: Gen<i32>) -> Gen {}
79+
│ --- `foo` is redefined here

0 commit comments

Comments
 (0)