@@ -5,7 +5,7 @@ use noirc_errors::Location;
5
5
6
6
use crate :: {
7
7
ast:: {
8
- EnumVariant , Expression , ExpressionKind , FunctionKind , Literal , NoirEnumeration ,
8
+ EnumVariant , Expression , ExpressionKind , FunctionKind , Ident , Literal , NoirEnumeration ,
9
9
StatementKind , UnresolvedType , Visibility ,
10
10
} ,
11
11
elaborator:: path_resolution:: PathResolutionItem ,
@@ -271,7 +271,8 @@ impl Elaborator<'_> {
271
271
272
272
let rows = vecmap ( rules, |( pattern, branch) | {
273
273
self . push_scope ( ) ;
274
- let pattern = self . expression_to_pattern ( pattern, & expected_pattern_type) ;
274
+ let pattern =
275
+ self . expression_to_pattern ( pattern, & expected_pattern_type, & mut Vec :: new ( ) ) ;
275
276
let columns = vec ! [ Column :: new( variable_to_match, pattern) ] ;
276
277
277
278
let guard = None ;
@@ -293,7 +294,12 @@ impl Elaborator<'_> {
293
294
}
294
295
295
296
/// Convert an expression into a Pattern, defining any variables within.
296
- fn expression_to_pattern ( & mut self , expression : Expression , expected_type : & Type ) -> Pattern {
297
+ fn expression_to_pattern (
298
+ & mut self ,
299
+ expression : Expression ,
300
+ expected_type : & Type ,
301
+ variables_defined : & mut Vec < Ident > ,
302
+ ) -> Pattern {
297
303
let expr_location = expression. type_location ( ) ;
298
304
let unify_with_expected_type = |this : & mut Self , actual| {
299
305
this. unify ( actual, expected_type, expr_location. file , || {
@@ -333,13 +339,25 @@ impl Elaborator<'_> {
333
339
Vec :: new ( ) ,
334
340
expected_type,
335
341
location,
342
+ variables_defined,
336
343
) ,
337
344
Err ( _) if path_len == 1 => {
338
345
// Define the variable
339
346
let kind = DefinitionKind :: Local ( None ) ;
340
- // TODO: `allow_shadowing` is false while I'm too lazy to add a check that we
341
- // don't define the same name multiple times in one pattern.
342
- let id = self . add_variable_decl ( last_ident, false , false , true , kind) . id ;
347
+
348
+ if let Some ( existing) =
349
+ variables_defined. iter ( ) . find ( |elem| * elem == & last_ident)
350
+ {
351
+ let error = ResolverError :: VariableAlreadyDefinedInPattern {
352
+ existing : existing. clone ( ) ,
353
+ new_span : last_ident. span ( ) ,
354
+ } ;
355
+ self . push_err ( error, self . file ) ;
356
+ } else {
357
+ variables_defined. push ( last_ident. clone ( ) ) ;
358
+ }
359
+
360
+ let id = self . add_variable_decl ( last_ident, false , true , true , kind) . id ;
343
361
self . interner . push_definition_type ( id, expected_type. clone ( ) ) ;
344
362
Pattern :: Binding ( id)
345
363
}
@@ -352,9 +370,12 @@ impl Elaborator<'_> {
352
370
}
353
371
}
354
372
}
355
- ExpressionKind :: Call ( call) => {
356
- self . expression_to_constructor ( * call. func , call. arguments , expected_type)
357
- }
373
+ ExpressionKind :: Call ( call) => self . expression_to_constructor (
374
+ * call. func ,
375
+ call. arguments ,
376
+ expected_type,
377
+ variables_defined,
378
+ ) ,
358
379
ExpressionKind :: Constructor ( _) => todo ! ( "handle constructors" ) ,
359
380
ExpressionKind :: Tuple ( fields) => {
360
381
let field_types = vecmap ( 0 ..fields. len ( ) , |_| self . interner . next_type_variable ( ) ) ;
@@ -363,21 +384,23 @@ impl Elaborator<'_> {
363
384
364
385
let fields = vecmap ( fields. into_iter ( ) . enumerate ( ) , |( i, field) | {
365
386
let expected = field_types. get ( i) . unwrap_or ( & Type :: Error ) ;
366
- self . expression_to_pattern ( field, expected)
387
+ self . expression_to_pattern ( field, expected, variables_defined )
367
388
} ) ;
368
389
369
390
Pattern :: Constructor ( Constructor :: Tuple ( field_types. clone ( ) ) , fields)
370
391
}
371
392
372
- ExpressionKind :: Parenthesized ( expr) => self . expression_to_pattern ( * expr, expected_type) ,
393
+ ExpressionKind :: Parenthesized ( expr) => {
394
+ self . expression_to_pattern ( * expr, expected_type, variables_defined)
395
+ }
373
396
ExpressionKind :: Interned ( id) => {
374
397
let kind = self . interner . get_expression_kind ( id) ;
375
398
let expr = Expression :: new ( kind. clone ( ) , expression. location ) ;
376
- self . expression_to_pattern ( expr, expected_type)
399
+ self . expression_to_pattern ( expr, expected_type, variables_defined )
377
400
}
378
401
ExpressionKind :: InternedStatement ( id) => {
379
402
if let StatementKind :: Expression ( expr) = self . interner . get_statement_kind ( id) {
380
- self . expression_to_pattern ( expr. clone ( ) , expected_type)
403
+ self . expression_to_pattern ( expr. clone ( ) , expected_type, variables_defined )
381
404
} else {
382
405
panic ! ( "Invalid expr kind {expression}" )
383
406
}
@@ -413,6 +436,7 @@ impl Elaborator<'_> {
413
436
name : Expression ,
414
437
args : Vec < Expression > ,
415
438
expected_type : & Type ,
439
+ variables_defined : & mut Vec < Ident > ,
416
440
) -> Pattern {
417
441
match name. kind {
418
442
ExpressionKind :: Variable ( path) => {
@@ -424,6 +448,7 @@ impl Elaborator<'_> {
424
448
args,
425
449
expected_type,
426
450
location,
451
+ variables_defined,
427
452
) ,
428
453
Err ( error) => {
429
454
self . push_err ( error, location. file ) ;
@@ -433,16 +458,21 @@ impl Elaborator<'_> {
433
458
}
434
459
}
435
460
ExpressionKind :: Parenthesized ( expr) => {
436
- self . expression_to_constructor ( * expr, args, expected_type)
461
+ self . expression_to_constructor ( * expr, args, expected_type, variables_defined )
437
462
}
438
463
ExpressionKind :: Interned ( id) => {
439
464
let kind = self . interner . get_expression_kind ( id) ;
440
465
let expr = Expression :: new ( kind. clone ( ) , name. location ) ;
441
- self . expression_to_constructor ( expr, args, expected_type)
466
+ self . expression_to_constructor ( expr, args, expected_type, variables_defined )
442
467
}
443
468
ExpressionKind :: InternedStatement ( id) => {
444
469
if let StatementKind :: Expression ( expr) = self . interner . get_statement_kind ( id) {
445
- self . expression_to_constructor ( expr. clone ( ) , args, expected_type)
470
+ self . expression_to_constructor (
471
+ expr. clone ( ) ,
472
+ args,
473
+ expected_type,
474
+ variables_defined,
475
+ )
446
476
} else {
447
477
panic ! ( "Invalid expr kind {name}" )
448
478
}
@@ -457,6 +487,7 @@ impl Elaborator<'_> {
457
487
args : Vec < Expression > ,
458
488
expected_type : & Type ,
459
489
location : Location ,
490
+ variables_defined : & mut Vec < Ident > ,
460
491
) -> Pattern {
461
492
let span = location. span ;
462
493
@@ -515,7 +546,7 @@ impl Elaborator<'_> {
515
546
516
547
let args = args. into_iter ( ) . zip ( expected_arg_types) ;
517
548
let args = vecmap ( args, |( arg, expected_arg_type) | {
518
- self . expression_to_pattern ( arg, & expected_arg_type)
549
+ self . expression_to_pattern ( arg, & expected_arg_type, variables_defined )
519
550
} ) ;
520
551
let constructor = Constructor :: Variant ( actual_type, variant_index) ;
521
552
Pattern :: Constructor ( constructor, args)
0 commit comments