Skip to content

Commit 72ce94b

Browse files
asteriteTomAFrench
andauthored
fix!: better error message when cannot infer generic numeric type (#7843)
Co-authored-by: Tom French <[email protected]>
1 parent cafcdcd commit 72ce94b

File tree

11 files changed

+95
-10
lines changed

11 files changed

+95
-10
lines changed

compiler/noirc_frontend/src/hir_def/types.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,13 @@ impl Kind {
263263
match self {
264264
Kind::IntegerOrField => Some(Type::default_int_or_field_type()),
265265
Kind::Integer => Some(Type::default_int_type()),
266-
Kind::Numeric(typ) => Some(*typ.clone()),
266+
Kind::Numeric(_typ) => {
267+
// Even though we have a type here, that type cannot be used as
268+
// the default type of a numeric generic.
269+
// For example, if we have `let N: u32` and we don't know
270+
// what `N` is, we can't assume it's `u32`.
271+
None
272+
}
267273
Kind::Any | Kind::Normal => None,
268274
}
269275
}

compiler/noirc_frontend/src/monomorphization/errors.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub enum MonomorphizationError {
2323
generic_name: String,
2424
item_kind: &'static str,
2525
item_name: String,
26+
is_numeric: bool,
2627
},
2728
InternalError {
2829
message: &'static str,
@@ -96,10 +97,12 @@ impl From<MonomorphizationError> for CustomDiagnostic {
9697
generic_name,
9798
item_kind,
9899
item_name,
100+
is_numeric,
99101
} => {
100102
let message = "Type annotation needed".into();
103+
let type_or_value = if *is_numeric { "value" } else { "type" };
101104
let secondary = format!(
102-
"Could not determine the type of the generic argument `{generic_name}` declared on the {item_kind} `{item_name}`"
105+
"Could not determine the {type_or_value} of the generic argument `{generic_name}` declared on the {item_kind} `{item_name}`",
103106
);
104107
return CustomDiagnostic::simple_error(message, secondary, *location);
105108
}

compiler/noirc_frontend/src/monomorphization/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1387,11 +1387,13 @@ impl<'interner> Monomorphizer<'interner> {
13871387
for generic in &meta.direct_generics {
13881388
if generic.type_var.id() == id {
13891389
let item_name = self.interner.definition_name(ident.id).to_string();
1390+
let is_numeric = matches!(generic.type_var.kind(), Kind::Numeric(..));
13901391
return Err(MonomorphizationError::NoDefaultTypeInItem {
13911392
location,
13921393
generic_name: generic.name.to_string(),
13931394
item_kind: "function",
13941395
item_name,
1396+
is_numeric,
13951397
});
13961398
}
13971399
}
@@ -1403,11 +1405,13 @@ impl<'interner> Monomorphizer<'interner> {
14031405
let typ = typ.borrow();
14041406
let item_name = typ.name.to_string();
14051407
let item_kind = if typ.is_struct() { "struct" } else { "enum" };
1408+
let is_numeric = matches!(generic.type_var.kind(), Kind::Numeric(..));
14061409
return Err(MonomorphizationError::NoDefaultTypeInItem {
14071410
location,
14081411
generic_name: generic.name.to_string(),
14091412
item_kind,
14101413
item_name,
1414+
is_numeric,
14111415
});
14121416
}
14131417
}
@@ -1430,11 +1434,13 @@ impl<'interner> Monomorphizer<'interner> {
14301434
let def = def.borrow();
14311435
for generic in &def.generics {
14321436
if generic.type_var.id() == id {
1437+
let is_numeric = matches!(generic.type_var.kind(), Kind::Numeric(..));
14331438
return Err(MonomorphizationError::NoDefaultTypeInItem {
14341439
location,
14351440
generic_name: generic.name.to_string(),
14361441
item_kind: "enum",
14371442
item_name: def.name.to_string(),
1443+
is_numeric,
14381444
});
14391445
}
14401446
}
@@ -1459,7 +1465,7 @@ impl<'interner> Monomorphizer<'interner> {
14591465
| HirType::Error
14601466
| HirType::Quoted(_) => Ok(()),
14611467
HirType::Constant(_value, kind) => {
1462-
if kind.is_error() || kind.default_type().is_none() {
1468+
if kind.is_error() {
14631469
Err(MonomorphizationError::UnknownConstant { location })
14641470
} else {
14651471
Ok(())
@@ -2479,11 +2485,13 @@ fn check_struct_generic_type(
24792485

24802486
let def = def.borrow();
24812487
if let Some(generic) = def.generics.get(index) {
2488+
let is_numeric = matches!(generic.type_var.kind(), Kind::Numeric(..));
24822489
return Err(MonomorphizationError::NoDefaultTypeInItem {
24832490
location,
24842491
generic_name: generic.name.to_string(),
24852492
item_kind: "struct",
24862493
item_name: def.name.to_string(),
2494+
is_numeric,
24872495
});
24882496
}
24892497

compiler/noirc_frontend/src/tests.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4702,3 +4702,31 @@ fn only_one_private_error_when_name_in_types_and_values_namespace_collides() {
47024702
";
47034703
check_errors!(src);
47044704
}
4705+
4706+
#[named]
4707+
#[test]
4708+
fn cannot_determine_type_of_generic_argument_in_function_call_when_it_is_a_numeric_generic() {
4709+
let src = r#"
4710+
struct Foo<let N: u32> {
4711+
array: [Field; N],
4712+
}
4713+
4714+
impl<let N: u32> Foo<N> {
4715+
fn new() -> Self {
4716+
Self { array: [0; N] }
4717+
}
4718+
}
4719+
4720+
fn foo<let N: u32>() -> Foo<N> {
4721+
Foo::new()
4722+
}
4723+
4724+
fn main() {
4725+
let _ = foo();
4726+
^^^ Type annotation needed
4727+
~~~ Could not determine the value of the generic argument `N` declared on the function `foo`
4728+
}
4729+
"#;
4730+
let features = vec![UnstableFeature::Enums];
4731+
check_monomorphization_error_using_features!(src, &features);
4732+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
[package]
3+
name = "noirc_frontend_tests_cannot_determine_type_of_generic_argument_in_function_call_when_it_is_a_numeric_generic"
4+
type = "bin"
5+
authors = [""]
6+
7+
[dependencies]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
struct Foo<let N: u32> {
3+
array: [Field; N],
4+
}
5+
6+
impl<let N: u32> Foo<N> {
7+
fn new() -> Self {
8+
Self { array: [0; N] }
9+
}
10+
}
11+
12+
fn foo<let N: u32>() -> Foo<N> {
13+
Foo::new()
14+
}
15+
16+
fn main() {
17+
let _ = foo();
18+
}
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7627233576545093977

test_programs/noir_test_success/ski_calculus/src/main.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ impl<let N: u32> From<Node> for ShowState<N> {
115115
}
116116

117117
impl<let N: u32> ShowState<N> {
118-
pub fn step<let M: u32>(&mut self) -> Option<Id> {
118+
pub fn step(&mut self) -> Option<Id> {
119119
if self.done {
120120
Option::none()
121121
} else {

tooling/lsp/src/requests/inlay_hint.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,10 +525,11 @@ fn push_type_parts(typ: &Type, parts: &mut Vec<InlayHintLabelPart>, files: &File
525525
}
526526
Type::TypeVariable(binding) => match &*binding.borrow() {
527527
TypeBinding::Unbound(_, kind) => match kind {
528-
Kind::Any | Kind::Normal => push_type_variable_parts(binding, parts, files),
528+
Kind::Any | Kind::Normal | Kind::Numeric(..) => {
529+
push_type_variable_parts(binding, parts, files);
530+
}
529531
Kind::Integer => push_type_parts(&Type::default_int_type(), parts, files),
530532
Kind::IntegerOrField => parts.push(string_part("Field")),
531-
Kind::Numeric(typ) => push_type_parts(typ, parts, files),
532533
},
533534
_ => {
534535
push_type_variable_parts(binding, parts, files);

tooling/nargo_cli/tests/snapshots/compile_failure/cannot_deduce_numeric_generic/execute__tests__stderr.snap

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)