Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.

Commit c02ea2f

Browse files
perostOpenModelica-Hudson
authored andcommitted
[NF] Improve handling of record evaluation.
- Generate a binding from the record fields for record instances with no explicit binding. - Attempt to use the binding from the record instance when evaluating record fields with no explicit binding. Belonging to [master]: - #2441 - OpenModelica/OpenModelica-testsuite#948
1 parent 90c1886 commit c02ea2f

File tree

6 files changed

+143
-60
lines changed

6 files changed

+143
-60
lines changed

Compiler/NFFrontEnd/NFBinding.mo

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ public
7474
Expression bindingExp;
7575
end FLAT_BINDING;
7676

77+
record CEVAL_BINDING
78+
"Used by the constant evaluation for generated bindings (e.g. record
79+
bindings constructed from the record fields) that should be discarded
80+
during flattening."
81+
Expression bindingExp;
82+
end CEVAL_BINDING;
83+
7784
public
7885
function fromAbsyn
7986
input Option<Absyn.Exp> bindingExp;
@@ -105,6 +112,17 @@ public
105112
end match;
106113
end isBound;
107114

115+
function isExplicitlyBound
116+
input Binding binding;
117+
output Boolean isBound;
118+
algorithm
119+
isBound := match binding
120+
case UNBOUND() then false;
121+
case CEVAL_BINDING() then false;
122+
else true;
123+
end match;
124+
end isExplicitlyBound;
125+
108126
function isUnbound
109127
input Binding binding;
110128
output Boolean isUnbound;

Compiler/NFFrontEnd/NFCeval.mo

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ import Type = NFType;
4646
import NFTyping.ExpOrigin;
4747
import ExpressionSimplify;
4848
import NFPrefixes.Variability;
49+
import NFClassTree.ClassTree;
50+
import ComplexType = NFComplexType;
4951

5052
protected
5153
import NFFunction.Function;
@@ -268,6 +270,10 @@ algorithm
268270
comp := InstNode.component(node);
269271
binding := Component.getBinding(comp);
270272

273+
if not Binding.isBound(binding) then
274+
binding := makeComponentBinding(comp, node, originExp, target);
275+
end if;
276+
271277
exp := match binding
272278
case Binding.TYPED_BINDING()
273279
algorithm
@@ -281,6 +287,8 @@ algorithm
281287
then
282288
exp;
283289

290+
case Binding.CEVAL_BINDING() then binding.bindingExp;
291+
284292
case Binding.UNBOUND()
285293
algorithm
286294
printUnboundError(target, originExp);
@@ -295,6 +303,59 @@ algorithm
295303
end match;
296304
end evalComponentBinding;
297305

306+
function makeComponentBinding
307+
input Component component;
308+
input InstNode node;
309+
input Expression originExp;
310+
input EvalTarget target;
311+
output Binding binding;
312+
protected
313+
ClassTree tree;
314+
array<InstNode> comps;
315+
list<Expression> fields;
316+
Type ty;
317+
InstNode rec_node;
318+
Expression exp;
319+
ComponentRef cr;
320+
algorithm
321+
binding := matchcontinue (component, originExp, node)
322+
// A record component without an explicit binding, create one from its children.
323+
case (Component.TYPED_COMPONENT(ty = Type.COMPLEX(complexTy = ComplexType.RECORD(rec_node))),
324+
Expression.CREF(cref = cr), _)
325+
algorithm
326+
tree := Class.classTree(InstNode.getClass(component.classInst));
327+
comps := ClassTree.getComponents(tree);
328+
fields := {};
329+
330+
for i in arrayLength(comps):-1:1 loop
331+
ty := InstNode.getType(comps[i]);
332+
fields := Expression.CREF(ty,
333+
ComponentRef.CREF(comps[i], {}, ty, NFComponentRef.Origin.CREF, cr)) :: fields;
334+
end for;
335+
336+
exp := Expression.RECORD(InstNode.scopePath(rec_node), component.ty, fields);
337+
exp := evalExp(exp);
338+
binding := Binding.CEVAL_BINDING(exp);
339+
InstNode.updateComponent(Component.setBinding(binding, component), node);
340+
then
341+
binding;
342+
343+
// A record field without an explicit binding, evaluate the parent's binding
344+
// if it as one and fetch the binding from it instead.
345+
case (_, _, InstNode.COMPONENT_NODE(parent = rec_node as InstNode.COMPONENT_NODE()))
346+
guard Type.isRecord(InstNode.getType(rec_node))
347+
algorithm
348+
exp := evalComponentBinding(rec_node, Expression.EMPTY(), target);
349+
exp := Expression.lookupRecordField(InstNode.name(node), exp);
350+
binding := Binding.CEVAL_BINDING(exp);
351+
InstNode.updateComponent(Component.setBinding(binding, component), node);
352+
then
353+
binding;
354+
355+
else Binding.UNBOUND(NONE());
356+
end matchcontinue;
357+
end makeComponentBinding;
358+
298359
function evalTypename
299360
input Type ty;
300361
input Expression originExp;

