Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Compiler/NFFrontEnd/NFBinding.mo
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ public
Expression bindingExp;
end FLAT_BINDING;

record CEVAL_BINDING
"Used by the constant evaluation for generated bindings (e.g. record
bindings constructed from the record fields) that should be discarded
during flattening."
Expression bindingExp;
end CEVAL_BINDING;

public
function fromAbsyn
input Option<Absyn.Exp> bindingExp;
Expand Down Expand Up @@ -105,6 +112,17 @@ public
end match;
end isBound;

function isExplicitlyBound
input Binding binding;
output Boolean isBound;
algorithm
isBound := match binding
case UNBOUND() then false;
case CEVAL_BINDING() then false;
else true;
end match;
end isExplicitlyBound;

function isUnbound
input Binding binding;
output Boolean isUnbound;
Expand Down
61 changes: 61 additions & 0 deletions Compiler/NFFrontEnd/NFCeval.mo
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import Type = NFType;
import NFTyping.ExpOrigin;
import ExpressionSimplify;
import NFPrefixes.Variability;
import NFClassTree.ClassTree;
import ComplexType = NFComplexType;

protected
import NFFunction.Function;
Expand Down Expand Up @@ -268,6 +270,10 @@ algorithm
comp := InstNode.component(node);
binding := Component.getBinding(comp);

if not Binding.isBound(binding) then
binding := makeComponentBinding(comp, node, originExp, target);
end if;

exp := match binding
case Binding.TYPED_BINDING()
algorithm
Expand All @@ -281,6 +287,8 @@ algorithm
then
exp;

case Binding.CEVAL_BINDING() then binding.bindingExp;

case Binding.UNBOUND()
algorithm
printUnboundError(target, originExp);
Expand All @@ -295,6 +303,59 @@ algorithm
end match;
end evalComponentBinding;

function makeComponentBinding
input Component component;
input InstNode node;
input Expression originExp;
input EvalTarget target;
output Binding binding;
protected
ClassTree tree;
array<InstNode> comps;
list<Expression> fields;
Type ty;
InstNode rec_node;
Expression exp;
ComponentRef cr;
algorithm
binding := matchcontinue (component, originExp, node)
// A record component without an explicit binding, create one from its children.
case (Component.TYPED_COMPONENT(ty = Type.COMPLEX(complexTy = ComplexType.RECORD(rec_node))),
Expression.CREF(cref = cr), _)
algorithm
tree := Class.classTree(InstNode.getClass(component.classInst));
comps := ClassTree.getComponents(tree);
fields := {};

for i in arrayLength(comps):-1:1 loop
ty := InstNode.getType(comps[i]);
fields := Expression.CREF(ty,
ComponentRef.CREF(comps[i], {}, ty, NFComponentRef.Origin.CREF, cr)) :: fields;
end for;

exp := Expression.RECORD(InstNode.scopePath(rec_node), component.ty, fields);
exp := evalExp(exp);
binding := Binding.CEVAL_BINDING(exp);
InstNode.updateComponent(Component.setBinding(binding, component), node);
then
binding;

// A record field without an explicit binding, evaluate the parent's binding
// if it as one and fetch the binding from it instead.
case (_, _, InstNode.COMPONENT_NODE(parent = rec_node as InstNode.COMPONENT_NODE()))
guard Type.isRecord(InstNode.getType(rec_node))
algorithm
exp := evalComponentBinding(rec_node, Expression.EMPTY(), target);
exp := Expression.lookupRecordField(InstNode.name(node), exp);
binding := Binding.CEVAL_BINDING(exp);
InstNode.updateComponent(Component.setBinding(binding, component), node);
then
binding;

else Binding.UNBOUND(NONE());
end matchcontinue;
end makeComponentBinding;

function evalTypename
input Type ty;
input Expression originExp;
Expand Down
14 changes: 8 additions & 6 deletions Compiler/NFFrontEnd/NFFlatten.mo
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ algorithm
binding := Component.getBinding(comp);

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

Expand Down Expand Up @@ -444,12 +444,12 @@ function flattenBinding
input ComponentRef prefix;
input InstNode component;
algorithm
() := match binding
binding := match binding
local
list<Subscript> subs;
Integer binding_level;

case Binding.UNBOUND() then ();
case Binding.UNBOUND() then binding;

case Binding.TYPED_BINDING()
algorithm
Expand All @@ -460,7 +460,9 @@ algorithm
binding.bindingExp := Expression.applySubscripts(subs, binding.bindingExp);
end if;
then
();
binding;

case Binding.CEVAL_BINDING() then Binding.UNBOUND(NONE());

else
algorithm
Expand Down Expand Up @@ -838,7 +840,7 @@ algorithm
funcs := collectTypeFuncs(ty, funcs);

// Collect functions used in the component's binding, if it has one.
if Binding.isBound(binding) then
if Binding.isExplicitlyBound(binding) then
funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
end if;
then
Expand Down Expand Up @@ -1104,7 +1106,7 @@ algorithm
funcs := collectTypeFuncs(Component.getType(comp), funcs);
binding := Component.getBinding(comp);

