@@ -44,12 +44,13 @@ fn validate_implemented_methods<T: AnnotationMap>(
44
44
. flat_map ( |it| context. index . find_pou ( it. get_qualified_name ( ) ) ) ;
45
45
//XXX(ghha) should this not be combinations instead of tuple_windows?
46
46
for ( method1, method2) in methods. tuple_windows ( ) {
47
- let diagnostics = validate_method_signature ( context. index , method1, method2) ;
47
+ let diagnostics = validate_method_signature ( context. index , method1, method2, & pou . name_location ) ;
48
48
if !diagnostics. is_empty ( ) {
49
49
validator. push_diagnostic (
50
50
Diagnostic :: new ( format ! (
51
- "Method `{}` is defined with different signatures in interfaces `{}` and `{}`" ,
51
+ "Method `{}` in `{}` is declared with conflicting signatures in `{}` and `{}`" ,
52
52
method_name,
53
+ pou. name,
53
54
method1. get_parent_pou_name( ) . unwrap( ) ,
54
55
method2. get_parent_pou_name( ) . unwrap( )
55
56
) )
@@ -76,10 +77,11 @@ fn validate_implemented_methods<T: AnnotationMap>(
76
77
. filter ( |it| it. is_concrete ( ) )
77
78
. map ( |it| context. index . find_pou ( it. get_qualified_name ( ) ) . unwrap ( ) )
78
79
. next ( ) ;
79
- // Validate that each concrete method that has an abstract counterpart has the same signature
80
+ // Validate that each concrete method which has an abstract counterpart has the same signature
80
81
if let Some ( method_impl) = concrete {
81
82
abstracts. for_each ( |( _, method_ref) | {
82
- let diagnostics = validate_method_signature ( context. index , method_ref, method_impl) ;
83
+ let diagnostics =
84
+ validate_method_signature ( context. index , method_ref, method_impl, & pou. name_location ) ;
83
85
for diagnostic in diagnostics {
84
86
validator. push_diagnostic ( diagnostic) ;
85
87
}
@@ -121,7 +123,8 @@ fn validate_method<T: AnnotationMap>(
121
123
. flat_map ( |it| context. index . find_pou ( it. get_qualified_name ( ) ) )
122
124
. collect :: < Vec < _ > > ( ) ;
123
125
interface_methods. iter ( ) . for_each ( |method_ref| {
124
- let diagnostics = validate_method_signature ( context. index , method_ref, method_impl) ;
126
+ let diagnostics =
127
+ validate_method_signature ( context. index , method_ref, method_impl, & pou. name_location ) ;
125
128
for diagnostic in diagnostics {
126
129
validator. push_diagnostic ( diagnostic) ;
127
130
}
@@ -284,6 +287,7 @@ pub fn validate_action_container(validator: &mut Validator, implementation: &Imp
284
287
pub ( super ) mod signature_validation {
285
288
use itertools:: Itertools ;
286
289
use plc_diagnostics:: diagnostics:: Diagnostic ;
290
+ use plc_source:: source_location:: SourceLocation ;
287
291
288
292
use crate :: {
289
293
index:: { Index , PouIndexEntry } ,
@@ -294,8 +298,9 @@ pub(super) mod signature_validation {
294
298
index : & Index ,
295
299
method_ref : & PouIndexEntry ,
296
300
method_impl : & PouIndexEntry ,
301
+ primary_location : & SourceLocation ,
297
302
) -> Vec < Diagnostic > {
298
- let ctxt = Context :: new ( index, method_ref, method_impl) ;
303
+ let ctxt = Context :: new ( index, method_ref, method_impl, primary_location ) ;
299
304
let mut validator = SignatureValidator :: new ( & ctxt) ;
300
305
validator. validate ( ) ;
301
306
validator. diagnostics
@@ -305,15 +310,17 @@ pub(super) mod signature_validation {
305
310
index : & ' idx Index ,
306
311
method_ref : & ' idx PouIndexEntry ,
307
312
method_impl : & ' idx PouIndexEntry ,
313
+ primary_location : & ' idx SourceLocation ,
308
314
}
309
315
310
316
impl < ' idx > Context < ' idx > {
311
317
fn new (
312
318
index : & ' idx Index ,
313
319
method_ref : & ' idx PouIndexEntry ,
314
320
method_impl : & ' idx PouIndexEntry ,
321
+ primary_location : & ' idx SourceLocation ,
315
322
) -> Self {
316
- Self { index, method_ref, method_impl }
323
+ Self { index, method_ref, method_impl, primary_location }
317
324
}
318
325
319
326
/// Returns a tuple of the return [DataType]s of the method reference and the method implementation
@@ -350,9 +357,12 @@ pub(super) mod signature_validation {
350
357
let ( return_type_ref, return_type_impl) = self . context . get_return_types ( ) ;
351
358
if let Some ( sub_diagnostics) = self . validate_types ( return_type_impl, return_type_ref) {
352
359
self . diagnostics . push (
353
- Diagnostic :: new ( "Return types do not match:" )
354
- . with_error_code ( "E112" )
355
- . with_sub_diagnostics ( sub_diagnostics) ,
360
+ Diagnostic :: new (
361
+ "Derived methods with conflicting signatures, return types do not match:" ,
362
+ )
363
+ . with_location ( self . context . primary_location )
364
+ . with_error_code ( "E112" )
365
+ . with_sub_diagnostics ( sub_diagnostics) ,
356
366
) ;
357
367
}
358
368
}
@@ -364,7 +374,7 @@ pub(super) mod signature_validation {
364
374
let method_name = context. method_ref . get_flat_reference_name ( ) ;
365
375
let parameters_ref = context. index . get_declared_parameters ( method_ref. get_name ( ) ) ;
366
376
let parameters_impl = context. index . get_declared_parameters ( method_impl. get_name ( ) ) ;
367
-
377
+ let mut diagnostics = vec ! [ ] ;
368
378
// Conditionally skip the first parameter if the return type is aggregate.
369
379
// Return types have already been validated and we don't want to show errors
370
380
// for internally modified code.
@@ -379,14 +389,14 @@ pub(super) mod signature_validation {
379
389
itertools:: EitherOrBoth :: Both ( parameter_ref, parameter_impl) => {
380
390
// Name
381
391
if parameter_impl. get_name ( ) != parameter_ref. get_name ( ) {
382
- self . diagnostics . push (
392
+ diagnostics. push (
383
393
Diagnostic :: new ( format ! (
384
394
"Expected parameter `{}` but got `{}`" ,
385
395
parameter_ref. get_name( ) ,
386
396
parameter_impl. get_name( )
387
397
) )
388
- . with_error_code ( "E112 " )
389
- . with_location ( & parameter_ref. source_location )
398
+ . with_error_code ( "E118 " )
399
+ . with_secondary_location ( & parameter_ref. source_location )
390
400
. with_secondary_location ( & parameter_impl. source_location ) ,
391
401
) ;
392
402
}
@@ -400,63 +410,71 @@ pub(super) mod signature_validation {
400
410
. get_effective_type_or_void_by_name ( parameter_ref. get_type_name ( ) ) ;
401
411
402
412
if let Some ( sub_diagnostics) = self . validate_types ( impl_ty, ref_ty) {
403
- self . diagnostics . push (
413
+ diagnostics. push (
404
414
Diagnostic :: new ( format ! (
405
- "Parameter `{}` has different types in declaration and implemenation :" ,
415
+ "Parameter `{}` has conflicting type declarations :" ,
406
416
parameter_ref. get_name( ) ,
407
417
) )
408
- . with_error_code ( "E112 " )
418
+ . with_error_code ( "E118 " )
409
419
. with_sub_diagnostics ( sub_diagnostics)
410
- . with_location ( method_impl)
420
+ . with_secondary_location ( method_impl)
411
421
. with_secondary_location ( & parameter_ref. source_location )
412
422
) ;
413
423
}
414
424
415
425
// Declaration Type (VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT)
416
426
if parameter_impl. get_declaration_type ( ) != parameter_ref. get_declaration_type ( ) {
417
- self . diagnostics . push (
427
+ diagnostics. push (
418
428
Diagnostic :: new ( format ! (
419
429
"Expected parameter `{}` to have `{}` as its declaration type but got `{}`" ,
420
430
parameter_impl. get_name( ) ,
421
431
parameter_ref. get_declaration_type( ) . get_inner( ) ,
422
432
parameter_impl. get_declaration_type( ) . get_inner( ) ,
423
433
) )
424
- . with_error_code ( "E112 " )
425
- . with_location ( method_impl)
434
+ . with_error_code ( "E118 " )
435
+ . with_secondary_location ( method_impl)
426
436
. with_secondary_location ( & parameter_ref. source_location ) ,
427
437
) ;
428
438
}
429
439
}
430
440
itertools:: EitherOrBoth :: Left ( parameter_ref) => {
431
- self . diagnostics . push (
441
+ diagnostics. push (
432
442
Diagnostic :: new ( format ! (
433
443
"Parameter `{} : {}` missing in method `{}`" ,
434
444
parameter_ref. get_name( ) ,
435
445
parameter_ref. get_type_name( ) ,
436
446
method_name,
437
447
) )
438
- . with_error_code ( "E112 " )
439
- . with_location ( method_impl)
448
+ . with_error_code ( "E118 " )
449
+ . with_secondary_location ( method_impl)
440
450
. with_secondary_location ( & parameter_ref. source_location ) ,
441
451
) ;
442
452
}
443
453
// Exceeding parameters in the POU, which we did not catch in the for loop above because we were only
444
454
// iterating over the interface parameters; anyhow any exceeding parameter is considered an error because
445
455
// the function signature no longer holds
446
456
itertools:: EitherOrBoth :: Right ( parameter_impl) => {
447
- self . diagnostics . push (
457
+ diagnostics. push (
448
458
Diagnostic :: new ( format ! (
449
459
"`{}` has more parameters than the method defined in `{}`" ,
450
460
method_name,
451
461
method_ref. get_parent_pou_name( ) . unwrap( ) ,
452
462
) )
453
- . with_error_code ( "E112 " )
454
- . with_location ( & parameter_impl. source_location )
463
+ . with_error_code ( "E118 " )
464
+ . with_secondary_location ( & parameter_impl. source_location )
455
465
. with_secondary_location ( method_ref) ,
456
466
) ;
457
467
}
458
468
}
459
- } )
469
+ } ) ;
470
+ if !diagnostics. is_empty ( ) {
471
+ self . diagnostics . push (
472
+ Diagnostic :: new ( "Derived methods with conflicting signatures, parameters do not match:" )
473
+ . with_error_code ( "E112" )
474
+ . with_location ( self . context . primary_location )
475
+ . with_sub_diagnostics ( diagnostics) ,
476
+ ) ;
477
+ }
460
478
}
461
479
462
480
fn validate_types ( & self , left : & DataType , right : & DataType ) -> Option < Vec < Diagnostic > > {
@@ -516,12 +534,12 @@ pub(super) mod signature_validation {
516
534
517
535
fn create_diagnostic ( & self , left : & str , right : & str ) -> Diagnostic {
518
536
Diagnostic :: new ( format ! (
519
- "Type `{right}` declared in `{}` but `{}` implemented type `{left}`" ,
537
+ "Type `{right}` declared in `{}` but `{}` declared type `{left}`" ,
520
538
self . context. method_ref. get_name( ) ,
521
539
self . context. method_impl. get_name( )
522
540
) )
523
- . with_error_code ( "E112 " )
524
- . with_location ( self . context . method_impl )
541
+ . with_error_code ( "E118 " )
542
+ . with_secondary_location ( self . context . method_impl )
525
543
. with_secondary_location ( self . context . method_ref )
526
544
}
527
545
@@ -552,8 +570,8 @@ pub(super) mod signature_validation {
552
570
"Expected array of type `{}` but got `{}`" ,
553
571
right_name, left_name
554
572
) )
555
- . with_error_code ( "E112 " )
556
- . with_location ( method_impl)
573
+ . with_error_code ( "E118 " )
574
+ . with_secondary_location ( method_impl)
557
575
. with_secondary_location ( method_ref) ,
558
576
)
559
577
} ;
@@ -580,7 +598,7 @@ pub(super) mod signature_validation {
580
598
"Array range declared as `[{}..{}]` but implemented as `[{}..{}]`" ,
581
599
r_range. start, r_range. end, l_range. start, l_range. end
582
600
) )
583
- . with_error_code ( "E112 " )
601
+ . with_error_code ( "E118 " )
584
602
. with_secondary_location ( left. location . clone ( ) )
585
603
. with_secondary_location ( right. location . clone ( ) ) ,
586
604
) ,
@@ -597,8 +615,8 @@ pub(super) mod signature_validation {
597
615
if l_dims. len( ) == 1 { "" } else { "s" } ,
598
616
r_dims. len( )
599
617
) )
600
- . with_error_code ( "E112 " )
601
- . with_location ( right. location . clone ( ) )
618
+ . with_error_code ( "E118 " )
619
+ . with_secondary_location ( right. location . clone ( ) )
602
620
. with_secondary_location ( context. method_impl )
603
621
. with_secondary_location ( left. location . clone ( ) )
604
622
. with_secondary_location ( context. method_ref ) ,
@@ -627,8 +645,8 @@ pub(super) mod signature_validation {
627
645
"Expected string of length `{}` but got string of length `{}`" ,
628
646
right_length, left_length
629
647
) )
630
- . with_error_code ( "E112 " )
631
- . with_location ( method_impl)
648
+ . with_error_code ( "E118 " )
649
+ . with_secondary_location ( method_impl)
632
650
. with_secondary_location ( method_ref) ,
633
651
) ;
634
652
} ) ;
0 commit comments