Compiler/NFFrontEnd/NFFlatten.mo

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ algorithm
379379
binding := Component.getBinding(comp);
380380

381381
// Create an equation if there's a binding on a complex component.
382-
if Binding.isBound(binding) then
382+
if Binding.isExplicitlyBound(binding) then
383383
binding := flattenBinding(binding, prefix, node);
384384
binding_exp := Binding.getTypedExp(binding);
385385

@@ -444,12 +444,12 @@ function flattenBinding
444444
input ComponentRef prefix;
445445
input InstNode component;
446446
algorithm
447-
() := match binding
447+
binding := match binding
448448
local
449449
list<Subscript> subs;
450450
Integer binding_level;
451451

452-
case Binding.UNBOUND() then ();
452+
case Binding.UNBOUND() then binding;
453453

454454
case Binding.TYPED_BINDING()
455455
algorithm
@@ -460,7 +460,9 @@ algorithm
460460
binding.bindingExp := Expression.applySubscripts(subs, binding.bindingExp);
461461
end if;
462462
then
463-
();
463+
binding;
464+
465+
case Binding.CEVAL_BINDING() then Binding.UNBOUND(NONE());
464466

465467
else
466468
algorithm
@@ -838,7 +840,7 @@ algorithm
838840
funcs := collectTypeFuncs(ty, funcs);
839841

840842
// Collect functions used in the component's binding, if it has one.
841-
if Binding.isBound(binding) then
843+
if Binding.isExplicitlyBound(binding) then
842844
funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
843845
end if;
844846
then
@@ -1104,7 +1106,7 @@ algorithm
11041106
funcs := collectTypeFuncs(Component.getType(comp), funcs);
11051107
binding := Component.getBinding(comp);
11061108

1107-
if Binding.isBound(binding) then
1109+
if Binding.isExplicitlyBound(binding) then
11081110
funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
11091111
end if;
11101112
end for;

Compiler/NFFrontEnd/NFType.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ public
329329
output Boolean isRecord;
330330
algorithm
331331
isRecord := match ty
332-
case COMPLEX() then Restriction.isRecord(Class.restriction(InstNode.getClass(ty.cls)));
332+
case COMPLEX(complexTy = ComplexType.RECORD()) then true;
333333
else false;
334334
end match;
335335
end isRecord;

Compiler/NFFrontEnd/NFTypeCheck.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function isValidArgumentMatch
124124
output Boolean v = kind == MatchKind.EXACT
125125
or kind == MatchKind.CAST
126126
or kind == MatchKind.GENERIC
127-
;
127+
or kind == MatchKind.PLUG_COMPATIBLE;
128128
end isValidArgumentMatch;
129129

130130
function isValidPlugCompatibleMatch

Compiler/NFFrontEnd/NFTyping.mo

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import NFInstNode.CachedData;
8484
import Direction = NFPrefixes.Direction;
8585
import BindingOrigin = NFBindingOrigin;
8686
import ElementSource;
87+
import StringUtil;
8788

8889
uniontype TypingError
8990
record NO_ERROR end NO_ERROR;
@@ -657,6 +658,11 @@ function typeComponentBinding
657658
protected
658659
InstNode node = InstNode.resolveOuter(component);
659660
Component c;
661+
Binding binding;
662+
InstNode cls;
663+
MatchKind matchKind;
664+
String name;
665+
Variability comp_var, comp_eff_var, bind_var;
660666
algorithm
661667
if InstNode.isEmpty(component) then
662668
return;
@@ -665,71 +671,67 @@ algorithm
665671
c := InstNode.component(node);
666672

667673
() := match c
668-
local
669-
Binding binding;
670-
InstNode cls;
671-
MatchKind matchKind;
672-
Boolean dirty;
673-
String name;
674-
Variability comp_var, comp_eff_var, bind_var;
675-
676-
// A component that's already been typed.
674+
// A component with a binding that's already been typed.
677675
case Component.TYPED_COMPONENT(binding = Binding.TYPED_BINDING()) then ();
676+
case Component.TYPED_COMPONENT(binding = Binding.CEVAL_BINDING()) then ();
678677

