Skip to content

Commit f2fd4da

Browse files
committed
Typecheck return value
1 parent 124c59d commit f2fd4da

File tree

13 files changed

+183
-48
lines changed

13 files changed

+183
-48
lines changed

vhdl_lang/src/analysis/assignment.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'a> AnalyzeContext<'a> {
113113
self.analyze_expression_for_target(scope, ttyp, value, diagnostics)?;
114114
if let Some(expr) = after {
115115
let standard = self.standard_package().unwrap();
116-
self.expr_with_ttyp(
116+
self.expr_pos_with_ttyp(
117117
scope,
118118
standard.time(),
119119
&expr.pos,
@@ -136,7 +136,7 @@ impl<'a> AnalyzeContext<'a> {
136136
diagnostics: &mut dyn DiagnosticHandler,
137137
) -> FatalResult {
138138
if let Some(ttyp) = ttyp {
139-
self.expr_with_ttyp(scope, ttyp, &expr.pos, &mut expr.item, diagnostics)?;
139+
self.expr_pos_with_ttyp(scope, ttyp, &expr.pos, &mut expr.item, diagnostics)?;
140140
} else {
141141
self.analyze_expression_pos(scope, &expr.pos, &mut expr.item, diagnostics)?;
142142
}

vhdl_lang/src/analysis/association.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ impl<'a> AnalyzeContext<'a> {
332332
{
333333
match &mut actual.item {
334334
ActualPart::Expression(expr) => {
335-
self.expr_with_ttyp(
335+
self.expr_pos_with_ttyp(
336336
scope,
337337
formal.type_mark(),
338338
&actual.pos,

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#![allow(clippy::unneeded_field_pattern)]
99

1010
use super::named_entity::*;
11+
use super::sequential::SequentialRoot;
1112
use super::*;
1213
use crate::ast::*;
1314
use crate::data::*;
@@ -77,7 +78,12 @@ impl<'a> AnalyzeContext<'a> {
7778
}
7879
let nested = scope.nested();
7980
self.analyze_declarative_part(&nested, decl, diagnostics)?;
80-
self.analyze_sequential_part(&nested, statements, diagnostics)?;
81+
self.analyze_sequential_part(
82+
&nested,
83+
&SequentialRoot::Process,
84+
statements,
85+
diagnostics,
86+
)?;
8187
}
8288
ConcurrentStatement::ForGenerate(ref mut gen) => {
8389
let ForGenerateStatement {

vhdl_lang/src/analysis/declarative.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use super::formal_region::FormalRegion;
88
use super::formal_region::RecordRegion;
99
use super::named_entity::*;
1010
use super::names::*;
11+
use super::sequential::SequentialRoot;
1112
use super::*;
1213
use crate::ast;
1314
use crate::ast::*;
@@ -251,7 +252,7 @@ impl<'a> AnalyzeContext<'a> {
251252

252253
if let Some(ref mut expr) = object_decl.expression {
253254
if let Ok(ref subtype) = subtype {
254-
self.expr_with_ttyp(
255+
self.expr_pos_with_ttyp(
255256
scope,
256257
subtype.type_mark(),
257258
&expr.pos,
@@ -358,7 +359,7 @@ impl<'a> AnalyzeContext<'a> {
358359
Ok(NamedEntities::Single(ent)) => {
359360
ident.set_unique_reference(ent);
360361
if let AnyEntKind::Attribute(typ) = ent.actual_kind() {
361-
self.expr_with_ttyp(
362+
self.expr_pos_with_ttyp(
362363
scope,
363364
*typ,
364365
&expr.pos,
@@ -443,22 +444,38 @@ impl<'a> AnalyzeContext<'a> {
443444
let subpgm_region = Scope::new(subpgm_region.into_region());
444445

445446
// Overwrite subprogram definition with full signature
446-
match signature {
447+
let sroot = match signature {
447448
Ok(signature) => {
449+
let sroot = if let Some(return_type) = signature.return_type() {
450+
SequentialRoot::Function(return_type)
451+
} else {
452+
SequentialRoot::Procedure
453+
};
454+
448455
let subpgm_ent = body.specification.define(
449456
self.arena,
450457
AnyEntKind::Overloaded(Overloaded::Subprogram(signature)),
451458
);
452459
scope.add(subpgm_ent, diagnostics);
460+
461+
sroot
453462
}
454-
Err(err) => err.add_to(diagnostics)?,
455-
}
463+
Err(err) => {
464+
err.add_to(diagnostics)?;
465+
SequentialRoot::Unknown
466+
}
467+
};
456468
let subpgm_region = subpgm_region.with_parent(scope);
457469

458470
self.analyze_declarative_part(&subpgm_region, &mut body.declarations, diagnostics)?;
459471
subpgm_region.close(diagnostics);
460472

461-
self.analyze_sequential_part(&subpgm_region, &mut body.statements, diagnostics)?;
473+
self.analyze_sequential_part(
474+
&subpgm_region,
475+
&sroot,
476+
&mut body.statements,
477+
diagnostics,
478+
)?;
462479
}
463480
Declaration::SubprogramDeclaration(ref mut subdecl) => {
464481
let subpgm_region = scope.nested();
@@ -971,7 +988,7 @@ impl<'a> AnalyzeContext<'a> {
971988

972989
if let Some(ref mut expression) = object_decl.expression {
973990
if let Ok(ref subtype) = subtype {
974-
self.expr_with_ttyp(
991+
self.expr_pos_with_ttyp(
975992
scope,
976993
subtype.type_mark(),
977994
&expression.pos,

vhdl_lang/src/analysis/expression.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ impl<'a> AnalyzeContext<'a> {
229229
op.set_unique_reference(&overloaded);
230230
for (idx, expr) in exprs.iter_mut().enumerate() {
231231
let target_type = overloaded.formals().nth(idx).unwrap().type_mark();
232-
self.expr_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics)?;
232+
self.expr_pos_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics)?;
233233
}
234234
Ok(())
235235
}
@@ -489,7 +489,13 @@ impl<'a> AnalyzeContext<'a> {
489489

490490
match self.resolve_type_mark(scope, type_mark) {
491491
Ok(target_type) => {
492-
self.expr_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics)?;
492+
self.expr_pos_with_ttyp(
493+
scope,
494+
target_type,
495+
&expr.pos,
496+
&mut expr.item,
497+
diagnostics,
498+
)?;
493499
Ok(target_type)
494500
}
495501
Err(e) => {
@@ -517,9 +523,19 @@ impl<'a> AnalyzeContext<'a> {
517523
Ok(())
518524
}
519525

526+
pub fn expr_with_ttyp(
527+
&self,
528+
scope: &Scope<'a>,
529+
target_type: TypeEnt<'a>,
530+
expr: &mut WithPos<Expression>,
531+
diagnostics: &mut dyn DiagnosticHandler,
532+
) -> FatalResult {
533+
self.expr_pos_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics)
534+
}
535+
520536
/// Returns true if the name actually matches the target type
521537
/// None if it was uncertain
522-
pub fn expr_with_ttyp(
538+
pub fn expr_pos_with_ttyp(
523539
&self,
524540
scope: &Scope<'a>,
525541
target_type: TypeEnt<'a>,
@@ -766,7 +782,7 @@ impl<'a> AnalyzeContext<'a> {
766782
};
767783

768784
if let Some(elem) = elem {
769-
self.expr_with_ttyp(
785+
self.expr_pos_with_ttyp(
770786
scope,
771787
elem.type_mark(),
772788
&actual_expr.pos,
@@ -813,7 +829,7 @@ impl<'a> AnalyzeContext<'a> {
813829
}
814830
Ok(None) => {
815831
if let Some(index_type) = index_type {
816-
self.expr_with_ttyp(
832+
self.expr_pos_with_ttyp(
817833
scope,
818834
index_type.into(),
819835
&index_expr.pos,
@@ -860,12 +876,12 @@ impl<'a> AnalyzeContext<'a> {
860876

861877
if is_elem || !is_array {
862878
// Prefer element type in presence of ambiguity
863-
self.expr_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?;
879+
self.expr_pos_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?;
864880
} else if is_array {
865-
self.expr_with_ttyp(scope, array_type, &expr.pos, &mut expr.item, diagnostics)?;
881+
self.expr_pos_with_ttyp(scope, array_type, &expr.pos, &mut expr.item, diagnostics)?;
866882
}
867883
} else {
868-
self.expr_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?;
884+
self.expr_pos_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?;
869885
}
870886

871887
Ok(())
@@ -932,7 +948,7 @@ mod test {
932948
) {
933949
let mut expr = code.expr();
934950
self.ctx()
935-
.expr_with_ttyp(&self.scope, ttyp, &expr.pos, &mut expr.item, diagnostics)
951+
.expr_pos_with_ttyp(&self.scope, ttyp, &expr.pos, &mut expr.item, diagnostics)
936952
.unwrap()
937953
}
938954
}

vhdl_lang/src/analysis/package_instance.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<'a> AnalyzeContext<'a> {
109109

110110
mapping.insert(uninst_typ.id(), typ.into());
111111
}
112-
GpkgInterfaceEnt::Constant(obj) => self.expr_with_ttyp(
112+
GpkgInterfaceEnt::Constant(obj) => self.expr_pos_with_ttyp(
113113
scope,
114114
obj.type_mark(),
115115
&assoc.actual.pos,

vhdl_lang/src/analysis/range.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,14 @@ impl<'a> AnalyzeContext<'a> {
196196
) -> FatalResult {
197197
match range {
198198
Range::Range(ref mut constraint) => {
199-
self.expr_with_ttyp(
199+
self.expr_pos_with_ttyp(
200200
scope,
201201
target_type,
202202
&constraint.left_expr.pos,
203203
&mut constraint.left_expr.item,
204204
diagnostics,
205205
)?;
206-
self.expr_with_ttyp(
206+
self.expr_pos_with_ttyp(
207207
scope,
208208
target_type,
209209
&constraint.right_expr.pos,

vhdl_lang/src/analysis/sequential.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// These fields are better explicit than .. since we are forced to consider if new fields should be searched
88
#![allow(clippy::unneeded_field_pattern)]
99

10+
use super::named_entity::TypeEnt;
1011
use super::*;
1112
use crate::ast::*;
1213
use crate::data::*;
@@ -18,6 +19,7 @@ impl<'a> AnalyzeContext<'a> {
1819
fn analyze_sequential_statement(
1920
&self,
2021
scope: &Scope<'a>,
22+
sroot: &SequentialRoot<'a>,
2123
statement: &mut LabeledSequentialStatement,
2224
diagnostics: &mut dyn DiagnosticHandler,
2325
) -> FatalResult {
@@ -27,9 +29,29 @@ impl<'a> AnalyzeContext<'a> {
2729

2830
match statement.statement {
2931
SequentialStatement::Return(ref mut ret) => {
30-
let ReturnStatement { expression } = ret;
31-
if let Some(ref mut expression) = expression {
32-
self.analyze_expression(scope, expression, diagnostics)?;
32+
let ReturnStatement { ref mut expression } = ret.item;
33+
34+
match sroot {
35+
SequentialRoot::Function(ttyp) => {
36+
if let Some(ref mut expression) = expression {
37+
self.expr_with_ttyp(scope, *ttyp, expression, diagnostics)?;
38+
} else {
39+
diagnostics.error(&ret.pos, "Functions cannot return without a value");
40+
}
41+
}
42+
SequentialRoot::Procedure => {
43+
if expression.is_some() {
44+
diagnostics.error(&ret.pos, "Procedures cannot return a value");
45+
}
46+
}
47+
SequentialRoot::Process => {
48+
diagnostics.error(&ret.pos, "Cannot return from a process");
49+
}
50+
SequentialRoot::Unknown => {
51+
if let Some(ref mut expression) = expression {
52+
self.analyze_expression(scope, expression, diagnostics)?;
53+
}
54+
}
3355
}
3456
}
3557
SequentialStatement::Wait(ref mut wait_stmt) => {
@@ -98,11 +120,11 @@ impl<'a> AnalyzeContext<'a> {
98120
// @TODO write generic function for this
99121
for conditional in conditionals {
100122
let Conditional { condition, item } = conditional;
101-
self.analyze_sequential_part(scope, item, diagnostics)?;
123+
self.analyze_sequential_part(scope, sroot, item, diagnostics)?;
102124
self.analyze_expression(scope, condition, diagnostics)?;
103125
}
104126
if let Some(else_item) = else_item {
105-
self.analyze_sequential_part(scope, else_item, diagnostics)?;
127+
self.analyze_sequential_part(scope, sroot, else_item, diagnostics)?;
106128
}
107129
}
108130
SequentialStatement::Case(ref mut case_stmt) => {
@@ -115,7 +137,7 @@ impl<'a> AnalyzeContext<'a> {
115137
for alternative in alternatives.iter_mut() {
116138
let Alternative { choices, item } = alternative;
117139
self.analyze_choices(scope, choices, diagnostics)?;
118-
self.analyze_sequential_part(scope, item, diagnostics)?;
140+
self.analyze_sequential_part(scope, sroot, item, diagnostics)?;
119141
}
120142
}
121143
SequentialStatement::Loop(ref mut loop_stmt) => {
@@ -131,14 +153,14 @@ impl<'a> AnalyzeContext<'a> {
131153
self.arena.define(index, AnyEntKind::LoopParameter(typ)),
132154
diagnostics,
133155
);
134-
self.analyze_sequential_part(&region, statements, diagnostics)?;
156+
self.analyze_sequential_part(&region, sroot, statements, diagnostics)?;
135157
}
136158
Some(IterationScheme::While(ref mut expr)) => {
137159
self.analyze_expression(scope, expr, diagnostics)?;
138-
self.analyze_sequential_part(scope, statements, diagnostics)?;
160+
self.analyze_sequential_part(scope, sroot, statements, diagnostics)?;
139161
}
140162
None => {
141-
self.analyze_sequential_part(scope, statements, diagnostics)?;
163+
self.analyze_sequential_part(scope, sroot, statements, diagnostics)?;
142164
}
143165
}
144166
}
@@ -195,13 +217,21 @@ impl<'a> AnalyzeContext<'a> {
195217
pub fn analyze_sequential_part(
196218
&self,
197219
scope: &Scope<'a>,
220+
sroot: &SequentialRoot<'a>,
198221
statements: &mut [LabeledSequentialStatement],
199222
diagnostics: &mut dyn DiagnosticHandler,
200223
) -> FatalResult {
201224
for statement in statements.iter_mut() {
202-
self.analyze_sequential_statement(scope, statement, diagnostics)?;
225+
self.analyze_sequential_statement(scope, sroot, statement, diagnostics)?;
203226
}
204227

205228
Ok(())
206229
}
207230
}
231+
232+
pub enum SequentialRoot<'a> {
233+
Process,
234+
Procedure,
235+
Function(TypeEnt<'a>),
236+
Unknown,
237+
}

vhdl_lang/src/analysis/tests/resolves_names.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ end package;
483483
package body pkg is
484484
procedure proc2(c : natural) is
485485
begin
486-
return c;
486+
return;
487487
end;
488488
489489
function f return natural is

0 commit comments

Comments
 (0)