Skip to content

Commit

Permalink
Fix evaluation of record fields (#12940)
Browse files Browse the repository at this point in the history
- Delay the type matching when creating a binding for a record field from
  its parent during constant evaluation. The reason why it might not
  already have been type matched is usually that it's used in a
  dimension, in which case the parent might not yet have been completely
  typed.
  • Loading branch information
perost authored Sep 26, 2024
1 parent 9c930d2 commit 27f0bf5
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 35 deletions.
7 changes: 6 additions & 1 deletion OMCompiler/Compiler/NFFrontEnd/NFCeval.mo
Original file line number Diff line number Diff line change
Expand Up @@ -697,12 +697,17 @@ algorithm
exp_context := if InstNode.isFunction(InstNode.explicitParent(parent))
then NFInstContext.FUNCTION else NFInstContext.CLASS;

Typing.typeComponentBinding(parent, exp_context, typeChildren = false);
comp := InstNode.component(parent);
binding := Component.getBinding(comp);
subs := ComponentRef.getSubscripts(parent_cr);

if Binding.hasExp(binding) then
if not Binding.isTyped(binding) then
binding := Typing.typeBinding(binding, InstContext.set(exp_context, NFInstContext.BINDING));
comp := Component.setBinding(binding, comp);
InstNode.updateComponent(comp, parent);
end if;

exp := Binding.getExp(binding);
exp := Expression.applySubscripts(subs, exp);
exp := Expression.recordElement(ComponentRef.firstName(cref), exp);
Expand Down
65 changes: 31 additions & 34 deletions OMCompiler/Compiler/NFFrontEnd/NFTypeCheck.mo
Original file line number Diff line number Diff line change
Expand Up @@ -1952,46 +1952,43 @@ algorithm
for i in 1:arrayLength(actualComponents) loop
enode := expectedComponents[i];
ecomp := InstNode.component(enode);
anode := actualComponents[i];

if Component.isTyped(ecomp) then
anode := actualComponents[i];

// The records must have the same named components, but they don't need to
// be in the same order.
if InstNode.name(anode) == InstNode.name(enode) then
// If the names match we can use the index as is.
idx := i;
// The records must have the same named components, but they don't need to
// be in the same order.
if InstNode.name(anode) == InstNode.name(enode) then
// If the names match we can use the index as is.
idx := i;
else
// Otherwise look the index of the component up in the actual type.
try
idx := ClassTree.lookupComponentIndex(InstNode.name(enode), classTree);
else
// Otherwise look the index of the component up in the actual type.
try
idx := ClassTree.lookupComponentIndex(InstNode.name(enode), classTree);
else
// The records do not have the same named components and are incompatible.
matchKind := MatchKind.NOT_COMPATIBLE;
return;
end try;
// The records do not have the same named components and are incompatible.
matchKind := MatchKind.NOT_COMPATIBLE;
return;
end try;

anode := actualComponents[idx];
end if;
anode := actualComponents[idx];
end if;

// If the components aren't in the same order then we need to type cast
// the record expression to the expected record type.
if i <> idx then
matchKind := MatchKind.CAST;
end if;
// If the components aren't in the same order then we need to type cast
// the record expression to the expected record type.
if i <> idx then
matchKind := MatchKind.CAST;
end if;

// Match the type of the component to the expected type.
acomp := InstNode.component(anode);
e := expressions[idx];
(e, _, mk) := matchTypes(Component.getType(acomp), Component.getType(ecomp), e, options);
matchedExpressions := e :: matchedExpressions;
// Match the type of the component to the expected type.
acomp := InstNode.component(anode);
e := expressions[idx];
(e, _, mk) := matchTypes(Component.getType(acomp), Component.getType(ecomp), e, options);
matchedExpressions := e :: matchedExpressions;

if mk == MatchKind.CAST then
matchKind := mk;
elseif not isValidPlugCompatibleMatch(mk) then
matchKind := MatchKind.NOT_COMPATIBLE;
break;
end if;
if mk == MatchKind.CAST then
matchKind := mk;
elseif not isValidPlugCompatibleMatch(mk) then
matchKind := MatchKind.NOT_COMPATIBLE;
break;
end if;
end for;

Expand Down
1 change: 1 addition & 0 deletions testsuite/flattening/modelica/scodeinst/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ RecordBinding10.mo \
RecordBinding11.mo \
RecordBinding12.mo \
RecordBinding13.mo \
RecordBinding14.mo \
RecordConstructor1.mo \
RecordConstructor2.mo \
RecordConstructor3.mo \
Expand Down
65 changes: 65 additions & 0 deletions testsuite/flattening/modelica/scodeinst/RecordBinding14.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// name: RecordBinding14
// keywords:
// status: correct
// cflags: -d=newInst
//

package Cooling
record DXCoil
parameter Integer nSta = 1;
parameter Stage sta[nSta];
end DXCoil;

record NominalValues
parameter Real TEvaIn_nominal = 292.55;
parameter Real m_flow_nominal;
end NominalValues;

record Stage
parameter NominalValues nomVal;
end Stage;
end Cooling;

package Heating
model DryCoil
parameter Cooling.DXCoil datCoi;
end DryCoil;

model SingleSpeed
parameter DXCoil datCoi;
DryCoil dxCoi(final datCoi = datCoi);
end SingleSpeed;

record DXCoil
parameter Integer nSta = 1;
parameter Stage sta[nSta];
end DXCoil;

record NominalValues
parameter Real m_flow_nominal;
parameter Real TEvaIn_nominal = 292.55;
end NominalValues;

record Stage
parameter NominalValues nomVal;
end Stage;
end Heating;

model RecordBinding14
parameter Heating.DXCoil datCoi(sta = {Heating.Stage(nomVal = Heating.NominalValues(m_flow_nominal = 2))});
Heating.SingleSpeed sinSpeDX(final datCoi = datCoi);
end RecordBinding14;

// Result:
// class RecordBinding14
// final parameter Integer datCoi.nSta = 1;
// parameter Real datCoi.sta[1].nomVal.m_flow_nominal = 2.0;
// parameter Real datCoi.sta[1].nomVal.TEvaIn_nominal = 292.55;
// final parameter Integer sinSpeDX.datCoi.nSta = 1;
// final parameter Real sinSpeDX.datCoi.sta[1].nomVal.m_flow_nominal = datCoi.sta[1].nomVal.m_flow_nominal;
// final parameter Real sinSpeDX.datCoi.sta[1].nomVal.TEvaIn_nominal = datCoi.sta[1].nomVal.TEvaIn_nominal;
// final parameter Integer sinSpeDX.dxCoi.datCoi.nSta = 1;
// final parameter Real sinSpeDX.dxCoi.datCoi.sta[1].nomVal.TEvaIn_nominal = 292.55;
// final parameter Real sinSpeDX.dxCoi.datCoi.sta[1].nomVal.m_flow_nominal = 2.0;
// end RecordBinding14;
// endResult

0 comments on commit 27f0bf5

Please sign in to comment.