if Binding.isBound(binding) then
if Binding.isExplicitlyBound(binding) then
funcs := collectExpFuncs(Binding.getTypedExp(binding), funcs);
end if;
end for;
Expand Down
2 changes: 1 addition & 1 deletion Compiler/NFFrontEnd/NFType.mo
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ public
output Boolean isRecord;
algorithm
isRecord := match ty
case COMPLEX() then Restriction.isRecord(Class.restriction(InstNode.getClass(ty.cls)));
case COMPLEX(complexTy = ComplexType.RECORD()) then true;
else false;
end match;
end isRecord;
Expand Down
2 changes: 1 addition & 1 deletion Compiler/NFFrontEnd/NFTypeCheck.mo
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function isValidArgumentMatch
output Boolean v = kind == MatchKind.EXACT
or kind == MatchKind.CAST
or kind == MatchKind.GENERIC
;
or kind == MatchKind.PLUG_COMPATIBLE;
end isValidArgumentMatch;

function isValidPlugCompatibleMatch
Expand Down
106 changes: 54 additions & 52 deletions Compiler/NFFrontEnd/NFTyping.mo
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import NFInstNode.CachedData;
import Direction = NFPrefixes.Direction;
import BindingOrigin = NFBindingOrigin;
import ElementSource;
import StringUtil;

uniontype TypingError
record NO_ERROR end NO_ERROR;
Expand Down Expand Up @@ -657,6 +658,11 @@ function typeComponentBinding
protected
InstNode node = InstNode.resolveOuter(component);
Component c;
Binding binding;
InstNode cls;
MatchKind matchKind;
String name;
Variability comp_var, comp_eff_var, bind_var;
algorithm
if InstNode.isEmpty(component) then
return;
Expand All @@ -665,71 +671,67 @@ algorithm
c := InstNode.component(node);

() := match c
local
Binding binding;
InstNode cls;
MatchKind matchKind;
Boolean dirty;
String name;
Variability comp_var, comp_eff_var, bind_var;

// A component that's already been typed.
// A component with a binding that's already been typed.
case Component.TYPED_COMPONENT(binding = Binding.TYPED_BINDING()) then ();
case Component.TYPED_COMPONENT(binding = Binding.CEVAL_BINDING()) then ();

case Component.TYPED_COMPONENT()
case Component.TYPED_COMPONENT(binding = Binding.UNBOUND())
algorithm
name := InstNode.name(component);
checkBindingEach(c.binding, not Type.isArray(c.ty), InstNode.parent(component));
binding := typeBinding(c.binding, intBitOr(origin, ExpOrigin.BINDING));
dirty := not referenceEq(binding, c.binding);

// If the binding changed during typing it means it was an untyped
// binding which is now typed, and it needs to be type checked.
if dirty then
binding := TypeCheck.matchBinding(binding, c.ty, name, InstNode.derivedParent(node));
comp_var := Component.variability(c);
comp_eff_var := Prefixes.effectiveVariability(comp_var);
bind_var := Prefixes.effectiveVariability(Binding.variability(binding));

if bind_var > comp_eff_var then
if comp_var == Variability.PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then
Error.addSourceMessage(Error.FUNCTION_HIGHER_VARIABILITY_BINDING, {
name, Prefixes.variabilityString(comp_eff_var),
Binding.toString(c.binding), Prefixes.variabilityString(bind_var)},
Binding.getInfo(binding));
else
Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING, {
name, Prefixes.variabilityString(comp_eff_var),
"'" + Binding.toString(c.binding) + "'", Prefixes.variabilityString(bind_var)},
Binding.getInfo(binding));
fail();
end if;
end if;

// Evaluate the binding if the component is a constant.
if comp_var <= Variability.STRUCTURAL_PARAMETER then
// TODO: Allow this to fail for now. Once constant evaluation has
// been improved we should print an error when a constant binding
// couldn't be evaluated instead.
try
binding := evalBinding(binding, origin);
else
end try;
if Binding.isBound(c.condition) then
c.condition := typeComponentCondition(c.condition, origin);
InstNode.updateComponent(c, node);
end if;

typeBindings(c.classInst, component, origin);
then
();

case Component.TYPED_COMPONENT(binding = Binding.UNTYPED_BINDING())
algorithm
name := InstNode.name(component);
binding := typeBinding(c.binding, intBitOr(origin, ExpOrigin.BINDING));
checkBindingEach(binding, not Type.isArray(c.ty), InstNode.parent(component));

binding := TypeCheck.matchBinding(binding, c.ty, name, InstNode.derivedParent(node));
comp_var := Component.variability(c);
comp_eff_var := Prefixes.effectiveVariability(comp_var);
bind_var := Prefixes.effectiveVariability(Binding.variability(binding));

if bind_var > comp_eff_var then
if comp_var == Variability.PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then
Error.addSourceMessage(Error.FUNCTION_HIGHER_VARIABILITY_BINDING, {
name, Prefixes.variabilityString(comp_eff_var),
Binding.toString(c.binding), Prefixes.variabilityString(bind_var)},
Binding.getInfo(binding));
else
Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING, {
name, Prefixes.variabilityString(comp_eff_var),
"'" + Binding.toString(c.binding) + "'", Prefixes.variabilityString(bind_var)},
Binding.getInfo(binding));
fail();
end if;
end if;

c.binding := binding;
// Evaluate the binding if the component is a constant.
if comp_var <= Variability.STRUCTURAL_PARAMETER then
// TODO: Allow this to fail for now. Once constant evaluation has
// been improved we should print an error when a constant binding
// couldn't be evaluated instead.
try
binding := evalBinding(binding, origin);
else
end try;
end if;

c.binding := binding;

if Binding.isBound(c.condition) then
c.condition := typeComponentCondition(c.condition, origin);
dirty := true;
end if;

// Update the node if the component changed.
if dirty then
InstNode.updateComponent(c, node);
end if;

InstNode.updateComponent(c, node);
typeBindings(c.classInst, component, origin);
then
();
Expand Down