/*
* #%~
* The VDM Type Checker
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.typechecker.visitor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.intf.IQuestionAnswer;
import org.overture.ast.definitions.ABusClassDefinition;
import org.overture.ast.definitions.ACpuClassDefinition;
import org.overture.ast.definitions.AExplicitFunctionDefinition;
import org.overture.ast.definitions.AImplicitFunctionDefinition;
import org.overture.ast.definitions.AMultiBindListDefinition;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.definitions.ASystemClassDefinition;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.expressions.*;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.intf.lex.ILexRealToken;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.patterns.AExpressionPattern;
import org.overture.ast.patterns.AIdentifierPattern;
import org.overture.ast.patterns.ASeqBind;
import org.overture.ast.patterns.ASetBind;
import org.overture.ast.patterns.ATypeBind;
import org.overture.ast.patterns.PBind;
import org.overture.ast.patterns.PMultipleBind;
import org.overture.ast.patterns.PPattern;
import org.overture.ast.typechecker.NameScope;
import org.overture.ast.types.ABooleanBasicType;
import org.overture.ast.types.AClassType;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.AIntNumericBasicType;
import org.overture.ast.types.AMapMapType;
import org.overture.ast.types.ANatNumericBasicType;
import org.overture.ast.types.ANatOneNumericBasicType;
import org.overture.ast.types.AOperationType;
import org.overture.ast.types.AParameterType;
import org.overture.ast.types.AProductType;
import org.overture.ast.types.ARealNumericBasicType;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.ast.types.ASeq1SeqType;
import org.overture.ast.types.ASeqSeqType;
import org.overture.ast.types.ASet1SetType;
import org.overture.ast.types.SSetType;
import org.overture.ast.types.ATokenBasicType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SMapType;
import org.overture.ast.types.SNumericBasicType;
import org.overture.ast.types.SSeqType;
import org.overture.ast.util.PTypeSet;
import org.overture.ast.util.Utils;
import org.overture.config.Release;
import org.overture.config.Settings;
import org.overture.typechecker.Environment;
import org.overture.typechecker.FlatCheckedEnvironment;
import org.overture.typechecker.TypeCheckException;
import org.overture.typechecker.TypeCheckInfo;
import org.overture.typechecker.TypeCheckerErrors;
import org.overture.typechecker.assistant.definition.PDefinitionAssistantTC;
import org.overture.typechecker.assistant.definition.SClassDefinitionAssistantTC;
import org.overture.typechecker.assistant.type.AClassTypeAssistantTC;
import org.overture.typechecker.assistant.type.PTypeAssistantTC;
import org.overture.typechecker.utilities.type.QualifiedDefinition;
public class TypeCheckerExpVisitor extends AbstractTypeCheckVisitor
{
public TypeCheckerExpVisitor(
IQuestionAnswer<TypeCheckInfo, PType> typeCheckVisitor)
{
super(typeCheckVisitor);
}
@Override
public PType caseAApplyExp(AApplyExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
noConstraint.qualifiers = null;
node.setArgtypes(new ArrayList<PType>());
for (PExp a : node.getArgs())
{
question.qualifiers = null;
node.getArgtypes().add(a.apply(THIS, noConstraint));
}
node.setType(node.getRoot().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, question.scope, node.getArgtypes())));
if (question.assistantFactory.createPTypeAssistant().isUnknown(node.getType()))
{
return node.getType();
}
PDefinition func = question.env.getEnclosingDefinition();
boolean inFunction = question.env.isFunctional();
boolean inOperation = !inFunction;
boolean inReserved = (func == null || func.getName() == null) ? false : func.getName().isReserved();
if (inFunction)
{
PDefinition called = getRecursiveDefinition(node, question);
if (called instanceof AExplicitFunctionDefinition)
{
AExplicitFunctionDefinition def = (AExplicitFunctionDefinition) called;
if (def.getIsCurried())
{
// Only recursive if this apply is the last - so our type is not a function.
if (node.getType() instanceof AFunctionType
&& ((AFunctionType) node.getType()).getResult() instanceof AFunctionType)
{
called = null;
}
}
}
if (called != null)
{
if (func instanceof AExplicitFunctionDefinition)
{
AExplicitFunctionDefinition def = (AExplicitFunctionDefinition) func;
if (called == def)
{
node.setRecursive(def);
def.setRecursive(true);
}
} else if (func instanceof AImplicitFunctionDefinition)
{
AImplicitFunctionDefinition def = (AImplicitFunctionDefinition) func;
if (called == def)
{
node.setRecursive(def);
def.setRecursive(true);
}
}
}
}
boolean isSimple = !question.assistantFactory.createPTypeAssistant().isUnion(node.getType());
PTypeSet results = new PTypeSet(question.assistantFactory);
if (question.assistantFactory.createPTypeAssistant().isFunction(node.getType()))
{
AFunctionType ft = question.assistantFactory.createPTypeAssistant().getFunction(node.getType());
if (ft.getInstantiated() != null && !ft.getInstantiated())
{
// Something like f(x) rather than f[nat](x)
TypeCheckerErrors.report(3350, "Polymorphic function has not been instantiated", node.getRoot().getLocation(), node);
}
question.assistantFactory.createPTypeAssistant().typeResolve(ft, null, THIS, question);
results.add(functionApply(node, isSimple, ft, question));
}
if (question.assistantFactory.createPTypeAssistant().isOperation(node.getType()))
{
if (node.getRoot() instanceof AVariableExp)
{
AVariableExp exp = (AVariableExp)node.getRoot();
PDefinition opdef = question.env.findName(exp.getName(), question.scope);
AClassTypeAssistantTC assist = question.assistantFactory.createAClassTypeAssistant();
if (opdef != null && assist.isConstructor(opdef) && !assist.inConstructor(question.env))
{
TypeCheckerErrors.report(3337, "Cannot call a constructor from here", node.getLocation(), node);
results.add(AstFactory.newAUnknownType(node.getLocation()));
}
}
AOperationType ot = question.assistantFactory.createPTypeAssistant().getOperation(node.getType());
question.assistantFactory.createPTypeAssistant().typeResolve(ot, null, THIS, question);
if (inFunction && Settings.release == Release.VDM_10 && !ot.getPure())
{
TypeCheckerErrors.report(3300, "Impure operation '" + node.getRoot()
+ "' cannot be called from here", node.getLocation(), node);
results.add(AstFactory.newAUnknownType(node.getLocation()));
}
else if (inOperation && Settings.release == Release.VDM_10 && func != null && func.getAccess().getPure() && !ot.getPure())
{
TypeCheckerErrors.report(3339, "Cannot call impure operation '" + node.getRoot()
+ "' from a pure operation", node.getLocation(), node);
results.add(AstFactory.newAUnknownType(node.getLocation()));
}
else
{
results.add(operationApply(node, isSimple, ot, question));
}
if (inFunction && Settings.release == Release.VDM_10 && ot.getPure() && !inReserved)
{
TypeCheckerErrors.warning(5017, "Pure operation call may not be referentially transparent", node.getLocation(), node);
}
}
if (question.assistantFactory.createPTypeAssistant().isSeq(node.getType()))
{
SSeqType seq = question.assistantFactory.createPTypeAssistant().getSeq(node.getType());
results.add(sequenceApply(node, isSimple, seq, question));
}
if (question.assistantFactory.createPTypeAssistant().isMap(node.getType()))
{
SMapType map = question.assistantFactory.createPTypeAssistant().getMap(node.getType());
results.add(mapApply(node, isSimple, map, question));
}
if (results.isEmpty())
{
TypeCheckerErrors.report(3054, "Type " + node.getType()
+ " cannot be applied", node.getLocation(), node);
return AstFactory.newAUnknownType(node.getLocation());
}
node.setType(results.getType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType defaultSBooleanBinaryExp(SBooleanBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
node.setType(binaryCheck(node, AstFactory.newABooleanBasicType(node.getLocation()), THIS, question));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAAndBooleanBinaryExp(AAndBooleanBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
List<QualifiedDefinition> qualified = node.getLeft().apply(question.assistantFactory.getQualificationVisitor(), question);
for (QualifiedDefinition qdef : qualified)
{
qdef.qualifyType();
}
PType result = defaultSBooleanBinaryExp(node, question);
for (QualifiedDefinition qdef : qualified)
{
qdef.resetType();
}
return result;
}
@Override
public PType caseACompBinaryExp(ACompBinaryExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
noConstraint.qualifiers = null;
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PTypeSet results = new PTypeSet(question.assistantFactory);
if (question.assistantFactory.createPTypeAssistant().isMap(node.getLeft().getType()))
{
if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.report(3068, "Right hand of map 'comp' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail("Type", node.getRight().getType());
node.setType(AstFactory.newAMapMapType(node.getLocation())); // Unknown
// types
// types
return node.getType();
}
SMapType lm = question.assistantFactory.createPTypeAssistant().getMap(node.getLeft().getType());
SMapType rm = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
if (!question.assistantFactory.getTypeComparator().compatible(lm.getFrom(), rm.getTo()))
{
TypeCheckerErrors.report(3069, "Domain of left should equal range of right in map 'comp'", node.getLocation(), node);
TypeCheckerErrors.detail2("Dom", lm.getFrom(), "Rng", rm.getTo());
}
results.add(AstFactory.newAMapMapType(node.getLocation(), rm.getFrom(), lm.getTo()));
}
if (question.assistantFactory.createPTypeAssistant().isFunction(node.getLeft().getType()))
{
if (!question.assistantFactory.createPTypeAssistant().isFunction(node.getRight().getType()))
{
TypeCheckerErrors.report(3070, "Right hand of function 'comp' is not a function", node.getLocation(), node);
TypeCheckerErrors.detail("Type", node.getRight().getType());
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
} else
{
AFunctionType lf = question.assistantFactory.createPTypeAssistant().getFunction(node.getLeft().getType());
AFunctionType rf = question.assistantFactory.createPTypeAssistant().getFunction(node.getRight().getType());
if (lf.getParameters().size() != 1)
{
TypeCheckerErrors.report(3071, "Left hand function must have a single parameter", node.getLocation(), node);
TypeCheckerErrors.detail("Type", lf);
} else if (rf.getParameters().size() != 1)
{
TypeCheckerErrors.report(3072, "Right hand function must have a single parameter", node.getLocation(), node);
TypeCheckerErrors.detail("Type", rf);
} else if (!question.assistantFactory.getTypeComparator().compatible(lf.getParameters().get(0), rf.getResult()))
{
TypeCheckerErrors.report(3073, "Parameter of left should equal result of right in function 'comp'", node.getLocation(), node);
TypeCheckerErrors.detail2("Parameter", lf.getParameters().get(0), "Result", rf.getResult());
}
results.add(AstFactory.newAFunctionType(node.getLocation(), true, rf.getParameters(), lf.getResult()));
}
}
if (results.isEmpty())
{
TypeCheckerErrors.report(3074, "Left hand of 'comp' is neither a map nor a function", node.getLocation(), node);
TypeCheckerErrors.detail("Type", node.getLeft().getType());
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setType(results.getType(node.getLocation()));
return node.getType();
}
@Override
public PType caseADomainResByBinaryExp(ADomainResByBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo domConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getFrom();
domConstraint = question.newConstraint(AstFactory.newASetSetType(node.getLocation(), stype));
}
node.getLeft().apply(THIS, domConstraint);
node.getRight().apply(THIS, question);
if (!question.assistantFactory.createPTypeAssistant().isSet(node.getLeft().getType()))
{
TypeCheckerErrors.report(3079, "Left of '<-:' is not a set", node.getLocation(), node);
} else if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.report(3080, "Right of '<-:' is not a map", node.getLocation(), node);
} else
{
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(node.getLeft().getType());
SMapType map = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
if (!question.assistantFactory.getTypeComparator().compatible(set.getSetof(), map.getFrom()))
{
TypeCheckerErrors.report(3081, "Restriction of map should be set of "
+ map.getFrom(), node.getLocation(), node);
}
}
node.setType(node.getRight().getType());
return node.getType();
}
@Override
public PType caseADomainResToBinaryExp(ADomainResToBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo domConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getFrom();
domConstraint = question.newConstraint(AstFactory.newASetSetType(node.getLocation(), stype));
}
node.getLeft().apply(THIS, domConstraint);
node.getRight().apply(THIS, question);
if (!question.assistantFactory.createPTypeAssistant().isSet(node.getLeft().getType()))
{
TypeCheckerErrors.report(3082, "Left of '<:' is not a set", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", node.getLeft().getType());
} else if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.report(3083, "Right of '<:' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", node.getRight().getType());
} else
{
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(node.getLeft().getType());
SMapType map = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
if (!question.assistantFactory.getTypeComparator().compatible(set.getSetof(), map.getFrom()))
{
TypeCheckerErrors.report(3084, "Restriction of map should be set of "
+ map.getFrom(), node.getLocation(), node);
}
}
node.setType(node.getRight().getType());
return node.getType();
}
@Override
public PType caseAEqualsBinaryExp(AEqualsBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
if (!question.assistantFactory.getTypeComparator().compatible(node.getLeft().getType(), node.getRight().getType()))
{
TypeCheckerErrors.report(3087, "Left and right of '=' are incompatible types", node.getLocation(), node);
TypeCheckerErrors.detail2("Left", node.getLeft().getType(), "Right", node.getRight().getType());
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAInSetBinaryExp(AInSetBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
PType ltype = node.getLeft().apply(THIS, noConstraint);
PType rtype = node.getRight().apply(THIS, noConstraint);
if (!question.assistantFactory.createPTypeAssistant().isSet(node.getRight().getType()))
{
TypeCheckerErrors.report(3110, "Argument of 'in set' is not a set", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", rtype);
} else
{
SSetType stype = question.assistantFactory.createPTypeAssistant().getSet(rtype);
if (!question.assistantFactory.getTypeComparator().compatible(stype.getSetof(), ltype))
{
TypeCheckerErrors.report(3319, "'in set' expression is always false", node.getLocation(), node);
TypeCheckerErrors.detail2("Element", ltype, "Set", stype);
}
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAMapUnionBinaryExp(AMapUnionBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(THIS, question);
node.getRight().apply(THIS, question);
if (!question.assistantFactory.createPTypeAssistant().isMap(node.getLeft().getType()))
{
TypeCheckerErrors.report(3123, "Left hand of 'munion' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail("Type", node.getLeft().getType());
node.setType(AstFactory.newAMapMapType(node.getLocation())); // Unknown
// types
return node.getType();
} else if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.report(3124, "Right hand of 'munion' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail("Type", node.getRight().getType());
node.setType(node.getLeft().getType());
return node.getType();
} else
{
SMapType ml = question.assistantFactory.createPTypeAssistant().getMap(node.getLeft().getType());
SMapType mr = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
PTypeSet from = new PTypeSet(question.assistantFactory);
from.add(ml.getFrom());
from.add(mr.getFrom());
PTypeSet to = new PTypeSet(question.assistantFactory);
to.add(ml.getTo());
to.add(mr.getTo());
node.setType(AstFactory.newAMapMapType(node.getLocation(), from.getType(node.getLocation()), to.getType(node.getLocation())));
return node.getType();
}
}
@Override
public PType caseANotEqualBinaryExp(ANotEqualBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(THIS, question.newConstraint(null));
node.getRight().apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.getTypeComparator().compatible(node.getLeft().getType(), node.getRight().getType()))
{
TypeCheckerErrors.report(3136, "Left and right of '<>' different types", node.getLocation(), node);
TypeCheckerErrors.detail2("Left", node.getLeft().getType(), "Right", node.getRight().getType());
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseANotInSetBinaryExp(ANotInSetBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
PType ltype = node.getLeft().apply(THIS, noConstraint);
PType rtype = node.getRight().apply(THIS, noConstraint);
if (!question.assistantFactory.createPTypeAssistant().isSet(node.getRight().getType()))
{
TypeCheckerErrors.report(3138, "Argument of 'not in set' is not a set", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", node.getRight().getType());
} else
{
SSetType stype = question.assistantFactory.createPTypeAssistant().getSet(rtype);
if (!question.assistantFactory.getTypeComparator().compatible(stype.getSetof(), ltype))
{
TypeCheckerErrors.report(3320, "'not in set' expression is always true", node.getLocation(), node);
TypeCheckerErrors.detail2("Element", ltype, "Set", stype);
}
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseADivNumericBinaryExp(ADivNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseADivideNumericBinaryExp(ADivideNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newARealNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAGreaterEqualNumericBinaryExp(
AGreaterEqualNumericBinaryExp node, TypeCheckInfo question)
throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAGreaterNumericBinaryExp(AGreaterNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAModNumericBinaryExp(AModNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAPlusNumericBinaryExp(APlusNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
SNumericBasicType ln = question.assistantFactory.createPTypeAssistant().getNumeric(node.getLeft().getType());
SNumericBasicType rn = question.assistantFactory.createPTypeAssistant().getNumeric(node.getRight().getType());
if (ln instanceof ARealNumericBasicType)
{
node.setType(ln);
return ln;
} else if (rn instanceof ARealNumericBasicType)
{
node.setType(rn);
return rn;
} else if (ln instanceof AIntNumericBasicType)
{
node.setType(ln);
return ln;
} else if (rn instanceof AIntNumericBasicType)
{
node.setType(rn);
return rn;
} else if (ln instanceof ANatNumericBasicType
&& rn instanceof ANatNumericBasicType)
{
node.setType(ln);
return ln;
} else
{
node.setType(AstFactory.newANatOneNumericBasicType(ln.getLocation()));
return node.getType();
}
}
@Override
public PType caseARemNumericBinaryExp(ARemNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseASubtractNumericBinaryExp(ASubtractNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
if (node.getLeft().getType() instanceof ARealNumericBasicType
|| node.getRight().getType() instanceof ARealNumericBasicType)
{
node.setType(AstFactory.newARealNumericBasicType(node.getLocation()));
return node.getType();
} else
{
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
return node.getType();
}
}
@Override
public PType caseATimesNumericBinaryExp(ATimesNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question.newConstraint(null));
SNumericBasicType ln = question.assistantFactory.createPTypeAssistant().getNumeric(node.getLeft().getType());
SNumericBasicType rn = question.assistantFactory.createPTypeAssistant().getNumeric(node.getRight().getType());
if (ln instanceof ARealNumericBasicType)
{
node.setType(ln);
return ln;
} else if (rn instanceof ARealNumericBasicType)
{
node.setType(rn);
return rn;
} else if (ln instanceof AIntNumericBasicType)
{
node.setType(ln);
return ln;
} else if (rn instanceof AIntNumericBasicType)
{
node.setType(rn);
return rn;
} else if (ln instanceof ANatNumericBasicType)
{
node.setType(ln);
return ln;
} else if (rn instanceof ANatNumericBasicType)
{
node.setType(rn);
return rn;
} else
{
node.setType(AstFactory.newANatOneNumericBasicType(ln.getLocation()));
return node.getType();
}
}
@Override
public PType caseAPlusPlusBinaryExp(APlusPlusBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo leftcons = question.newConstraint(null);
TypeCheckInfo mapcons = question.newConstraint(null);
if (question.constraint != null && question.assistantFactory.createPTypeAssistant().isSeq(question.constraint))
{
SSeqType st = question.assistantFactory.createPTypeAssistant().getSeq(question.constraint);
mapcons = question.newConstraint(AstFactory.newAMapMapType(node.getLocation(),
AstFactory.newANatOneNumericBasicType(node.getLocation()), st.getSeqof()));
leftcons = question.newConstraint(AstFactory.newASeqSeqType(node.getLocation()));
}
else if (question.constraint != null && question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
SMapType mt = question.assistantFactory.createPTypeAssistant().getMap(question.constraint);
mapcons = question.newConstraint(mt);
leftcons = question.newConstraint(AstFactory.newAMapMapType(node.getLocation(),
mt.getFrom(), AstFactory.newAUnknownType(node.getLocation())));
}
node.getLeft().apply(THIS, leftcons);
node.getRight().apply(THIS, mapcons);
PTypeSet result = new PTypeSet(question.assistantFactory);
boolean unique = !question.assistantFactory.createPTypeAssistant().isUnion(node.getLeft().getType())
&& !question.assistantFactory.createPTypeAssistant().isUnion(node.getRight().getType());
if (question.assistantFactory.createPTypeAssistant().isMap(node.getLeft().getType()))
{
if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.concern(unique, 3141, "Right hand of '++' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail(unique, "Type", node.getRight().getType());
node.setType(AstFactory.newAMapMapType(node.getLocation())); // Unknown
// types
return node.getType();
}
SMapType lm = question.assistantFactory.createPTypeAssistant().getMap(node.getLeft().getType());
SMapType rm = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
PTypeSet domain = new PTypeSet(question.assistantFactory);
domain.add(lm.getFrom());
domain.add(rm.getFrom());
PTypeSet range = new PTypeSet(question.assistantFactory);
range.add(lm.getTo());
range.add(rm.getTo());
result.add(AstFactory.newAMapMapType(node.getLocation(), domain.getType(node.getLocation()), range.getType(node.getLocation())));
}
if (question.assistantFactory.createPTypeAssistant().isSeq(node.getLeft().getType()))
{
SSeqType st = question.assistantFactory.createPTypeAssistant().getSeq(node.getLeft().getType());
if (!question.assistantFactory.createPTypeAssistant().isMap(node.getRight().getType()))
{
TypeCheckerErrors.concern(unique, 3142, "Right hand of '++' is not a map", node.getLocation(), node);
TypeCheckerErrors.detail(unique, "Type", node.getRight().getType());
result.add(st);
}
else
{
SMapType mr = question.assistantFactory.createPTypeAssistant().getMap(node.getRight().getType());
if (!question.assistantFactory.createPTypeAssistant().isType(mr.getFrom(), SNumericBasicType.class))
{
TypeCheckerErrors.concern(unique, 3143, "Domain of right hand of '++' must be nat1", node.getLocation(), node);
TypeCheckerErrors.detail(unique, "Type", mr.getFrom());
}
PTypeSet type = new PTypeSet(question.assistantFactory);
type.add(st.getSeqof());
type.add(mr.getTo());
result.add(AstFactory.newASeqSeqType(node.getLocation(), type.getType(node.getLocation())));
}
}
if (result.isEmpty())
{
TypeCheckerErrors.report(3144, "Left of '++' is neither a map nor a sequence", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setType(result.getType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAProperSubsetBinaryExp(AProperSubsetBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (question.assistantFactory.createPTypeAssistant().isSet(ltype) &&
question.assistantFactory.createPTypeAssistant().isSet(rtype) &&
!question.assistantFactory.getTypeComparator().compatible(ltype, rtype))
{
TypeCheckerErrors.report(3335, "Subset will only be true if the LHS set is empty", node.getLocation(), node);
TypeCheckerErrors.detail("Left", ltype);
TypeCheckerErrors.detail("Right", rtype);
}
if (!question.assistantFactory.createPTypeAssistant().isSet(ltype))
{
TypeCheckerErrors.report(3146, "Left hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
}
if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3147, "Right hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseARangeResByBinaryExp(ARangeResByBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo rngConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getTo();
rngConstraint = question.newConstraint(AstFactory.newASetSetType(node.getLocation(), stype));
}
node.getLeft().apply(THIS, question);
node.getRight().apply(THIS, rngConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (!question.assistantFactory.createPTypeAssistant().isMap(ltype))
{
TypeCheckerErrors.report(3148, "Left of ':->' is not a map", node.getLocation(), node);
} else if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3149, "Right of ':->' is not a set", node.getLocation(), node);
} else
{
SMapType map = question.assistantFactory.createPTypeAssistant().getMap(ltype);
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(rtype);
if (!question.assistantFactory.getTypeComparator().compatible(set.getSetof(), map.getTo()))
{
TypeCheckerErrors.report(3150, "Restriction of map should be set of "
+ map.getTo(), node.getLocation(), node);
}
}
node.setType(ltype);
return ltype;
}
@Override
public PType caseARangeResToBinaryExp(ARangeResToBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo rngConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getTo();
rngConstraint = question.newConstraint(AstFactory.newASetSetType(node.getLocation(), stype));
}
node.getLeft().apply(THIS, question);
node.getRight().apply(THIS, rngConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (!question.assistantFactory.createPTypeAssistant().isMap(ltype))
{
TypeCheckerErrors.report(3151, "Left of ':>' is not a map", node.getLocation(), node);
} else if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3152, "Right of ':>' is not a set", node.getLocation(), node);
} else
{
SMapType map = question.assistantFactory.createPTypeAssistant().getMap(ltype);
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(rtype);
if (!question.assistantFactory.getTypeComparator().compatible(set.getSetof(), map.getTo()))
{
TypeCheckerErrors.report(3153, "Restriction of map should be set of "
+ map.getTo(), node.getLocation(), node);
}
}
node.setType(ltype);
return ltype;
}
@Override
public PType caseASeqConcatBinaryExp(ASeqConcatBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(THIS, question);
node.getRight().apply(THIS, question);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (!question.assistantFactory.createPTypeAssistant().isSeq(ltype))
{
TypeCheckerErrors.report(3157, "Left hand of '^' is not a sequence", node.getLocation(), node);
ltype = AstFactory.newASeqSeqType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation()));
}
if (!question.assistantFactory.createPTypeAssistant().isSeq(rtype))
{
TypeCheckerErrors.report(3158, "Right hand of '^' is not a sequence", node.getLocation(), node);
rtype = AstFactory.newASeqSeqType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation()));
}
PType lof = question.assistantFactory.createPTypeAssistant().getSeq(ltype);
PType rof = question.assistantFactory.createPTypeAssistant().getSeq(rtype);
boolean seq1 = lof instanceof ASeq1SeqType
|| rof instanceof ASeq1SeqType;
lof = ((SSeqType) lof).getSeqof();
rof = ((SSeqType) rof).getSeqof();
PTypeSet ts = new PTypeSet(question.assistantFactory);
ts.add(lof);
ts.add(rof);
node.setType(seq1 ? AstFactory.newASeq1SeqType(node.getLocation(), ts.getType(node.getLocation()))
: AstFactory.newASeqSeqType(node.getLocation(), ts.getType(node.getLocation())));
return node.getType();
}
@Override
public PType caseASetDifferenceBinaryExp(ASetDifferenceBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (!question.assistantFactory.createPTypeAssistant().isSet(ltype))
{
TypeCheckerErrors.report(3160, "Left hand of '\\' is not a set", node.getLocation(), node);
}
if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3161, "Right hand of '\\' is not a set", node.getLocation(), node);
}
if (!question.assistantFactory.getTypeComparator().compatible(ltype, rtype))
{
TypeCheckerErrors.report(3162, "Left and right of '\\' are different types", node.getLocation(), node);
TypeCheckerErrors.detail2("Left", ltype, "Right", rtype);
}
if (ltype instanceof ASet1SetType)
{
ASet1SetType set1 = (ASet1SetType)ltype;
ltype = AstFactory.newASetSetType(node.getLocation(), set1.getSetof());
}
node.setType(ltype);
return ltype;
}
@Override
public PType caseASetIntersectBinaryExp(ASetIntersectBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
PType lset = null;
PType rset = null;
PTypeAssistantTC assistant = question.assistantFactory.createPTypeAssistant();
if (!assistant.isSet(ltype))
{
TypeCheckerErrors.report(3163, "Left hand of " + node.getLocation()
+ " is not a set", node.getLocation(), node);
} else
{
lset = assistant.getSet(ltype).getSetof();
}
if (!assistant.isSet(rtype))
{
TypeCheckerErrors.report(3164, "Right hand of "
+ node.getLocation() + " is not a set", node.getLocation(), node);
} else
{
rset = assistant.getSet(rtype).getSetof();
}
PType result = ltype; // A guess
if (lset != null && !assistant.isUnknown(lset) && rset != null
&& !assistant.isUnknown(rset))
{
PType interTypes = question.assistantFactory.getTypeComparator().intersect(lset, rset);
if (interTypes == null)
{
TypeCheckerErrors.report(3165, "Left and right of intersect are different types", node.getLocation(), node);
TypeCheckerErrors.detail2("Left", ltype, "Right", rtype);
} else
{
result = AstFactory.newASetSetType(node.getLocation(), interTypes);
}
}
node.setType(result);
return result;
}
@Override
public PType caseASetUnionBinaryExp(ASetUnionBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(THIS, question);
node.getRight().apply(THIS, question);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (!question.assistantFactory.createPTypeAssistant().isSet(ltype))
{
TypeCheckerErrors.report(3168, "Left hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
ltype = AstFactory.newASetSetType(node.getLocation());
}
if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3169, "Right hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
rtype = AstFactory.newASetSetType(node.getLocation());
}
PType lof = question.assistantFactory.createPTypeAssistant().getSet(ltype).getSetof();
PType rof = question.assistantFactory.createPTypeAssistant().getSet(rtype).getSetof();
boolean set1 = lof instanceof ASet1SetType || rof instanceof ASet1SetType;
PTypeSet result = new PTypeSet(question.assistantFactory);
result.add(lof);
result.add(rof);
node.setType(set1 ?
AstFactory.newASet1SetType(node.getLocation(), result.getType(node.getLocation())) :
AstFactory.newASetSetType(node.getLocation(), result.getType(node.getLocation())));
return node.getType();
}
@Override
public PType caseAStarStarBinaryExp(AStarStarBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (question.assistantFactory.createPTypeAssistant().isMap(ltype))
{
question.assistantFactory.createPTypeAssistant();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(rtype))
{
// rtype.report(3170,
// "Map iterator expects nat as right hand arg");
TypeCheckerErrors.report(3170, "Map iterator expects nat as right hand arg", rtype.getLocation(), rtype);
}
} else if (question.assistantFactory.createPTypeAssistant().isFunction(ltype))
{
question.assistantFactory.createPTypeAssistant();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(rtype))
{
TypeCheckerErrors.report(3171, "Function iterator expects nat as right hand arg", rtype.getLocation(), rtype);
}
} else
{
question.assistantFactory.createPTypeAssistant();
if (question.assistantFactory.createPTypeAssistant().isNumeric(ltype))
{
question.assistantFactory.createPTypeAssistant();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(rtype))
{
TypeCheckerErrors.report(3172, "'**' expects number as right hand arg", rtype.getLocation(), rtype);
}
} else
{
TypeCheckerErrors.report(3173, "First arg of '**' must be a map, function or number", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
}
node.setType(ltype);
return ltype;
}
@Override
public PType caseASubsetBinaryExp(ASubsetBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
node.getLeft().apply(THIS, noConstraint);
node.getRight().apply(THIS, noConstraint);
PType ltype = node.getLeft().getType();
PType rtype = node.getRight().getType();
if (question.assistantFactory.createPTypeAssistant().isSet(ltype) &&
question.assistantFactory.createPTypeAssistant().isSet(rtype) &&
!question.assistantFactory.getTypeComparator().compatible(ltype, rtype))
{
TypeCheckerErrors.report(3335, "Subset will only be true if the LHS set is empty", node.getLocation(), node);
TypeCheckerErrors.detail("Left", ltype);
TypeCheckerErrors.detail("Right", rtype);
}
if (!question.assistantFactory.createPTypeAssistant().isSet(ltype))
{
TypeCheckerErrors.report(3177, "Left hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
TypeCheckerErrors.detail("Type", ltype);
}
if (!question.assistantFactory.createPTypeAssistant().isSet(rtype))
{
TypeCheckerErrors.report(3178, "Right hand of " + node.getOp()
+ " is not a set", node.getLocation(), node);
TypeCheckerErrors.detail("Type", rtype);
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseABooleanConstExp(ABooleanConstExp node,
TypeCheckInfo question)
{
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseACasesExp(ACasesExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
question.qualifiers = null;
PType expType = node.getExpression().apply(THIS, noConstraint);
PTypeSet rtypes = new PTypeSet(question.assistantFactory);
for (ACaseAlternative c : node.getCases())
{
rtypes.add(typeCheck(c, THIS, question, expType));
}
if (node.getOthers() != null)
{
rtypes.add(node.getOthers().apply(THIS, question));
}
node.setType(rtypes.getType(node.getLocation()));
return node.getType();
}
@Override
public PType caseACharLiteralExp(ACharLiteralExp node,
TypeCheckInfo question)
{
node.setType(AstFactory.newACharBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAElseIfExp(AElseIfExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setType(typeCheckAElseIf(node, node.getLocation(), node.getElseIf(), node.getThen(), question));
return node.getType();
}
@Override
public PType caseAExists1Exp(AExists1Exp node, TypeCheckInfo question)
throws AnalysisException
{
node.setDef(AstFactory.newAMultiBindListDefinition(node.getBind().getLocation(), question.assistantFactory.createPBindAssistant().getMultipleBindList(node.getBind())));
node.getDef().apply(THIS, question.newConstraint(null));
Environment local = new FlatCheckedEnvironment(question.assistantFactory, node.getDef(), question.env, question.scope);
if (node.getBind() instanceof ATypeBind)
{
ATypeBind tb = (ATypeBind) node.getBind();
question.assistantFactory.createATypeBindAssistant().typeResolve(tb, THIS, question);
}
question.qualifiers = null;
if (!question.assistantFactory.createPTypeAssistant().isType(node.getPredicate().apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null)), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3088, "Predicate is not boolean", node.getPredicate().getLocation(), node.getPredicate());
}
local.unusedCheck();
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAExistsExp(AExistsExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getLocation(), node.getBindList());
def.apply(THIS, question.newConstraint(null));
def.setNameScope(NameScope.LOCAL);
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
question = new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null);
if (!question.assistantFactory.createPTypeAssistant().isType(node.getPredicate().apply(THIS, question), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3089, "Predicate is not boolean", node.getPredicate().getLocation(), node.getPredicate());
}
local.unusedCheck();
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAFieldExp(AFieldExp node, TypeCheckInfo question)
throws AnalysisException
{
PType root = node.getObject().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, question.scope));
if (question.assistantFactory.createPTypeAssistant().isUnknown(root))
{
node.setMemberName(new LexNameToken("?", node.getField()));
node.setType(root);
return root;
}
PTypeSet results = new PTypeSet(question.assistantFactory);
boolean recOrClass = false;
boolean unique = !question.assistantFactory.createPTypeAssistant().isUnion(root);
if (question.assistantFactory.createPTypeAssistant().isRecord(root))
{
ARecordInvariantType rec = question.assistantFactory.createPTypeAssistant().getRecord(root);
AFieldField cf = question.assistantFactory.createARecordInvariantTypeAssistant().findField(rec, node.getField().getName());
if (cf != null)
{
results.add(cf.getType());
} else
{
TypeCheckerErrors.concern(unique, 3090, "Unknown field "
+ node.getField().getName() + " in record "
+ rec.getName(), node.getField().getLocation(), node.getField());
}
recOrClass = true;
}
if (question.env.isVDMPP()
&& question.assistantFactory.createPTypeAssistant().isClass(root, question.env))
{
AClassType cls = question.assistantFactory.createPTypeAssistant().getClassType(root, question.env);
ILexNameToken memberName = node.getMemberName();
if (memberName == null)
{
memberName = question.assistantFactory.createAClassTypeAssistant().getMemberName(cls, node.getField());
node.setMemberName(memberName);
}
memberName.setTypeQualifier(question.qualifiers);
PDefinition encl = question.env.getEnclosingDefinition();
NameScope findScope = question.scope;
if (encl != null && question.assistantFactory.createPDefinitionAssistant().isFunction(encl))
{
findScope = NameScope.VARSANDNAMES; // Allow fields as well in functions
}
PDefinition fdef = question.assistantFactory.createAClassTypeAssistant().findName(cls, memberName, findScope);
if (fdef == null)
{
// The field may be a map or sequence, which would not
// have the type qualifier of its arguments in the name...
List<PType> oldq = memberName.getTypeQualifier();
memberName.setTypeQualifier(null);
fdef = // cls.apply(question.assistantFactory.getNameFinder(), new NameFinder.Newquestion(memberName,
// question.scope));
question.assistantFactory.createAClassTypeAssistant().findName(cls, memberName, question.scope);
memberName.setTypeQualifier(oldq); // Just for error text!
}
if (fdef == null && memberName.getTypeQualifier() == null)
{
// We might be selecting a bare function or operation, without
// applying it (ie. no qualifiers). In this case, if there is
// precisely one possibility, we choose it.
for (PDefinition possible : question.env.findMatches(memberName))
{
if (question.assistantFactory.createPDefinitionAssistant().isFunctionOrOperation(possible))
{
if (fdef != null)
{
fdef = null; // Alas, more than one
break;
} else
{
fdef = possible;
}
}
}
}
if (fdef == null)
{
TypeCheckerErrors.concern(unique, 3091, "Unknown member "
+ memberName + " of class " + cls.getName().getName(), node.getField().getLocation(), node.getField());
if (unique)
{
question.env.listAlternatives(memberName);
}
} else if (question.assistantFactory.createSClassDefinitionAssistant().isAccessible(question.env, fdef, false))
{
// The following gives lots of warnings for self.value access
// to values as though they are fields of self in the CSK test
// suite, so commented out for now.
if (question.assistantFactory.createPDefinitionAssistant().isStatic(fdef))// && !env.isStatic())
{
// warning(5005, "Should access member " + field +
// " from a static context");
}
results.add(question.assistantFactory.createPDefinitionAssistant().getType(fdef));
// At runtime, type qualifiers must match exactly
memberName.setTypeQualifier(fdef.getName().getTypeQualifier());
} else
{
TypeCheckerErrors.concern(unique, 3092, "Inaccessible member "
+ memberName + " of class " + cls.getName().getName(), node.getField().getLocation(), node.getField());
}
recOrClass = true;
}
if (results.isEmpty())
{
if (!recOrClass)
{
TypeCheckerErrors.report(3093, "Field '"
+ node.getField().getName()
+ "' applied to non-aggregate type", node.getObject().getLocation(), node.getObject());
}
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
PType resType = results.getType(node.getLocation());
node.setType(resType);
return node.getType();
}
@Override
public PType caseAFieldNumberExp(AFieldNumberExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp tuple = node.getTuple();
question.qualifiers = null;
PType type = tuple.apply(THIS, question.newConstraint(null));
node.setType(type);
if (!question.assistantFactory.createPTypeAssistant().isProduct(type))
{
TypeCheckerErrors.report(3094, "Field '#" + node.getField()
+ "' applied to non-tuple type", tuple.getLocation(), tuple);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
AProductType product = question.assistantFactory.createPTypeAssistant().getProduct(type);
long fn = node.getField().getValue();
if (fn > product.getTypes().size() || fn < 1)
{
TypeCheckerErrors.report(3095, "Field number does not match tuple size", node.getField().getLocation(), node.getField());
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setType(product.getTypes().get((int) fn - 1));
return node.getType();
}
@Override
public PType caseAForAllExp(AForAllExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getLocation(), node.getBindList());
def.apply(THIS, question.newConstraint(null));
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
if (!question.assistantFactory.createPTypeAssistant().isType(node.getPredicate().apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null)), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3097, "Predicate is not boolean", node.getPredicate().getLocation(), node.getPredicate());
}
local.unusedCheck();
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAFuncInstatiationExp(AFuncInstatiationExp node,
TypeCheckInfo question) throws AnalysisException
{
// If there are no type qualifiers passed because the poly function
// value
// is being accessed alone (not applied). In this case, the null
// qualifier
// will cause VariableExpression to search for anything that matches the
// name alone. If there is precisely one, it is selected; if there are
// several, this is an ambiguity error.
//
// Note that a poly function is hard to identify from the actual types
// passed here because the number of parameters may not equal the number
// of type parameters.
PType ftype = node.getFunction().apply(THIS, question.newConstraint(null));
if (question.assistantFactory.createPTypeAssistant().isUnknown(ftype))
{
node.setType(ftype);
return ftype;
}
if (question.assistantFactory.createPTypeAssistant().isFunction(ftype))
{
AFunctionType t = question.assistantFactory.createPTypeAssistant().getFunction(ftype);
PTypeSet set = new PTypeSet(question.assistantFactory);
if (t.getDefinitions().size() == 0)
{
TypeCheckerErrors.report(3098, "Function value is not polymorphic", node.getLocation(), node);
set.add(AstFactory.newAUnknownType(node.getLocation()));
} else
{
boolean serious = t.getDefinitions().size() == 1;
for (PDefinition def : t.getDefinitions()) // Possibly a union
// of several
{
List<ILexNameToken> typeParams = null;
def = question.assistantFactory.createPDefinitionAssistant().deref(def);
if (def instanceof AExplicitFunctionDefinition)
{
node.setExpdef((AExplicitFunctionDefinition) def);
typeParams = node.getExpdef().getTypeParams();
} else if (def instanceof AImplicitFunctionDefinition)
{
node.setImpdef((AImplicitFunctionDefinition) def);
typeParams = node.getImpdef().getTypeParams();
} else
{
TypeCheckerErrors.report(3099, "Polymorphic function is not in scope", node.getLocation(), node);
continue;
}
if (typeParams.size() == 0)
{
TypeCheckerErrors.concern(serious, 3100, "Function has no type parameters", node.getLocation(), node);
continue;
}
if (node.getActualTypes().size() != typeParams.size())
{
TypeCheckerErrors.concern(serious, 3101, "Expecting "
+ typeParams.size() + " type parameters", node.getLocation(), node);
continue;
}
List<PType> fixed = new Vector<PType>();
for (PType ptype : node.getActualTypes())
{
if (ptype instanceof AParameterType) // Recursive
// polymorphism
{
AParameterType pt = (AParameterType) ptype;
PDefinition d = question.env.findName(pt.getName(), question.scope);
if (d == null)
{
TypeCheckerErrors.report(3102, "Parameter name "
+ pt + " not defined", node.getLocation(), node);
ptype = AstFactory.newAUnknownType(node.getLocation());
} else
{
ptype = d.getType();
}
}
ptype = question.assistantFactory.createPTypeAssistant().typeResolve(ptype, null, THIS, question);
fixed.add(ptype);
question.assistantFactory.getTypeComparator().checkComposeTypes(ptype, question.env, false);
}
node.setActualTypes(fixed);
node.setType(node.getExpdef() == null ? question.assistantFactory.createAImplicitFunctionDefinitionAssistant().getType(node.getImpdef(), node.getActualTypes())
: question.assistantFactory.createAExplicitFunctionDefinitionAssistant().getType(node.getExpdef(), node.getActualTypes()));
// type = expdef == null ?
// impdef.getType(actualTypes) :
// expdef.getType(actualTypes);
set.add(node.getType());
}
}
if (!set.isEmpty())
{
node.setType(set.getType(node.getLocation()));
return node.getType();
}
} else
{
TypeCheckerErrors.report(3103, "Function instantiation does not yield a function", node.getLocation(), node);
}
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAHistoryExp(AHistoryExp node, TypeCheckInfo question)
{
SClassDefinition classdef = question.env.findClassDefinition();
for (ILexNameToken opname : node.getOpnames())
{
int found = 0;
List<PDefinition> allDefs = (List<PDefinition>) classdef.getDefinitions().clone();
allDefs.addAll(classdef.getAllInheritedDefinitions());
for (PDefinition def : allDefs)
{
if (def.getName() != null && def.getName().matches(opname))
{
found++;
if (!question.assistantFactory.createPDefinitionAssistant().isCallableOperation(def))
{
TypeCheckerErrors.report(3105, opname
+ " is not an explicit operation", opname.getLocation(), opname);
}
if (def.getAccess().getPure())
{
TypeCheckerErrors.report(3342, "Cannot use history counters for pure operations", opname.getLocation(), opname);
}
if (def.getAccess().getStatic() == null && question.env.isStatic())
{
TypeCheckerErrors.report(3349,
"Cannot see non-static operation from static context", opname.getLocation(), opname);
}
}
}
if (found == 0)
{
TypeCheckerErrors.report(3106, opname + " is not in scope", opname.getLocation(), opname);
} else if (found > 1)
{
TypeCheckerErrors.warning(5004, "History expression of overloaded operation", opname.getLocation(), opname);
}
if (opname.getName().equals(classdef.getName().getName()))
{
TypeCheckerErrors.report(3107, "Cannot use history of a constructor", opname.getLocation(), opname);
}
}
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAIfExp(AIfExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setType(typeCheckIf(node.getLocation(), node.getTest(), node.getThen(), node.getElseList(), node.getElse(), question));// rtypes.getType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAIntLiteralExp(AIntLiteralExp node, TypeCheckInfo question)
{
if (node.getValue().getValue() < 0)
{
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
} else if (node.getValue().getValue() == 0)
{
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
} else
{
node.setType(AstFactory.newANatOneNumericBasicType(node.getLocation()));
}
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAIotaExp(AIotaExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getLocation(), question.assistantFactory.createPBindAssistant().getMultipleBindList(node.getBind()));
def.apply(THIS, question.newConstraint(null));
PType rt = null;
PBind bind = node.getBind();
if (bind instanceof ASetBind)
{
ASetBind sb = (ASetBind) bind;
question.qualifiers = null;
rt = sb.getSet().apply(THIS, question.newConstraint(null));
if (question.assistantFactory.createPTypeAssistant().isSet(rt))
{
rt = question.assistantFactory.createPTypeAssistant().getSet(rt).getSetof();
}
else
{
TypeCheckerErrors.report(3112, "Iota set bind is not a set", node.getLocation(), node);
}
}
else if (bind instanceof ASeqBind)
{
ASeqBind sb = (ASeqBind) bind;
question.qualifiers = null;
rt = sb.getSeq().apply(THIS, question.newConstraint(null));
if (question.assistantFactory.createPTypeAssistant().isSeq(rt))
{
rt = question.assistantFactory.createPTypeAssistant().getSeq(rt).getSeqof();
}
else
{
TypeCheckerErrors.report(3112, "Iota seq bind is not a sequence", node.getLocation(), node);
}
}
else
{
ATypeBind tb = (ATypeBind) bind;
question.assistantFactory.createATypeBindAssistant().typeResolve(tb, THIS, question);
rt = tb.getType();
}
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
question.qualifiers = null;
if (!question.assistantFactory.createPTypeAssistant().isType(node.getPredicate().apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null)), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3088, "Predicate is not boolean", node.getPredicate().getLocation(), node.getPredicate());
}
local.unusedCheck();
node.setType(rt);
return rt;
}
@Override
public PType caseAIsExp(AIsExp node, TypeCheckInfo question)
throws AnalysisException
{
question.qualifiers = null;
node.getTest().apply(THIS, question.newConstraint(null));
PType basictype = node.getBasicType();
if (basictype != null)
{
basictype = question.assistantFactory.createPTypeAssistant().typeResolve(basictype, null, THIS, question);
question.assistantFactory.getTypeComparator().checkComposeTypes(basictype, question.env, false);
}
ILexNameToken typename = node.getTypeName();
if (typename != null)
{
PDefinition typeFound = question.env.findType(typename, node.getLocation().getModule());
if (typeFound == null)
{
TypeCheckerErrors.report(3113, "Unknown type name '" + typename
+ "'", node.getLocation(), node);
}
else
{
node.setTypedef(typeFound.clone());
}
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAIsOfBaseClassExp(AIsOfBaseClassExp node,
TypeCheckInfo question) throws AnalysisException
{
if (question.env.findType(node.getBaseClass(), null) == null)
{
TypeCheckerErrors.report(3114, "Undefined base class type: "
+ node.getBaseClass().getName(), node.getLocation(), node);
}
question.qualifiers = null;
PType rt = node.getExp().apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(rt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", node.getExp().getLocation(), node.getExp());
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAIsOfClassExp(AIsOfClassExp node, TypeCheckInfo question)
throws AnalysisException
{
ILexNameToken classname = node.getClassName();
PDefinition cls = question.env.findType(classname, null);
if (cls == null || !(cls instanceof SClassDefinition))
{
TypeCheckerErrors.report(3115, "Undefined class type: "
+ classname.getName(), node.getLocation(), node);
} else
{
node.setClassType((AClassType) cls.getType());
}
question.qualifiers = null;
PType rt = node.getExp().apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(rt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", node.getExp().getLocation(), node.getExp());
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseALambdaExp(ALambdaExp node, TypeCheckInfo question)
throws AnalysisException
{
List<PMultipleBind> mbinds = new Vector<PMultipleBind>();
List<PType> ptypes = new Vector<PType>();
List<PPattern> paramPatterns = new Vector<PPattern>();
List<PDefinition> paramDefinitions = new Vector<PDefinition>();
// node.setParamPatterns(paramPatterns);
for (ATypeBind tb : node.getBindList())
{
mbinds.addAll(tb.apply(question.assistantFactory.getMultipleBindLister()));
paramDefinitions.addAll(question.assistantFactory.createPPatternAssistant().getDefinitions(tb.getPattern(), tb.getType(), NameScope.LOCAL));
paramPatterns.add(tb.getPattern());
tb.setType(question.assistantFactory.createPTypeAssistant().typeResolve(tb.getType(), null, THIS, question));
ptypes.add(tb.getType());
}
node.setParamPatterns(paramPatterns);
question.assistantFactory.createPDefinitionListAssistant().implicitDefinitions(paramDefinitions, question.env);
question.assistantFactory.createPDefinitionListAssistant().typeCheck(paramDefinitions, THIS, question);
node.setParamDefinitions(paramDefinitions);
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getLocation(), mbinds);
def.apply(THIS, question.newConstraint(null));
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
local.setFunctional(true);
local.setEnclosingDefinition(def); // Prevent recursive checks
TypeCheckInfo newInfo = new TypeCheckInfo(question.assistantFactory, local, question.scope);
PType result = node.getExpression().apply(THIS, newInfo);
local.unusedCheck();
node.setType(AstFactory.newAFunctionType(node.getLocation(), true, ptypes, result));
return node.getType();
}
@Override
public PType caseALetBeStExp(ALetBeStExp node, TypeCheckInfo question)
throws AnalysisException
{
Entry<PType, AMultiBindListDefinition> res = typecheckLetBeSt(node, node.getLocation(), node.getBind(), node.getSuchThat(), node.getValue(), question);
node.setDef(res.getValue());
node.setType(res.getKey());
return node.getType();
}
@Override
public PType caseALetDefExp(ALetDefExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setType(typeCheckLet(node, node.getLocalDefs(), node.getExpression(), question));
return node.getType();
}
@Override
public PType caseADefExp(ADefExp node, TypeCheckInfo question)
throws AnalysisException
{
// Each local definition is in scope for later local definitions...
Environment local = question.env;
for (PDefinition d : node.getLocalDefs())
{
if (d instanceof AExplicitFunctionDefinition)
{
// Functions' names are in scope in their bodies, whereas
// simple variable declarations aren't
local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative
question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local);
TypeCheckInfo newQuestion = new TypeCheckInfo(question.assistantFactory, local, question.scope);
question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, question);
if (question.env.isVDMPP())
{
SClassDefinition cdef = question.env.findClassDefinition();
d.setClassDefinition(cdef);
d.setAccess(question.assistantFactory.createPAccessSpecifierAssistant().getStatic(d, true));
}
d.apply(THIS, newQuestion);
} else
{
question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local);
question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
d.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative
}
}
PType r = node.getExpression().apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, question.constraint, null));
local.unusedCheck(question.env);
node.setType(r);
return r;
}
@Override
public PType caseAMapCompMapExp(AMapCompMapExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getLocation(), node.getBindings());
def.apply(THIS, question.newConstraint(null));
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
PExp predicate = node.getPredicate();
TypeCheckInfo pquestion = new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null);
if (predicate != null
&& !question.assistantFactory.createPTypeAssistant().isType(predicate.apply(THIS, pquestion), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3118, "Predicate is not boolean", predicate.getLocation(), predicate);
}
node.setType(node.getFirst().apply(THIS, question.newInfo(local)));
local.unusedCheck();
return node.getType();
}
@Override
public PType caseAMapEnumMapExp(AMapEnumMapExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setDomTypes(new Vector<PType>());
node.setRngTypes(new Vector<PType>());
if (node.getMembers().isEmpty())
{
node.setType(AstFactory.newAMapMapType(node.getLocation()));
return node.getType();
}
PTypeSet dom = new PTypeSet(question.assistantFactory);
PTypeSet rng = new PTypeSet(question.assistantFactory);
for (AMapletExp ex : node.getMembers())
{
PType mt = ex.apply(THIS, question);
if (!question.assistantFactory.createPTypeAssistant().isMap(mt))
{
TypeCheckerErrors.report(3121, "Element is not of maplet type", node.getLocation(), node);
} else
{
SMapType maplet = question.assistantFactory.createPTypeAssistant().getMap(mt);
dom.add(maplet.getFrom());
node.getDomTypes().add(maplet.getFrom());
rng.add(maplet.getTo());
node.getRngTypes().add(maplet.getTo());
}
}
node.setType(AstFactory.newAMapMapType(node.getLocation(), dom.getType(node.getLocation()), rng.getType(node.getLocation())));
return node.getType();
}
@Override
public PType caseAMapletExp(AMapletExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo domConstraint = question;
TypeCheckInfo rngConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isMap(question.constraint))
{
PType dtype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getFrom();
domConstraint = question.newConstraint(dtype);
PType rtype = question.assistantFactory.createPTypeAssistant().getMap(question.constraint).getTo();
rngConstraint = question.newConstraint(rtype);
}
PType ltype = node.getLeft().apply(THIS, domConstraint);
PType rtype = node.getRight().apply(THIS, rngConstraint);
node.setType(AstFactory.newAMapMapType(node.getLocation(), ltype, rtype));
return node.getType();
}
@Override
public PType caseAMkBasicExp(AMkBasicExp node, TypeCheckInfo question)
throws AnalysisException
{
PType argtype = node.getArg().apply(THIS, question.newConstraint(null));
if (!(node.getType() instanceof ATokenBasicType)
&& !question.assistantFactory.createPTypeAssistant().equals(argtype, node.getType()))
{
TypeCheckerErrors.report(3125, "Argument of mk_" + node.getType()
+ " is the wrong type", node.getLocation(), node);
}
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAMkTypeExp(AMkTypeExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition typeDef = question.env.findType(node.getTypeName(), node.getLocation().getModule());
if (typeDef == null)
{
TypeCheckerErrors.report(3126, "Unknown type '"
+ node.getTypeName() + "' in constructor", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
PType rec = null;
if (typeDef instanceof ATypeDefinition)
{
rec = ((ATypeDefinition) typeDef).getType();
} else if (typeDef instanceof AStateDefinition)
{
rec = ((AStateDefinition) typeDef).getRecordType();
} else
{
rec = question.assistantFactory.createPDefinitionAssistant().getType(typeDef);
}
if (!(rec instanceof ARecordInvariantType))
{
TypeCheckerErrors.report(3127, "Type '" + node.getTypeName()
+ "' is not a record type", node.getLocation(), node);
node.setType(rec);
return rec;
}
node.setRecordType((ARecordInvariantType) rec);
if (node.getRecordType().getOpaque())
{
TypeCheckerErrors.report(3127, "Type '" + node.getTypeName()
+ "' is not a record type", node.getLocation(), node);
node.setType(rec);
return rec;
}
if (node.getTypeName().getExplicit())
{
// If the type name is explicit, the Type ought to have an explicit
// name. This only really affects trace expansion.
ARecordInvariantType recordType = node.getRecordType();
AExplicitFunctionDefinition inv = recordType.getInvDef();
recordType = AstFactory.newARecordInvariantType(recordType.getName().getExplicit(true), recordType.getFields());
recordType.setInvDef(inv);
node.setRecordType(recordType);
}
if (node.getRecordType().getFields().size() != node.getArgs().size())
{
TypeCheckerErrors.report(3128, "Record and constructor do not have same number of fields", node.getLocation(), node);
node.setType(rec);
return rec;
}
int i = 0;
Iterator<AFieldField> fiter = node.getRecordType().getFields().iterator();
node.setArgTypes(new LinkedList<PType>());
List<PType> argTypes = node.getArgTypes();
for (PExp arg : node.getArgs())
{
PType fieldType = fiter.next().getType();
PType argType = arg.apply(THIS, question.newConstraint(fieldType));
i++;
if (!question.assistantFactory.getTypeComparator().compatible(fieldType, argType))
{
TypeCheckerErrors.report(3129, "Constructor field " + i
+ " is of wrong type", node.getLocation(), node);
TypeCheckerErrors.detail2("Expected", fieldType, "Actual", argType);
}
argTypes.add(argType);
}
node.setType(node.getRecordType().clone());
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getRecordType(), node.getLocation());
}
@Override
public PType caseAMuExp(AMuExp node, TypeCheckInfo question)
throws AnalysisException
{
PType rtype = node.getRecord().apply(THIS, question.newConstraint(null));
if (question.assistantFactory.createPTypeAssistant().isUnknown(rtype))
{
node.setType(rtype);
return rtype;
}
if (question.assistantFactory.createPTypeAssistant().isRecord(rtype))
{
node.setRecordType(question.assistantFactory.createPTypeAssistant().getRecord(rtype));
node.setModTypes(new LinkedList<PType>());
List<PType> modTypes = node.getModTypes();
for (ARecordModifier rm : node.getModifiers())
{
PType mtype = rm.getValue().apply(THIS, question.newConstraint(null));
modTypes.add(mtype);
AFieldField f = question.assistantFactory.createARecordInvariantTypeAssistant().findField(node.getRecordType(), rm.getTag().getName());
if (f != null)
{
if (!question.assistantFactory.getTypeComparator().compatible(f.getType(), mtype))
{
TypeCheckerErrors.report(3130, "Modifier for "
+ f.getTag() + " should be " + f.getType(), node.getLocation(), node);
TypeCheckerErrors.detail("Actual", mtype);
}
} else
{
TypeCheckerErrors.report(3131, "Modifier tag "
+ rm.getTag() + " not found in record", node.getLocation(), node);
}
}
} else
{
TypeCheckerErrors.report(3132, "mu operation on non-record type", node.getLocation(), node);
}
node.setType(rtype);
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, rtype, node.getLocation());
}
@Override
public PType caseANarrowExp(ANarrowExp node, TypeCheckInfo question)
throws AnalysisException
{
node.getTest().setType(node.getTest().apply(THIS, question.newConstraint(null)));
PType result = null;
if (node.getBasicType() != null)
{
node.setBasicType(question.assistantFactory.createPTypeAssistant().typeResolve(node.getBasicType(), null, THIS, question));
result = node.getBasicType();
question.assistantFactory.getTypeComparator().checkComposeTypes(result, question.env, false);
} else
{
node.setTypedef(question.env.findType(node.getTypeName(), node.getLocation().getModule()));
if (node.getTypedef() == null)
{
TypeCheckerErrors.report(3113, "Unknown type name '"
+ node.getTypeName() + "'", node.getLocation(), node);
result = AstFactory.newAUnknownType(node.getLocation());
} else
{
result = question.assistantFactory.createPDefinitionAssistant().getType(node.getTypedef());
}
}
if (!question.assistantFactory.getTypeComparator().compatible(result, node.getTest().getType()))
{
TypeCheckerErrors.report(3317, "Expression can never match narrow type", node.getLocation(), node);
}
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, result, node.getLocation());
}
@Override
public PType caseANewExp(ANewExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition cdef = question.env.findType(node.getClassName().getClassName(), null);
if (cdef == null || !(cdef instanceof SClassDefinition))
{
TypeCheckerErrors.report(3133, "Class name " + node.getClassName()
+ " not in scope", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
if (Settings.release == Release.VDM_10 && question.env.isFunctional())
{
TypeCheckerErrors.report(3348, "Cannot use 'new' in a functional context", node.getLocation(), node);
}
node.setClassdef((SClassDefinition) cdef);
SClassDefinition classdef = node.getClassdef();
if (classdef instanceof ASystemClassDefinition)
{
TypeCheckerErrors.report(3279, "Cannot instantiate system class "
+ classdef.getName(), node.getLocation(), node);
}
if (classdef.getIsAbstract())
{
TypeCheckerErrors.report(3330, "Cannot instantiate abstract class "
+ classdef.getName(), node.getLocation(), node);
PDefinitionAssistantTC assistant = question.assistantFactory.createPDefinitionAssistant();
List<PDefinition> localDefs = new LinkedList<PDefinition>();
localDefs.addAll(classdef.getDefinitions());
localDefs.addAll(classdef.getLocalInheritedDefinitions());
for (PDefinition d : localDefs)
{
if (assistant.isSubclassResponsibility(d))
{
TypeCheckerErrors.detail("Unimplemented", d.getName().getName()
+ d.getType());
}
}
}
List<PType> argtypes = new LinkedList<PType>();
for (PExp a : node.getArgs())
{
argtypes.add(a.apply(THIS, question.newConstraint(null)));
}
PDefinition opdef = question.assistantFactory.createSClassDefinitionAssistant().findConstructor(classdef, argtypes);
if (opdef == null)
{
if (!node.getArgs().isEmpty()) // Not having a default ctor is OK
{
TypeCheckerErrors.report(3134, "Class has no constructor with these parameter types", node.getLocation(), node);
question.assistantFactory.createSClassDefinitionAssistant();
TypeCheckerErrors.detail("Called", SClassDefinitionAssistantTC.getCtorName(classdef, argtypes));
} else if (classdef instanceof ACpuClassDefinition
|| classdef instanceof ABusClassDefinition)
{
TypeCheckerErrors.report(3297, "Cannot use default constructor for this class", node.getLocation(), node);
}
} else
{
if (!question.assistantFactory.createPDefinitionAssistant().isCallableOperation(opdef))
{
TypeCheckerErrors.report(3135, "Class has no constructor with these parameter types", node.getLocation(), node);
question.assistantFactory.createSClassDefinitionAssistant();
TypeCheckerErrors.detail("Called", SClassDefinitionAssistantTC.getCtorName(classdef, argtypes));
} else if (!question.assistantFactory.createSClassDefinitionAssistant().isAccessible(question.env, opdef, false))
{
TypeCheckerErrors.report(3292, "Constructor is not accessible", node.getLocation(), node);
question.assistantFactory.createSClassDefinitionAssistant();
TypeCheckerErrors.detail("Called", SClassDefinitionAssistantTC.getCtorName(classdef, argtypes));
} else
{
node.setCtorDefinition(opdef);
}
}
PType type = question.assistantFactory.createPDefinitionAssistant().getType(classdef);
node.setType(type);
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, type, node.getLocation());
}
@Override
public PType caseANilExp(ANilExp node, TypeCheckInfo question)
{
node.setType(AstFactory.newAOptionalType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation())));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseANotYetSpecifiedExp(ANotYetSpecifiedExp node,
TypeCheckInfo question)
{
node.setType(typeCheckANotYetSpecifiedExp(node, node.getLocation()));
return node.getType();
}
@Override
public PType caseAPostOpExp(APostOpExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setType(node.getPostexpression().apply(THIS, question.newConstraint(null)));
return node.getType();
}
@Override
public PType caseAPreExp(APreExp node, TypeCheckInfo question)
throws AnalysisException
{
node.getFunction().apply(THIS, question.newConstraint(null));
for (PExp a : node.getArgs())
{
question.qualifiers = null;
a.apply(THIS, question.newConstraint(null));
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAPreOpExp(APreOpExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setType(node.getExpression().apply(THIS, question.newConstraint(null)));
return node.getType();
}
@Override
public PType caseAQuoteLiteralExp(AQuoteLiteralExp node,
TypeCheckInfo question)
{
node.setType(AstFactory.newAQuoteType(node.getValue().clone()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseARealLiteralExp(ARealLiteralExp node,
TypeCheckInfo question)
{
ILexRealToken value = node.getValue();
if (Math.round(value.getValue()) == value.getValue())
{
if (value.getValue() < 0)
{
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
} else if (value.getValue() == 0)
{
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
} else
{
node.setType(AstFactory.newANatOneNumericBasicType(node.getLocation()));
}
} else
{
node.setType(AstFactory.newARationalNumericBasicType(node.getLocation()));
}
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseASameBaseClassExp(ASameBaseClassExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp left = node.getLeft();
PExp right = node.getRight();
question.qualifiers = null;
PType lt = left.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(lt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", left.getLocation(), left);
}
question.qualifiers = null;
PType rt = right.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(rt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", right.getLocation(), right);
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseASameClassExp(ASameClassExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp left = node.getLeft();
PExp right = node.getRight();
question.qualifiers = null;
PType lt = left.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(lt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", left.getLocation(), left);
}
question.qualifiers = null;
PType rt = right.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isClass(rt, question.env))
{
TypeCheckerErrors.report(3266, "Argument is not an object", right.getLocation(), right);
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseASelfExp(ASelfExp node, TypeCheckInfo question)
{
PDefinition cdef = question.env.findName(node.getName(), question.scope);
if (cdef == null)
{
TypeCheckerErrors.report(3154, node.getName() + " not in scope", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setType(cdef.getType());
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseASeqCompSeqExp(ASeqCompSeqExp node, TypeCheckInfo question)
throws AnalysisException
{
// TODO: check if this is still needed?!
// save these so we can clone them after they have been type checked
// PExp setBindSet = node.getSetBind().getSet();
// PPattern setBindPattern = node.getSetBind().getPattern();
//
// List<PPattern> plist = new ArrayList<PPattern>();
// plist.add(setBindPattern);
// List<PMultipleBind> mblist = new Vector<PMultipleBind>();
// mblist.add(new ASetMultipleBind(plist.get(0).getLocation(), plist,
// setBindSet));
PDefinition def = null;
if (node.getSetBind() != null)
{
def = AstFactory.newAMultiBindListDefinition(node.getLocation(), question.assistantFactory.createPBindAssistant().getMultipleBindList(node.getSetBind()));
def.parent(node.getSetBind());
}
else
{
def = AstFactory.newAMultiBindListDefinition(node.getLocation(), question.assistantFactory.createPBindAssistant().getMultipleBindList(node.getSeqBind()));
def.parent(node.getSeqBind());
}
def.apply(THIS, question.newConstraint(null));
// now they are typechecked, add them again
// node.getSetBind().setSet(setBindSet.clone());
// node.getSetBind().setPattern(setBindPattern.clone());
if (node.getSetBind() != null &&
(question.assistantFactory.createPPatternAssistant().getVariableNames(node.getSetBind().getPattern()).size() != 1
|| !question.assistantFactory.createPTypeAssistant().isNumeric(question.assistantFactory.createPDefinitionAssistant().getType(def))))
{
TypeCheckerErrors.report(3155, "List comprehension must define one numeric bind variable", node.getLocation(), node);
}
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
PType etype = node.getFirst().apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
PExp predicate = node.getPredicate();
if (predicate != null)
{
TypeCheckInfo pquestion = new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null);
question.qualifiers = null;
if (!question.assistantFactory.createPTypeAssistant().isType(predicate.apply(THIS, pquestion), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3156, "Predicate is not boolean", predicate.getLocation(), predicate);
}
}
local.unusedCheck();
node.setType(AstFactory.newASeqSeqType(node.getLocation(), etype));
return node.getType();
}
@Override
public PType caseASeqEnumSeqExp(ASeqEnumSeqExp node, TypeCheckInfo question)
throws AnalysisException
{
PTypeSet ts = new PTypeSet(question.assistantFactory);
node.setTypes(new LinkedList<PType>());
List<PType> types = node.getTypes();
TypeCheckInfo elemConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isSeq(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getSeq(question.constraint).getSeqof();
elemConstraint = question.newConstraint(stype);
}
for (PExp ex : node.getMembers())
{
question.qualifiers = null;
PType mt = ex.apply(THIS, elemConstraint);
ts.add(mt);
types.add(mt);
}
node.setType(ts.isEmpty() ? AstFactory.newASeqSeqType(node.getLocation())
: AstFactory.newASeq1SeqType(node.getLocation(), ts.getType(node.getLocation())));
return node.getType();
}
@Override
public PType caseASetCompSetExp(ASetCompSetExp node, TypeCheckInfo question)
throws AnalysisException
{
PDefinition def = AstFactory.newAMultiBindListDefinition(node.getFirst().getLocation(), node.getBindings());
def.apply(THIS, question.newConstraint(null));
Environment local = new FlatCheckedEnvironment(question.assistantFactory, def, question.env, question.scope);
question = new TypeCheckInfo(question.assistantFactory, local, question.scope);
PType etype = node.getFirst().apply(THIS, question.newConstraint(null));
PExp predicate = node.getPredicate();
if (predicate != null)
{
TypeCheckInfo pquestion = new TypeCheckInfo(question.assistantFactory, local, question.scope, null, AstFactory.newABooleanBasicType(node.getLocation()), null);
if (!question.assistantFactory.createPTypeAssistant().isType(predicate.apply(THIS, pquestion), ABooleanBasicType.class))
{
TypeCheckerErrors.report(3159, "Predicate is not boolean", predicate.getLocation(), predicate);
}
}
local.unusedCheck();
SSetType setType = AstFactory.newASetSetType(node.getLocation(), etype);
node.setType(setType);
node.setSetType(setType);
return setType;
}
@Override
public PType caseASetEnumSetExp(ASetEnumSetExp node, TypeCheckInfo question)
throws AnalysisException
{
PTypeSet ts = new PTypeSet(question.assistantFactory);
node.setTypes(new LinkedList<PType>());
List<PType> types = node.getTypes();
TypeCheckInfo elemConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isSet(question.constraint))
{
PType setType = question.assistantFactory.createPTypeAssistant().getSet(question.constraint).getSetof();
elemConstraint = question.newConstraint(setType);
}
for (PExp ex : node.getMembers())
{
question.qualifiers = null;
PType mt = ex.apply(THIS, elemConstraint);
ts.add(mt);
types.add(mt);
}
node.setType(ts.isEmpty() ? AstFactory.newASetSetType(node.getLocation())
: AstFactory.newASet1SetType(node.getLocation(), ts.getType(node.getLocation())));
return node.getType();
}
@Override
public PType caseASetRangeSetExp(ASetRangeSetExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp first = node.getFirst();
PExp last = node.getLast();
question.qualifiers = null;
node.setFtype(first.apply(THIS, question.newConstraint(null)));
question.qualifiers = null;
node.setLtype(last.apply(THIS, question.newConstraint(null)));
PType ftype = node.getFtype();
PType ltype = node.getLtype();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(ftype))
{
TypeCheckerErrors.report(3166, "Set range type must be an number", ftype.getLocation(), ftype);
ftype = AstFactory.newAIntNumericBasicType(node.getLocation());
}
SNumericBasicType ntype = question.assistantFactory.createPTypeAssistant().getNumeric(ftype);
if (question.assistantFactory.createSNumericBasicTypeAssistant().getWeight(ntype) > 1)
{
ftype = AstFactory.newAIntNumericBasicType(node.getLocation()); // Caused by ceiling/floor
}
if (!question.assistantFactory.createPTypeAssistant().isNumeric(ltype))
{
TypeCheckerErrors.report(3167, "Set range type must be an number", ltype.getLocation(), ltype);
}
node.setType(AstFactory.newASetSetType(first.getLocation(), ftype));
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAStateInitExp(AStateInitExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
PPattern pattern = node.getState().getInitPattern();
PExp exp = node.getState().getInitExpression();
boolean canBeExecuted = false;
if (pattern instanceof AIdentifierPattern
&& exp instanceof AEqualsBinaryExp)
{
AEqualsBinaryExp ee = (AEqualsBinaryExp) exp;
ee.setType(AstFactory.newABooleanBasicType(ee.getLocation()));
question.qualifiers = null;
ee.getLeft().apply(THIS, noConstraint);
if (ee.getLeft() instanceof AVariableExp)
{
question.qualifiers = null;
PType rhs = ee.getRight().apply(THIS, noConstraint);
if (question.assistantFactory.createPTypeAssistant().isTag(rhs))
{
ARecordInvariantType rt = question.assistantFactory.createPTypeAssistant().getRecord(rhs);
canBeExecuted = rt.getName().getName().equals(node.getState().getName().getName());
}
}
} else
{
question.qualifiers = null;
exp.apply(THIS, noConstraint);
}
if (!canBeExecuted)
{
TypeCheckerErrors.warning(5010, "State init expression cannot be executed", node.getLocation(), node);
TypeCheckerErrors.detail("Expected", "p == p = mk_"
+ node.getState().getName().getName() + "(...)");
}
node.getState().setCanBeExecuted(canBeExecuted);
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAStringLiteralExp(AStringLiteralExp node,
TypeCheckInfo question)
{
if (node.getValue().getValue().isEmpty())
{
ASeqSeqType tt = AstFactory.newASeqSeqType(node.getLocation(), AstFactory.newACharBasicType(node.getLocation()));
node.setType(tt);
} else
{
node.setType(AstFactory.newASeq1SeqType(node.getLocation(), AstFactory.newACharBasicType(node.getLocation())));
}
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseASubclassResponsibilityExp(
ASubclassResponsibilityExp node, TypeCheckInfo question)
{
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType(); // Because we terminate anyway
}
@Override
public PType caseASubseqExp(ASubseqExp node, TypeCheckInfo question)
throws AnalysisException
{
TypeCheckInfo noConstraint = question.newConstraint(null);
question.qualifiers = null;
PType stype = node.getSeq().apply(THIS, noConstraint);
question.qualifiers = null;
node.setFtype(node.getFrom().apply(THIS, noConstraint));
PType ftype = node.getFtype();
question.qualifiers = null;
node.setTtype(node.getTo().apply(THIS, noConstraint));
PType ttype = node.getTtype();
if (!question.assistantFactory.createPTypeAssistant().isSeq(stype))
{
TypeCheckerErrors.report(3174, "Subsequence is not of a sequence type", node.getLocation(), node);
}
question.assistantFactory.createPTypeAssistant();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(ftype))
{
TypeCheckerErrors.report(3175, "Subsequence range start is not a number", node.getLocation(), node);
}
question.assistantFactory.createPTypeAssistant();
if (!question.assistantFactory.createPTypeAssistant().isNumeric(ttype))
{
TypeCheckerErrors.report(3176, "Subsequence range end is not a number", node.getLocation(), node);
}
node.setType(stype);
return stype;
}
@Override
public PType caseAThreadIdExp(AThreadIdExp node, TypeCheckInfo question)
{
PDefinition encl = question.env.getEnclosingDefinition();
if (encl != null && encl.getAccess().getPure())
{
TypeCheckerErrors.report(3346, "Cannot use 'threadid' in pure operations", node.getLocation(), node);
}
if (Settings.release == Release.VDM_10 && question.env.isFunctional())
{
TypeCheckerErrors.report(3348, "Cannot use 'threadid' in a functional context", node.getLocation(), node);
}
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseATimeExp(ATimeExp node, TypeCheckInfo question)
{
PDefinition encl = question.env.getEnclosingDefinition();
if (encl != null && encl.getAccess().getPure())
{
TypeCheckerErrors.report(3346, "Cannot use 'time' in pure operations", node.getLocation(), node);
}
if (Settings.release == Release.VDM_10 && question.env.isFunctional())
{
TypeCheckerErrors.report(3348, "Cannot use 'time' in a functional context", node.getLocation(), node);
}
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseATupleExp(ATupleExp node, TypeCheckInfo question)
throws AnalysisException
{
node.setTypes(new LinkedList<PType>());
List<PType> types = node.getTypes();
List<PType> elemConstraints = null;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isProduct(question.constraint))
{
elemConstraints = question.assistantFactory.createPTypeAssistant().getProduct(question.constraint).getTypes();
if (elemConstraints.size() != node.getArgs().size())
{
elemConstraints = null;
}
}
int i = 0;
for (PExp arg : node.getArgs())
{
question.qualifiers = null;
if (elemConstraints == null)
{
types.add(arg.apply(THIS, question.newConstraint(null)));
} else
{
types.add(arg.apply(THIS, question.newConstraint(elemConstraints.get(i++))));
}
}
node.setType(AstFactory.newAProductType(node.getLocation(), types));
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAUndefinedExp(AUndefinedExp node, TypeCheckInfo question)
{
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAVariableExp(AVariableExp node, TypeCheckInfo question)
{
Environment env = question.env;
ILexNameToken name = node.getName();
if (env.isVDMPP())
{
name.setTypeQualifier(question.qualifiers);
node.setVardef(env.findName(name, question.scope));
PDefinition vardef = node.getVardef();
if (vardef != null)
{
if (vardef.getClassDefinition() != null)
{
SClassDefinition sd = vardef.getClassDefinition();
if (sd != null && node.getName().getModule().equals(""))
{
node.setName(name.getModifiedName(sd.getName().getName()));
}
if (!question.assistantFactory.createSClassDefinitionAssistant().isAccessible(env, vardef, true))
{
TypeCheckerErrors.report(3180, "Inaccessible member "
+ name
+ " of class "
+ vardef.getClassDefinition().getName().getName(), node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
} else if (!question.assistantFactory.createPAccessSpecifierAssistant().isStatic(vardef.getAccess())
&& env.isStatic())
{
TypeCheckerErrors.report(3181, "Cannot access " + name
+ " from a static context", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
//AKM: a little test
// if(vardef.getClassDefinition().getName().getName().startsWith("$actionClass"))
// node.setName(name.getModifiedName(vardef.getClassDefinition().getName().getName()));
}
} else if (question.qualifiers != null)
{
// It may be an apply of a map or sequence, which would not
// have the type qualifier of its arguments in the name. Or
// it might be an apply of a function via a function variable
// which would not be qualified.
name.setTypeQualifier(null);
vardef = env.findName(name, question.scope);
if (vardef == null)
{
name.setTypeQualifier(question.qualifiers); // Just for
// error text!
} else
{
node.setVardef(vardef);
}
} else
{
// We may be looking for a bare function/op "x", when in fact
// there is one with a qualified name "x(args)". So we check
// the possible matches - if there is precisely one, we pick it,
// else we raise an ambiguity error.
for (PDefinition possible : env.findMatches(name))
{
if (question.assistantFactory.createPDefinitionAssistant().isFunctionOrOperation(possible))
{
if (vardef != null)
{
TypeCheckerErrors.report(3269, "Ambiguous function/operation name: "
+ name.getName(), node.getLocation(), node);
env.listAlternatives(name);
break;
}
vardef = possible;
node.setVardef(vardef);
// Set the qualifier so that it will find it at runtime.
PType pt = possible.getType();
if (pt instanceof AFunctionType)
{
AFunctionType ft = (AFunctionType) pt;
name.setTypeQualifier(ft.getParameters());
} else
{
AOperationType ot = (AOperationType) pt;
name.setTypeQualifier(ot.getParameters());
}
}
}
}
} else
{
PDefinition temp = env.findName(name, question.scope);
node.setVardef(temp == null ? null : temp);
}
if (node.getVardef() == null)
{
TypeCheckerErrors.report(3182, "Name '" + name
+ "' is not in scope", node.getLocation(), node);
env.listAlternatives(name);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
else
{
PType result = question.assistantFactory.createPDefinitionAssistant().getType(node.getVardef());
if (result instanceof AParameterType)
{
AParameterType ptype = (AParameterType)result;
if (ptype.getName().equals(name)) // Referring to "T" of @T
{
TypeCheckerErrors.report(3351, "Type parameter '" + name.getName() + "' cannot be used here", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
}
// Note that we perform an extra typeResolve here. This is
// how forward referenced types are resolved, and is the reason
// we don't need to retry at the top level (assuming all names
// are in the environment).
node.setType(question.assistantFactory.createPTypeAssistant().typeResolve(question.assistantFactory.createPDefinitionAssistant().getType(node.getVardef()), null, THIS, question));
// If a constraint is passed in, we can raise an error if it is
// not possible for the type to match the constraint (rather than
// certain, as checkConstraint would).
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
}
/**
* BINARY Expressions
*
* @throws AnalysisException
*/
@Override
public PType caseALessEqualNumericBinaryExp(
ALessEqualNumericBinaryExp node, TypeCheckInfo question)
throws AnalysisException
{
checkNumeric(node, THIS, question);
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseALessNumericBinaryExp(ALessNumericBinaryExp node,
TypeCheckInfo question) throws AnalysisException
{
checkNumeric(node, THIS, question);
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
/**
* UNARY Expressions
*
* @throws AnalysisException
*/
@Override
public PType caseAAbsoluteUnaryExp(AAbsoluteUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
question.qualifiers = null;
TypeCheckInfo absConstraint = question.newConstraint(null);
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isNumeric(question.constraint))
{
if (question.constraint instanceof AIntNumericBasicType
|| question.constraint instanceof ANatOneNumericBasicType)
{
absConstraint = question.newConstraint(AstFactory.newAIntNumericBasicType(node.getLocation()));
} else
{
absConstraint = question;
}
}
PType t = node.getExp().apply(THIS, absConstraint);
if (!question.assistantFactory.createPTypeAssistant().isNumeric(t))
{
TypeCheckerErrors.report(3053, "Argument of 'abs' is not numeric", node.getLocation(), node);
} else if (t instanceof AIntNumericBasicType)
{
t = AstFactory.newANatNumericBasicType(t.getLocation());
}
node.setType(t);
return t;
}
@Override
public PType caseACardinalityUnaryExp(ACardinalityUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
if (!question.assistantFactory.createPTypeAssistant().isSet(exp.apply(THIS, question.newConstraint(null))))
{
TypeCheckerErrors.report(3067, "Argument of 'card' is not a set", exp.getLocation(), exp);
}
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseADistConcatUnaryExp(ADistConcatUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
TypeCheckInfo expConstraint = question;
if (question.constraint != null)
{
PType stype = AstFactory.newASeqSeqType(node.getLocation(), question.constraint);
expConstraint = question.newConstraint(stype);
}
PType result = exp.apply(THIS, expConstraint);
if (question.assistantFactory.createPTypeAssistant().isSeq(result))
{
PType inner = question.assistantFactory.createPTypeAssistant().getSeq(result).getSeqof();
if (question.assistantFactory.createPTypeAssistant().isSeq(inner))
{
node.setType(question.assistantFactory.createPTypeAssistant().getSeq(inner));
return node.getType();
}
}
TypeCheckerErrors.report(3075, "Argument of 'conc' is not a seq of seq", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
@Override
public PType caseADistIntersectUnaryExp(ADistIntersectUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType arg = exp.apply(THIS, question.newConstraint(null));
if (question.assistantFactory.createPTypeAssistant().isSet(arg))
{
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(arg);
if (set.getEmpty()
|| question.assistantFactory.createPTypeAssistant().isSet(set.getSetof()))
{
node.setType(set.getSetof());
return set.getSetof();
}
}
TypeCheckerErrors.report(3076, "Argument of 'dinter' is not a set of sets", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
@Override
public PType caseADistMergeUnaryExp(ADistMergeUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
TypeCheckInfo expConstraint = question;
if (question.constraint != null)
{
PType stype = AstFactory.newASetSetType(node.getLocation(), question.constraint);
expConstraint = question.newConstraint(stype);
}
PType arg = exp.apply(THIS, expConstraint);
if (question.assistantFactory.createPTypeAssistant().isSet(arg))
{
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(arg);
if (!set.getEmpty()
&& question.assistantFactory.createPTypeAssistant().isMap(set.getSetof()))
{
node.setType(set.getSetof());
return set.getSetof();
}
}
TypeCheckerErrors.report(3077, "Merge argument is not a set of maps", node.getLocation(), node);
return AstFactory.newAMapMapType(node.getLocation()); // Unknown types
}
@Override
public PType caseADistUnionUnaryExp(ADistUnionUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
TypeCheckInfo expConstraint = question;
if (question.constraint != null)
{
PType stype = AstFactory.newASetSetType(node.getLocation(), question.constraint);
expConstraint = question.newConstraint(stype);
}
PType type = exp.apply(THIS, expConstraint);
if (question.assistantFactory.createPTypeAssistant().isSet(type))
{
SSetType set = question.assistantFactory.createPTypeAssistant().getSet(type);
if (question.assistantFactory.createPTypeAssistant().isSet(set.getSetof()))
{
node.setType(set.getSetof());
return set.getSetof();
}
}
TypeCheckerErrors.report(3078, "dunion argument is not a set of sets", node.getLocation(), node);
node.setType(AstFactory.newASetSetType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation())));
return node.getType();
}
@Override
public PType caseAFloorUnaryExp(AFloorUnaryExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
if (!question.assistantFactory.createPTypeAssistant().isNumeric(exp.apply(THIS, question.newConstraint(null))))
{
TypeCheckerErrors.report(3096, "Argument to floor is not numeric", node.getLocation(), node);
}
node.setType(AstFactory.newAIntNumericBasicType(node.getLocation()));
return node.getType();
}
@Override
public PType caseAHeadUnaryExp(AHeadUnaryExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isSeq(etype))
{
TypeCheckerErrors.report(3104, "Argument to 'hd' is not a sequence", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setType(question.assistantFactory.createPTypeAssistant().getSeq(etype).getSeqof());
return node.getType();
}
@Override
public PType caseAIndicesUnaryExp(AIndicesUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isSeq(etype))
{
TypeCheckerErrors.report(3109, "Argument to 'inds' is not a sequence", node.getLocation(), node);
TypeCheckerErrors.detail("Actual type", etype);
}
node.setType(AstFactory.newASetSetType(node.getLocation(), AstFactory.newANatOneNumericBasicType(node.getLocation())));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseALenUnaryExp(ALenUnaryExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isSeq(etype))
{
TypeCheckerErrors.report(3116, "Argument to 'len' is not a sequence", node.getLocation(), node);
}
node.setType(AstFactory.newANatNumericBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().possibleConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAMapDomainUnaryExp(AMapDomainUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isMap(etype))
{
TypeCheckerErrors.report(3120, "Argument to 'dom' is not a map", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
SMapType mt = question.assistantFactory.createPTypeAssistant().getMap(etype);
node.setType(AstFactory.newASetSetType(node.getLocation(), mt.getFrom()));
return node.getType();
}
@Override
public PType caseAMapInverseUnaryExp(AMapInverseUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isMap(etype))
{
TypeCheckerErrors.report(3111, "Argument to 'inverse' is not a map", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
node.setMapType(question.assistantFactory.createPTypeAssistant().getMap(etype));
AMapMapType mm = AstFactory.newAMapMapType(node.getLocation(), node.getMapType().getTo(), node.getMapType().getFrom());
node.setType(mm);
return node.getType();
}
@Override
public PType caseAMapRangeUnaryExp(AMapRangeUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isMap(etype))
{
TypeCheckerErrors.report(3122, "Argument to 'rng' is not a map", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
SMapType mt = question.assistantFactory.createPTypeAssistant().getMap(etype);
node.setType(AstFactory.newASetSetType(node.getLocation(), mt.getTo()));
return node.getType();
}
@Override
public PType caseANotUnaryExp(ANotUnaryExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType t = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isType(t, ABooleanBasicType.class))
{
TypeCheckerErrors.report(3137, "Not expression is not a boolean", node.getLocation(), node);
}
node.setType(AstFactory.newABooleanBasicType(node.getLocation()));
return question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, node.getType(), node.getLocation());
}
@Override
public PType caseAPowerSetUnaryExp(APowerSetUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
TypeCheckInfo argConstraint = question.newConstraint(null);
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isSet(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getSet(question.constraint).getSetof();
argConstraint = question.newConstraint(stype);
}
PType etype = exp.apply(THIS, argConstraint);
if (!question.assistantFactory.createPTypeAssistant().isSet(etype))
{
TypeCheckerErrors.report(3145, "Argument to 'power' is not a set", node.getLocation(), node);
node.setType(AstFactory.newAUnknownType(node.getLocation()));
return node.getType();
}
SSetType eset = question.assistantFactory.createPTypeAssistant().getSet(etype);
node.setType(AstFactory.newASetSetType(node.getLocation(),
AstFactory.newASetSetType(node.getLocation(), eset.getSetof())));
return node.getType();
}
@Override
public PType caseAReverseUnaryExp(AReverseUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question);
if (!question.assistantFactory.createPTypeAssistant().isSeq(etype))
{
TypeCheckerErrors.report(3295, "Argument to 'reverse' is not a sequence", node.getLocation(), node);
ASeqSeqType tt = AstFactory.newASeqSeqType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation()));
node.setType(tt);
return node.getType();
}
node.setType(etype);
return etype;
}
@Override
public PType caseATailUnaryExp(ATailUnaryExp node, TypeCheckInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
question.qualifiers = null;
PType etype = exp.apply(THIS, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isSeq(etype))
{
TypeCheckerErrors.report(3179, "Argument to 'tl' is not a sequence", node.getLocation(), node);
node.setType(AstFactory.newASeqSeqType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation())));
return node.getType();
}
node.setType(etype);
return etype;
}
@Override
public PType caseAUnaryMinusUnaryExp(AUnaryMinusUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
question.qualifiers = null;
PType t = node.getExp().apply(THIS, question);
if (t instanceof ANatNumericBasicType
|| t instanceof ANatOneNumericBasicType)
{
t = AstFactory.newAIntNumericBasicType(node.getLocation());
question.assistantFactory.createPTypeAssistant().checkConstraint(question.constraint, t, node.getLocation());
}
node.setType(t);
return t;
}
@Override
public PType caseAUnaryPlusUnaryExp(AUnaryPlusUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
question.qualifiers = null;
node.setType(node.getExp().apply(THIS, question));
return node.getType();
}
@Override
public PType caseAElementsUnaryExp(AElementsUnaryExp node,
TypeCheckInfo question) throws AnalysisException
{
PExp etype = node.getExp();
question.qualifiers = null;
TypeCheckInfo argConstraint = question;
if (question.constraint != null
&& question.assistantFactory.createPTypeAssistant().isSet(question.constraint))
{
PType stype = question.assistantFactory.createPTypeAssistant().getSet(question.constraint).getSetof();
stype = AstFactory.newASeqSeqType(node.getLocation(), stype);
argConstraint = question.newConstraint(stype);
}
PType arg = etype.apply(THIS, argConstraint);
if (!question.assistantFactory.createPTypeAssistant().isSeq(arg))
{
TypeCheckerErrors.report(3085, "Argument of 'elems' is not a sequence", node.getLocation(), node);
node.setType(AstFactory.newASetSetType(node.getLocation(), AstFactory.newAUnknownType(node.getLocation())));
return node.getType();
}
SSeqType seq = question.assistantFactory.createPTypeAssistant().getSeq(arg);
node.setType(seq.getEmpty() ? AstFactory.newASetSetType(node.getLocation())
: AstFactory.newASetSetType(node.getLocation(), seq.getSeqof()));
return node.getType();
}
private void checkNumeric(SNumericBinaryExp node,
IQuestionAnswer<TypeCheckInfo, PType> rootVisitor,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(rootVisitor, question.newConstraint(null));
node.getRight().apply(rootVisitor, question.newConstraint(null));
if (!question.assistantFactory.createPTypeAssistant().isNumeric(node.getLeft().getType()))
{
TypeCheckerErrors.report(3139, "Left hand of " + node.getOp()
+ " is not numeric", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", node.getLeft().getType());
node.getLeft().setType(AstFactory.newARealNumericBasicType(node.getLocation()));
}
if (!question.assistantFactory.createPTypeAssistant().isNumeric(node.getRight().getType()))
{
TypeCheckerErrors.report(3140, "Right hand of " + node.getOp()
+ " is not numeric", node.getLocation(), node);
TypeCheckerErrors.detail("Actual", node.getRight().getType());
node.getRight().setType(AstFactory.newARealNumericBasicType(node.getLocation()));
}
}
public PType functionApply(AApplyExp node, boolean isSimple,
AFunctionType ft,TypeCheckInfo question)
{
List<PType> ptypes = ft.getParameters();
if (node.getArgs().size() > ptypes.size())
{
TypeCheckerErrors.concern(isSimple, 3059, "Too many arguments", node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Args", node.getArgs(), "Params", ptypes);
return ft.getResult();
} else if (node.getArgs().size() < ptypes.size())
{
TypeCheckerErrors.concern(isSimple, 3060, "Too few arguments", node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Args", node.getArgs(), "Params", ptypes);
return ft.getResult();
}
int i = 0;
for (PType at : node.getArgtypes())
{
PType pt = ptypes.get(i++);
if (!question.assistantFactory.getTypeComparator().compatible(pt, at))
{
// TypeCheckerErrors.concern(isSimple, 3061, "Inappropriate type for argument " + i +
// ". (Expected: "+pt+" Actual: "+at+")",node.getLocation(),node);
TypeCheckerErrors.concern(isSimple, 3061, "Inappropriate type for argument "
+ i, node.getArgs().get(i-1).getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Expect", pt, "Actual", at);
}
else if (at instanceof AFunctionType)
{
AFunctionType fat = (AFunctionType)at;
if (fat.getInstantiated() != null && !fat.getInstantiated())
{
// Cannot pass uninstantiated polymorphic function arguments
TypeCheckerErrors.concern(isSimple, 3354, "Function argument must be instantiated",
node.getArgs().get(i-1).getLocation(), node);
}
}
}
return ft.getResult();
}
public PType operationApply(AApplyExp node, boolean isSimple,
AOperationType ot, TypeCheckInfo question)
{
List<PType> ptypes = ot.getParameters();
if (node.getArgs().size() > ptypes.size())
{
TypeCheckerErrors.concern(isSimple, 3062, "Too many arguments", node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Args", node.getArgs(), "Params", ptypes);
return ot.getResult();
} else if (node.getArgs().size() < ptypes.size())
{
TypeCheckerErrors.concern(isSimple, 3063, "Too few arguments", node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Args", node.getArgs(), "Params", ptypes);
return ot.getResult();
}
int i = 0;
for (PType at : node.getArgtypes())
{
PType pt = ptypes.get(i++);
if (!question.assistantFactory.getTypeComparator().compatible(pt, at))
{
// TypeCheckerErrors.concern(isSimple, 3064, "Inappropriate type for argument " + i
// +". (Expected: "+pt+" Actual: "+at+")",node.getLocation(),node);
TypeCheckerErrors.concern(isSimple, 3064, "Inappropriate type for argument "
+ i, node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Expect", pt, "Actual", at);
}
}
return ot.getResult();
}
public PType sequenceApply(AApplyExp node, boolean isSimple, SSeqType seq, TypeCheckInfo question)
{
if (node.getArgs().size() != 1)
{
TypeCheckerErrors.concern(isSimple, 3055, "Sequence selector must have one argument", node.getLocation(), node);
} else if (!question.assistantFactory.createPTypeAssistant().isNumeric(node.getArgtypes().get(0)))
{
TypeCheckerErrors.concern(isSimple, 3056, "Sequence application argument must be numeric", node.getLocation(), node);
} else if (seq.getEmpty())
{
TypeCheckerErrors.concern(isSimple, 3268, "Empty sequence cannot be applied", node.getLocation(), node);
}
return seq.getSeqof();
}
public PType mapApply(AApplyExp node, boolean isSimple, SMapType map, TypeCheckInfo question)
{
if (map.getEmpty())
{
TypeCheckerErrors.concern(isSimple, 3267, "Empty map cannot be applied", node.getLocation(), node);
}
if (node.getArgs().size() != 1)
{
TypeCheckerErrors.concern(isSimple, 3057, "Map application must have one argument", node.getLocation(), node);
}
else
{
PType argtype = node.getArgtypes().get(0);
if (!question.assistantFactory.getTypeComparator().compatible(map.getFrom(), argtype))
{
TypeCheckerErrors.concern(isSimple, 3058, "Map application argument is incompatible type", node.getLocation(), node);
TypeCheckerErrors.detail2(isSimple, "Map domain", map.getFrom(), "Argument", argtype);
}
}
return map.getTo();
}
public PDefinition getRecursiveDefinition(AApplyExp node,
TypeCheckInfo question)
{
ILexNameToken fname = null;
PExp root = node.getRoot();
if (root instanceof AApplyExp)
{
AApplyExp aexp = (AApplyExp) root;
return getRecursiveDefinition(aexp, question);
} else if (root instanceof AVariableExp)
{
AVariableExp var = (AVariableExp) root;
fname = var.getName();
} else if (root instanceof AFuncInstatiationExp)
{
AFuncInstatiationExp fie = (AFuncInstatiationExp) root;
if (fie.getExpdef() != null)
{
fname = fie.getExpdef().getName();
} else if (fie.getImpdef() != null)
{
fname = fie.getImpdef().getName();
}
}
if (fname != null)
{
return question.env.findName(fname, question.scope);
} else
{
return null;
}
}
/**
* Create a measure application string from this apply, turning the root function name into the measure name passed,
* and collapsing curried argument sets into one.
*
* @param node
* @param measure
* @param close
* @return
*/
public String getMeasureApply(AApplyExp node, ILexNameToken measure,
boolean close)
{
String start = null;
PExp root = node.getRoot();
if (root instanceof AApplyExp)
{
AApplyExp aexp = (AApplyExp) root;
start = getMeasureApply(aexp, measure, false);
} else if (root instanceof AVariableExp)
{
start = measure.getFullName() + "(";
} else if (root instanceof AFuncInstatiationExp)
{
AFuncInstatiationExp fie = (AFuncInstatiationExp) root;
start = measure.getFullName() + "["
+ Utils.listToString(fie.getActualTypes()) + "](";
} else
{
start = root.toString() + "(";
}
return start + Utils.listToString(node.getArgs())
+ (close ? ")" : ", ");
}
public PType typeCheck(ACaseAlternative c,
IQuestionAnswer<TypeCheckInfo, PType> rootVisitor,
TypeCheckInfo question, PType expType) throws AnalysisException
{
if (c.getDefs().size() == 0)
{
// c.setDefs(new ArrayList<PDefinition>());
question.assistantFactory.createPPatternAssistant().typeResolve(c.getPattern(), rootVisitor, new TypeCheckInfo(question.assistantFactory, question.env));
if (c.getPattern() instanceof AExpressionPattern)
{
// Only expression patterns need type checking...
AExpressionPattern ep = (AExpressionPattern) c.getPattern();
PType ptype = ep.getExp().apply(rootVisitor, new TypeCheckInfo(question.assistantFactory, question.env, question.scope));
if (!question.assistantFactory.getTypeComparator().compatible(ptype, expType))
{
TypeCheckerErrors.report(3311, "Pattern cannot match", c.getPattern().getLocation(), c.getPattern());
}
}
try
{
question.assistantFactory.createPPatternAssistant().typeResolve(c.getPattern(), rootVisitor, new TypeCheckInfo(question.assistantFactory, question.env));
c.getDefs().addAll(question.assistantFactory.createPPatternAssistant().getDefinitions(c.getPattern(), expType, NameScope.LOCAL));
}
catch (TypeCheckException e)
{
c.getDefs().clear();
throw e;
}
}
question.assistantFactory.createPPatternAssistant().typeCheck(c.getPattern(), question, rootVisitor);
question.assistantFactory.createPDefinitionListAssistant().typeCheck(c.getDefs(), rootVisitor, new TypeCheckInfo(question.assistantFactory, question.env, question.scope));
if (!question.assistantFactory.createPPatternAssistant().matches(c.getPattern(), expType))
{
TypeCheckerErrors.report(3311, "Pattern cannot match", c.getPattern().getLocation(), c.getPattern());
}
Environment local = new FlatCheckedEnvironment(question.assistantFactory, c.getDefs(), question.env, question.scope);
question = question.newInfo(local);
c.setType(c.getResult().apply(rootVisitor, question));
local.unusedCheck();
return c.getType();
}
public ABooleanBasicType binaryCheck(SBooleanBinaryExp node,
ABooleanBasicType expected,
IQuestionAnswer<TypeCheckInfo, PType> rootVisitor,
TypeCheckInfo question) throws AnalysisException
{
node.getLeft().apply(rootVisitor, question);
node.getRight().apply(rootVisitor, question);
if (!question.assistantFactory.createPTypeAssistant().isType(node.getLeft().getType(), expected.getClass()))
{
TypeCheckerErrors.report(3065, "Left hand of " + node.getOp()
+ " is not " + expected, node.getLocation(), node);
}
if (!question.assistantFactory.createPTypeAssistant().isType(node.getRight().getType(), expected.getClass()))
{
TypeCheckerErrors.report(3066, "Right hand of " + node.getOp()
+ " is not " + expected, node.getLocation(), node);
}
node.setType(expected);
return (ABooleanBasicType) node.getType();
}
}