Skip to content

Commit 251c749

Browse files
jfecherTomAFrench
authored andcommitted
fix: Error when a type variable is unbound during monomorphization instead of defaulting to Field (#4674)
# Description ## Problem\* Resolves <!-- Link to GitHub Issue --> ## Summary\* Adds an error when encountering an unbound `TypeVariableKind::Normal` instead of defaulting it to a Field. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
1 parent e6323e2 commit 251c749

File tree

17 files changed

+356
-234
lines changed

17 files changed

+356
-234
lines changed

compiler/noirc_driver/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ use noirc_frontend::graph::{CrateId, CrateName};
1616
use noirc_frontend::hir::def_map::{Contract, CrateDefMap};
1717
use noirc_frontend::hir::Context;
1818
use noirc_frontend::macros_api::MacroProcessor;
19-
use noirc_frontend::monomorphization::{monomorphize, monomorphize_debug, MonomorphizationError};
19+
use noirc_frontend::monomorphization::{
20+
errors::MonomorphizationError, monomorphize, monomorphize_debug,
21+
};
2022
use noirc_frontend::node_interner::FuncId;
2123
use noirc_frontend::token::SecondaryAttribute;
2224
use std::path::Path;

compiler/noirc_frontend/src/ast/statement.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl StatementKind {
120120
// Desugar `a <op>= b` to `a = a <op> b`. This relies on the evaluation of `a` having no side effects,
121121
// which is currently enforced by the restricted syntax of LValues.
122122
if operator != Token::Assign {
123-
let lvalue_expr = lvalue.as_expression(span);
123+
let lvalue_expr = lvalue.as_expression();
124124
let error_msg = "Token passed to Statement::assign is not a binary operator";
125125

126126
let infix = crate::InfixExpression {
@@ -425,9 +425,9 @@ pub struct AssignStatement {
425425
#[derive(Debug, PartialEq, Eq, Clone)]
426426
pub enum LValue {
427427
Ident(Ident),
428-
MemberAccess { object: Box<LValue>, field_name: Ident },
429-
Index { array: Box<LValue>, index: Expression },
430-
Dereference(Box<LValue>),
428+
MemberAccess { object: Box<LValue>, field_name: Ident, span: Span },
429+
Index { array: Box<LValue>, index: Expression, span: Span },
430+
Dereference(Box<LValue>, Span),
431431
}
432432

433433
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -484,28 +484,40 @@ impl Recoverable for Pattern {
484484
}
485485

486486
impl LValue {
487-
fn as_expression(&self, span: Span) -> Expression {
487+
fn as_expression(&self) -> Expression {
488488
let kind = match self {
489489
LValue::Ident(ident) => ExpressionKind::Variable(Path::from_ident(ident.clone())),
490-
LValue::MemberAccess { object, field_name } => {
490+
LValue::MemberAccess { object, field_name, span: _ } => {
491491
ExpressionKind::MemberAccess(Box::new(MemberAccessExpression {
492-
lhs: object.as_expression(span),
492+
lhs: object.as_expression(),
493493
rhs: field_name.clone(),
494494
}))
495495
}
496-
LValue::Index { array, index } => ExpressionKind::Index(Box::new(IndexExpression {
497-
collection: array.as_expression(span),
498-
index: index.clone(),
499-
})),
500-
LValue::Dereference(lvalue) => {
496+
LValue::Index { array, index, span: _ } => {
497+
ExpressionKind::Index(Box::new(IndexExpression {
498+
collection: array.as_expression(),
499+
index: index.clone(),
500+
}))
501+
}
502+
LValue::Dereference(lvalue, _span) => {
501503
ExpressionKind::Prefix(Box::new(crate::PrefixExpression {
502504
operator: crate::UnaryOp::Dereference { implicitly_added: false },
503-
rhs: lvalue.as_expression(span),
505+
rhs: lvalue.as_expression(),
504506
}))
505507
}
506508
};
509+
let span = self.span();
507510
Expression::new(kind, span)
508511
}
512+
513+
pub fn span(&self) -> Span {
514+
match self {
515+
LValue::Ident(ident) => ident.span(),
516+
LValue::MemberAccess { span, .. }
517+
| LValue::Index { span, .. }
518+
| LValue::Dereference(_, span) => *span,
519+
}
520+
}
509521
}
510522

511523
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -675,9 +687,11 @@ impl Display for LValue {
675687
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
676688
match self {
677689
LValue::Ident(ident) => ident.fmt(f),
678-
LValue::MemberAccess { object, field_name } => write!(f, "{object}.{field_name}"),
679-
LValue::Index { array, index } => write!(f, "{array}[{index}]"),
680-
LValue::Dereference(lvalue) => write!(f, "*{lvalue}"),
690+
LValue::MemberAccess { object, field_name, span: _ } => {
691+
write!(f, "{object}.{field_name}")
692+
}
693+
LValue::Index { array, index, span: _ } => write!(f, "{array}[{index}]"),
694+
LValue::Dereference(lvalue, _span) => write!(f, "*{lvalue}"),
681695
}
682696
}
683697
}

compiler/noirc_frontend/src/debug/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ impl DebugInstrumenter {
282282
.unwrap_or_else(|| panic!("var lookup failed for var_name={}", &id.0.contents));
283283
build_assign_var_stmt(var_id, id_expr(&ident("__debug_expr", id.span())))
284284
}
285-
ast::LValue::Dereference(_lv) => {
285+
ast::LValue::Dereference(_lv, span) => {
286286
// TODO: this is a dummy statement for now, but we should
287287
// somehow track the derefence and update the pointed to
288288
// variable
@@ -303,16 +303,16 @@ impl DebugInstrumenter {
303303
});
304304
break;
305305
}
306-
ast::LValue::MemberAccess { object, field_name } => {
306+
ast::LValue::MemberAccess { object, field_name, span } => {
307307
cursor = object;
308308
let field_name_id = self.insert_field_name(&field_name.0.contents);
309-
indexes.push(sint_expr(-(field_name_id.0 as i128), expression_span));
309+
indexes.push(sint_expr(-(field_name_id.0 as i128), *span));
310310
}
311-
ast::LValue::Index { index, array } => {
311+
ast::LValue::Index { index, array, span: _ } => {
312312
cursor = array;
313313
indexes.push(index.clone());
314314
}
315-
ast::LValue::Dereference(_ref) => {
315+
ast::LValue::Dereference(_ref, _span) => {
316316
unimplemented![]
317317
}
318318
}

compiler/noirc_frontend/src/hir/resolution/resolver.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,18 +1303,23 @@ impl<'a> Resolver<'a> {
13031303

13041304
HirLValue::Ident(ident.0, Type::Error)
13051305
}
1306-
LValue::MemberAccess { object, field_name } => {
1307-
let object = Box::new(self.resolve_lvalue(*object));
1308-
HirLValue::MemberAccess { object, field_name, field_index: None, typ: Type::Error }
1309-
}
1310-
LValue::Index { array, index } => {
1306+
LValue::MemberAccess { object, field_name, span } => HirLValue::MemberAccess {
1307+
object: Box::new(self.resolve_lvalue(*object)),
1308+
field_name,
1309+
location: Location::new(span, self.file),
1310+
field_index: None,
1311+
typ: Type::Error,
1312+
},
1313+
LValue::Index { array, index, span } => {
13111314
let array = Box::new(self.resolve_lvalue(*array));
13121315
let index = self.resolve_expression(index);
1313-
HirLValue::Index { array, index, typ: Type::Error }
1316+
let location = Location::new(span, self.file);
1317+
HirLValue::Index { array, index, location, typ: Type::Error }
13141318
}
1315-
LValue::Dereference(lvalue) => {
1319+
LValue::Dereference(lvalue, span) => {
13161320
let lvalue = Box::new(self.resolve_lvalue(*lvalue));
1317-
HirLValue::Dereference { lvalue, element_type: Type::Error }
1321+
let location = Location::new(span, self.file);
1322+
HirLValue::Dereference { lvalue, location, element_type: Type::Error }
13181323
}
13191324
}
13201325
}

compiler/noirc_frontend/src/hir/type_check/stmt.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use iter_extended::vecmap;
2-
use noirc_errors::{Location, Span};
2+
use noirc_errors::Span;
33

44
use crate::hir_def::expr::{HirExpression, HirIdent, HirLiteral};
55
use crate::hir_def::stmt::{
@@ -195,41 +195,43 @@ impl<'interner> TypeChecker<'interner> {
195195

196196
(typ.clone(), HirLValue::Ident(ident.clone(), typ), mutable)
197197
}
198-
HirLValue::MemberAccess { object, field_name, .. } => {
198+
HirLValue::MemberAccess { object, field_name, location, .. } => {
199199
let (lhs_type, object, mut mutable) = self.check_lvalue(object, assign_span);
200200
let mut object = Box::new(object);
201-
let span = field_name.span();
202201
let field_name = field_name.clone();
203202

204203
let object_ref = &mut object;
205204
let mutable_ref = &mut mutable;
205+
let location = *location;
206206

207207
let dereference_lhs = move |_: &mut Self, _, element_type| {
208208
// We must create a temporary value first to move out of object_ref before
209209
// we eventually reassign to it.
210210
let id = DefinitionId::dummy_id();
211-
let location = Location::new(span, fm::FileId::dummy());
212211
let ident = HirIdent::non_trait_method(id, location);
213212
let tmp_value = HirLValue::Ident(ident, Type::Error);
214213

215214
let lvalue = std::mem::replace(object_ref, Box::new(tmp_value));
216-
*object_ref = Box::new(HirLValue::Dereference { lvalue, element_type });
215+
*object_ref =
216+
Box::new(HirLValue::Dereference { lvalue, element_type, location });
217217
*mutable_ref = true;
218218
};
219219

220220
let name = &field_name.0.contents;
221221
let (object_type, field_index) = self
222-
.check_field_access(&lhs_type, name, span, Some(dereference_lhs))
222+
.check_field_access(&lhs_type, name, field_name.span(), Some(dereference_lhs))
223223
.unwrap_or((Type::Error, 0));
224224

225225
let field_index = Some(field_index);
226226
let typ = object_type.clone();
227-
let lvalue = HirLValue::MemberAccess { object, field_name, field_index, typ };
227+
let lvalue =
228+
HirLValue::MemberAccess { object, field_name, field_index, typ, location };
228229
(object_type, lvalue, mutable)
229230
}
230-
HirLValue::Index { array, index, .. } => {
231+
HirLValue::Index { array, index, location, .. } => {
231232
let index_type = self.check_expression(index);
232233
let expr_span = self.interner.expr_span(index);
234+
let location = *location;
233235

234236
index_type.unify(
235237
&Type::polymorphic_integer_or_field(self.interner),
@@ -248,7 +250,8 @@ impl<'interner> TypeChecker<'interner> {
248250
// as needed to unwrap any &mut wrappers.
249251
while let Type::MutableReference(element) = lvalue_type.follow_bindings() {
250252
let element_type = element.as_ref().clone();
251-
lvalue = HirLValue::Dereference { lvalue: Box::new(lvalue), element_type };
253+
lvalue =
254+
HirLValue::Dereference { lvalue: Box::new(lvalue), element_type, location };
252255
lvalue_type = *element;
253256
// We know this value to be mutable now since we found an `&mut`
254257
mutable = true;
@@ -275,11 +278,12 @@ impl<'interner> TypeChecker<'interner> {
275278
};
276279

277280
let array = Box::new(lvalue);
278-
(typ.clone(), HirLValue::Index { array, index: *index, typ }, mutable)
281+
(typ.clone(), HirLValue::Index { array, index: *index, typ, location }, mutable)
279282
}
280-
HirLValue::Dereference { lvalue, element_type: _ } => {
283+
HirLValue::Dereference { lvalue, element_type: _, location } => {
281284
let (reference_type, lvalue, _) = self.check_lvalue(lvalue, assign_span);
282285
let lvalue = Box::new(lvalue);
286+
let location = *location;
283287

284288
let element_type = Type::type_variable(self.interner.next_type_variable_id());
285289
let expected_type = Type::MutableReference(Box::new(element_type.clone()));
@@ -291,7 +295,11 @@ impl<'interner> TypeChecker<'interner> {
291295
});
292296

293297
// Dereferences are always mutable since we already type checked against a &mut T
294-
(element_type.clone(), HirLValue::Dereference { lvalue, element_type }, true)
298+
(
299+
element_type.clone(),
300+
HirLValue::Dereference { lvalue, element_type, location },
301+
true,
302+
)
295303
}
296304
}
297305
}

compiler/noirc_frontend/src/hir_def/stmt.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ impl HirPattern {
9999
| HirPattern::Struct(_, _, location) => location.span,
100100
}
101101
}
102+
103+
pub(crate) fn location(&self) -> Location {
104+
match self {
105+
HirPattern::Identifier(ident) => ident.location,
106+
HirPattern::Mutable(_, location)
107+
| HirPattern::Tuple(_, location)
108+
| HirPattern::Struct(_, _, location) => *location,
109+
}
110+
}
102111
}
103112

104113
/// Represents an Ast form that can be assigned to. These
@@ -111,14 +120,17 @@ pub enum HirLValue {
111120
field_name: Ident,
112121
field_index: Option<usize>,
113122
typ: Type,
123+
location: Location,
114124
},
115125
Index {
116126
array: Box<HirLValue>,
117127
index: ExprId,
118128
typ: Type,
129+
location: Location,
119130
},
120131
Dereference {
121132
lvalue: Box<HirLValue>,
122133
element_type: Type,
134+
location: Location,
123135
},
124136
}

compiler/noirc_frontend/src/hir_def/types.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -543,11 +543,11 @@ impl TypeBinding {
543543
pub struct TypeVariableId(pub usize);
544544

545545
impl Type {
546-
pub fn default_int_type() -> Type {
546+
pub fn default_int_or_field_type() -> Type {
547547
Type::FieldElement
548548
}
549549

550-
pub fn default_range_loop_type() -> Type {
550+
pub fn default_int_type() -> Type {
551551
Type::Integer(Signedness::Unsigned, IntegerBitSize::SixtyFour)
552552
}
553553

@@ -787,7 +787,7 @@ impl std::fmt::Display for Type {
787787
Type::TypeVariable(var, TypeVariableKind::Normal) => write!(f, "{}", var.borrow()),
788788
Type::TypeVariable(binding, TypeVariableKind::Integer) => {
789789
if let TypeBinding::Unbound(_) = &*binding.borrow() {
790-
write!(f, "{}", TypeVariableKind::Integer.default_type())
790+
write!(f, "{}", Type::default_int_type())
791791
} else {
792792
write!(f, "{}", binding.borrow())
793793
}
@@ -1706,11 +1706,12 @@ impl BinaryTypeOperator {
17061706
impl TypeVariableKind {
17071707
/// Returns the default type this type variable should be bound to if it is still unbound
17081708
/// during monomorphization.
1709-
pub(crate) fn default_type(&self) -> Type {
1709+
pub(crate) fn default_type(&self) -> Option<Type> {
17101710
match self {
1711-
TypeVariableKind::IntegerOrField | TypeVariableKind::Normal => Type::default_int_type(),
1712-
TypeVariableKind::Integer => Type::default_range_loop_type(),
1713-
TypeVariableKind::Constant(length) => Type::Constant(*length),
1711+
TypeVariableKind::IntegerOrField => Some(Type::default_int_or_field_type()),
1712+
TypeVariableKind::Integer => Some(Type::default_int_type()),
1713+
TypeVariableKind::Constant(length) => Some(Type::Constant(*length)),
1714+
TypeVariableKind::Normal => None,
17141715
}
17151716
}
17161717
}
@@ -1744,12 +1745,12 @@ impl From<&Type> for PrintableType {
17441745
},
17451746
Type::TypeVariable(binding, TypeVariableKind::Integer) => match &*binding.borrow() {
17461747
TypeBinding::Bound(typ) => typ.into(),
1747-
TypeBinding::Unbound(_) => Type::default_range_loop_type().into(),
1748+
TypeBinding::Unbound(_) => Type::default_int_type().into(),
17481749
},
17491750
Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => {
17501751
match &*binding.borrow() {
17511752
TypeBinding::Bound(typ) => typ.into(),
1752-
TypeBinding::Unbound(_) => Type::default_int_type().into(),
1753+
TypeBinding::Unbound(_) => Type::default_int_or_field_type().into(),
17531754
}
17541755
}
17551756
Type::Bool => PrintableType::Boolean,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use thiserror::Error;
2+
3+
use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location};
4+
5+
#[derive(Debug, Error)]
6+
pub enum MonomorphizationError {
7+
#[error("Length of generic array could not be determined.")]
8+
UnknownArrayLength { location: Location },
9+
10+
#[error("Type annotations needed")]
11+
TypeAnnotationsNeeded { location: Location },
12+
}
13+
14+
impl MonomorphizationError {
15+
fn location(&self) -> Location {
16+
match self {
17+
MonomorphizationError::UnknownArrayLength { location }
18+
| MonomorphizationError::TypeAnnotationsNeeded { location } => *location,
19+
}
20+
}
21+
}
22+
23+
impl From<MonomorphizationError> for FileDiagnostic {
24+
fn from(error: MonomorphizationError) -> FileDiagnostic {
25+
let location = error.location();
26+
let call_stack = vec![location];
27+
let diagnostic = error.into_diagnostic();
28+
diagnostic.in_file(location.file).with_call_stack(call_stack)
29+
}
30+
}
31+
32+
impl MonomorphizationError {
33+
fn into_diagnostic(self) -> CustomDiagnostic {
34+
let message = self.to_string();
35+
let location = self.location();
36+
37+
CustomDiagnostic::simple_error(message, String::new(), location.span)
38+
}
39+
}

0 commit comments

Comments
 (0)