679-
case Component.TYPED_COMPONENT()
678+
case Component.TYPED_COMPONENT(binding = Binding.UNBOUND())
680679
algorithm
681-
name := InstNode.name(component);
682680
checkBindingEach(c.binding, not Type.isArray(c.ty), InstNode.parent(component));
683-
binding := typeBinding(c.binding, intBitOr(origin, ExpOrigin.BINDING));
684-
dirty := not referenceEq(binding, c.binding);
685-
686-
// If the binding changed during typing it means it was an untyped
687-
// binding which is now typed, and it needs to be type checked.
688-
if dirty then
689-
binding := TypeCheck.matchBinding(binding, c.ty, name, InstNode.derivedParent(node));
690-
comp_var := Component.variability(c);
691-
comp_eff_var := Prefixes.effectiveVariability(comp_var);
692-
bind_var := Prefixes.effectiveVariability(Binding.variability(binding));
693-
694-
if bind_var > comp_eff_var then
695-
if comp_var == Variability.PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then
696-
Error.addSourceMessage(Error.FUNCTION_HIGHER_VARIABILITY_BINDING, {
697-
name, Prefixes.variabilityString(comp_eff_var),
698-
Binding.toString(c.binding), Prefixes.variabilityString(bind_var)},
699-
Binding.getInfo(binding));
700-
else
701-
Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING, {
702-
name, Prefixes.variabilityString(comp_eff_var),
703-
"'" + Binding.toString(c.binding) + "'", Prefixes.variabilityString(bind_var)},
704-
Binding.getInfo(binding));
705-
fail();
706-
end if;
707-
end if;
708681

709-
// Evaluate the binding if the component is a constant.
710-
if comp_var <= Variability.STRUCTURAL_PARAMETER then
711-
// TODO: Allow this to fail for now. Once constant evaluation has
712-
// been improved we should print an error when a constant binding
713-
// couldn't be evaluated instead.
714-
try
715-
binding := evalBinding(binding, origin);
716-
else
717-
end try;
682+
if Binding.isBound(c.condition) then
683+
c.condition := typeComponentCondition(c.condition, origin);
684+
InstNode.updateComponent(c, node);
685+
end if;
686+
687+
typeBindings(c.classInst, component, origin);
688+
then
689+
();
690+
691+
case Component.TYPED_COMPONENT(binding = Binding.UNTYPED_BINDING())
692+
algorithm
693+
name := InstNode.name(component);
694+
binding := typeBinding(c.binding, intBitOr(origin, ExpOrigin.BINDING));
695+
checkBindingEach(binding, not Type.isArray(c.ty), InstNode.parent(component));
696+
697+
binding := TypeCheck.matchBinding(binding, c.ty, name, InstNode.derivedParent(node));
698+
comp_var := Component.variability(c);
699+
comp_eff_var := Prefixes.effectiveVariability(comp_var);
700+
bind_var := Prefixes.effectiveVariability(Binding.variability(binding));
701+
702+
if bind_var > comp_eff_var then
703+
if comp_var == Variability.PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then
704+
Error.addSourceMessage(Error.FUNCTION_HIGHER_VARIABILITY_BINDING, {
705+
name, Prefixes.variabilityString(comp_eff_var),
706+
Binding.toString(c.binding), Prefixes.variabilityString(bind_var)},
707+
Binding.getInfo(binding));
708+
else
709+
Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING, {
710+
name, Prefixes.variabilityString(comp_eff_var),
711+
"'" + Binding.toString(c.binding) + "'", Prefixes.variabilityString(bind_var)},
712+
Binding.getInfo(binding));
713+
fail();
718714
end if;
715+
end if;
719716

720-
c.binding := binding;
717+
// Evaluate the binding if the component is a constant.
718+
if comp_var <= Variability.STRUCTURAL_PARAMETER then
719+
// TODO: Allow this to fail for now. Once constant evaluation has
720+
// been improved we should print an error when a constant binding
721+
// couldn't be evaluated instead.
722+
try
723+
binding := evalBinding(binding, origin);
724+
else
725+
end try;
721726
end if;
722727

728+
c.binding := binding;
729+
723730
if Binding.isBound(c.condition) then
724731
c.condition := typeComponentCondition(c.condition, origin);
725-
dirty := true;
726-
end if;
727-
728-
// Update the node if the component changed.
729-
if dirty then
730-
InstNode.updateComponent(c, node);
731732
end if;
732733

734+
InstNode.updateComponent(c, node);
733735
typeBindings(c.classInst, component, origin);
734736
then
735737
();

0 commit comments

Comments
 (0)