/* * #%~ * 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.LinkedList; import java.util.Set; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.definitions.AAssignmentDefinition; import org.overture.ast.definitions.AExternalDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.expressions.PExp; import org.overture.ast.factory.AstFactory; import org.overture.ast.intf.lex.ILexIdentifierToken; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.lex.LexNameToken; import org.overture.ast.node.Node; import org.overture.ast.patterns.ADefPatternBind; import org.overture.ast.patterns.ASeqBind; import org.overture.ast.patterns.ASetBind; import org.overture.ast.patterns.ATypeBind; import org.overture.ast.statements.AApplyObjectDesignator; import org.overture.ast.statements.AFieldObjectDesignator; import org.overture.ast.statements.AFieldStateDesignator; import org.overture.ast.statements.AForPatternBindStm; import org.overture.ast.statements.AIdentifierObjectDesignator; import org.overture.ast.statements.AIdentifierStateDesignator; import org.overture.ast.statements.AMapSeqStateDesignator; import org.overture.ast.statements.ANewObjectDesignator; import org.overture.ast.statements.ASelfObjectDesignator; import org.overture.ast.statements.ATixeStmtAlternative; import org.overture.ast.statements.ATrapStm; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.AClassType; import org.overture.ast.types.AFieldField; import org.overture.ast.types.AFunctionType; import org.overture.ast.types.AOperationType; import org.overture.ast.types.ARecordInvariantType; import org.overture.ast.types.SSetType; import org.overture.ast.types.PType; import org.overture.ast.types.SMapType; import org.overture.ast.types.SSeqType; import org.overture.ast.util.PTypeSet; import org.overture.typechecker.Environment; import org.overture.typechecker.TypeCheckInfo; import org.overture.typechecker.TypeCheckerErrors; public class TypeCheckerOthersVisitor extends AbstractTypeCheckVisitor { public TypeCheckerOthersVisitor( IQuestionAnswer<TypeCheckInfo, PType> typeCheckVisitor) { super(typeCheckVisitor); } @Override public PType caseADefPatternBind(ADefPatternBind node, TypeCheckInfo question) throws AnalysisException { node.setDefs(null); PType type = null; Node parent = node.getAncestor(AForPatternBindStm.class); if (parent != null) { type = ((AForPatternBindStm) parent).getSeqType().getSeqof(); } else if ((parent = node.getAncestor(ATrapStm.class)) != null) { type = ((ATrapStm) parent).getType(); } else if ((parent = node.getAncestor(ATixeStmtAlternative.class)) != null) { type = ((ATixeStmtAlternative) parent).getExp(); } if (node.getBind() != null) { if (node.getBind() instanceof ATypeBind) { ATypeBind typebind = (ATypeBind) node.getBind(); typebind.setType(question.assistantFactory.createPTypeAssistant().typeResolve(typebind.getType(), null, THIS, question)); // resolve pattern such that it is resolved before it is cloned later in newAMultiBindListDefinition if (node.getBind().getPattern() != null) { question.assistantFactory.createPPatternAssistant().typeResolve(node.getBind().getPattern(), THIS, question); } if (!question.assistantFactory.getTypeComparator().compatible(typebind.getType(), type)) { TypeCheckerErrors.report(3198, "Type bind not compatible with expression", node.getBind().getLocation(), node.getBind()); TypeCheckerErrors.detail2("Bind", typebind.getType(), "Exp", type); } } else if (node.getBind() instanceof ASetBind) { ASetBind setbind = (ASetBind) node.getBind(); PType bindtype = setbind.getSet().apply(THIS, question); if (!question.assistantFactory.createPTypeAssistant().isSet(bindtype)) { TypeCheckerErrors.report(3199, "Set bind not compatible with expression", node.getBind().getLocation(), node.getBind()); } else { SSetType settype = question.assistantFactory.createPTypeAssistant().getSet(bindtype); if (!question.assistantFactory.getTypeComparator().compatible(type, settype.getSetof())) { TypeCheckerErrors.report(3199, "Set bind not compatible with expression", node.getBind().getLocation(), node.getBind()); TypeCheckerErrors.detail2("Bind", settype.getSetof(), "Exp", type); } } } else { ASeqBind seqbind = (ASeqBind) node.getBind(); PType bindtype = seqbind.getSeq().apply(THIS, question); if (!question.assistantFactory.createPTypeAssistant().isSeq(bindtype)) { TypeCheckerErrors.report(3199, "Seq bind not compatible with expression", node.getBind().getLocation(), node.getBind()); } else { SSeqType seqtype = question.assistantFactory.createPTypeAssistant().getSeq(bindtype); if (!question.assistantFactory.getTypeComparator().compatible(type, seqtype.getSeqof())) { TypeCheckerErrors.report(3199, "Seq bind not compatible with expression", node.getBind().getLocation(), node.getBind()); TypeCheckerErrors.detail2("Bind", seqtype.getSeqof(), "Exp", type); } } } PDefinition def = AstFactory.newAMultiBindListDefinition(node.getBind().getLocation(), question.assistantFactory.createPBindAssistant().getMultipleBindList(node.getBind())); def.apply(THIS, question); LinkedList<PDefinition> defs = new LinkedList<PDefinition>(); defs.add(def); node.setDefs(defs); } else { assert type != null : "Can't typecheck a pattern without a type"; question.assistantFactory.createPPatternAssistant().typeResolve(node.getPattern(), THIS, question); node.setDefs(question.assistantFactory.createPPatternAssistant().getDefinitions(node.getPattern(), type, NameScope.LOCAL)); } return null; } @Override public PType caseAFieldStateDesignator(AFieldStateDesignator node, TypeCheckInfo question) throws AnalysisException { PType type = node.getObject().apply(THIS, question); PTypeSet result = new PTypeSet(question.assistantFactory); boolean unique = !question.assistantFactory.createPTypeAssistant().isUnion(type); ILexIdentifierToken field = node.getField(); if (question.assistantFactory.createPTypeAssistant().isRecord(type)) { ARecordInvariantType rec = question.assistantFactory.createPTypeAssistant().getRecord(type); AFieldField rf = question.assistantFactory.createARecordInvariantTypeAssistant().findField(rec, field.getName()); if (rf == null) { TypeCheckerErrors.concern(unique, 3246, "Unknown field name, '" + field + "'", node.getLocation(), field); result.add(AstFactory.newAUnknownType(field.getLocation())); } else { result.add(rf.getType()); } } if (question.assistantFactory.createPTypeAssistant().isClass(type, question.env)) { AClassType ctype = question.assistantFactory.createPTypeAssistant().getClassType(type, question.env); String cname = ctype.getName().getName(); node.setObjectfield(new LexNameToken(cname, field.getName(), node.getObject().getLocation())); PDefinition fdef = question.assistantFactory.createPDefinitionAssistant().findName(ctype.getClassdef(), node.getObjectfield(), NameScope.STATE); // SClassDefinitionAssistantTC.findName(ctype.getClassdef(), node.getObjectfield(), NameScope.STATE); if (fdef == null) { TypeCheckerErrors.concern(unique, 3260, "Unknown class field name, '" + field + "'", field.getLocation(), field); result.add(AstFactory.newAUnknownType(node.getLocation())); } else if (question.assistantFactory.createSClassDefinitionAssistant().isAccessible(question.env, fdef, false)) { result.add(fdef.getType()); } else { TypeCheckerErrors.concern(unique, 3092, "Inaccessible member " + field.getName() + " of class " + cname, field.getLocation(), field); result.add(AstFactory.newAUnknownType(node.getLocation())); } } if (result.isEmpty()) { TypeCheckerErrors.report(3245, "Field assignment is not of a record or object type", node.getLocation(), node); TypeCheckerErrors.detail2("Expression", node.getObject(), "Type", type); node.setType(AstFactory.newAUnknownType(field.getLocation())); return node.getType(); } node.setType(result.getType(node.getLocation())); return node.getType(); } @Override public PType caseAIdentifierStateDesignator( AIdentifierStateDesignator node, TypeCheckInfo question) { Environment env = question.env; PDefinition encl = env.getEnclosingDefinition(); if (env.isVDMPP()) { // We generate an explicit name because accessing a variable // by name in VDM++ does not "inherit" values from a superclass. ILexNameToken name = node.getName(); ILexNameToken exname = name.getExplicit(true); PDefinition def = env.findName(exname, NameScope.STATE); if (def == null) { Set<PDefinition> matches = env.findMatches(exname); if (!matches.isEmpty()) { PDefinition match = matches.iterator().next(); // Just take first if (question.assistantFactory.createPDefinitionAssistant().isFunction(match)) { TypeCheckerErrors.report(3247, "Function apply not allowed in state designator", name.getLocation(), name); } else { TypeCheckerErrors.report(3247, "Operation call not allowed in state designator", name.getLocation(), name); } node.setType(match.getType()); return node.getType(); } else { TypeCheckerErrors.report(3247, "Symbol '" + name + "' is not an updatable variable", name.getLocation(), name); } node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (!question.assistantFactory.createPDefinitionAssistant().isUpdatable(def)) { TypeCheckerErrors.report(3301, "Variable '" + name + "' in scope is not updatable", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (encl != null && encl.getAccess().getPure() && question.assistantFactory.createPDefinitionAssistant().isInstanceVariable(def)) { TypeCheckerErrors.report(3338, "Cannot update state in a pure operation", name.getLocation(), name); } else if (def.getClassDefinition() != null) { if (!question.assistantFactory.createSClassDefinitionAssistant().isAccessible(env, def, true)) { TypeCheckerErrors.report(3180, "Inaccessible member '" + name + "' of class " + def.getClassDefinition().getName().getName(), name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (!question.assistantFactory.createPDefinitionAssistant().isStatic(def) && env.isStatic()) { TypeCheckerErrors.report(3181, "Cannot access " + name + " from a static context", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } } else if (def instanceof AExternalDefinition) { AExternalDefinition d = (AExternalDefinition) def; if (d.getReadOnly()) { TypeCheckerErrors.report(3248, "Cannot assign to 'ext rd' state " + name, name.getLocation(), name); } } // else just state access in (say) an explicit operation node.setType(question.assistantFactory.createPDefinitionAssistant().getType(def)); return node.getType(); } else { ILexNameToken name = node.getName(); PDefinition def = env.findName(name, NameScope.STATE); if (def == null) { TypeCheckerErrors.report(3247, "Unknown state variable '" + name + "' in assignment", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (question.assistantFactory.createPDefinitionAssistant().isFunction(def)) { TypeCheckerErrors.report(3247, "Function apply not allowed in state designator", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (question.assistantFactory.createPDefinitionAssistant().isOperation(def)) { TypeCheckerErrors.report(3247, "Operation call not allowed in state designator", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (!question.assistantFactory.createPDefinitionAssistant().isUpdatable(def)) { TypeCheckerErrors.report(3301, "Variable '" + name + "' in scope is not updatable", name.getLocation(), name); node.setType(AstFactory.newAUnknownType(name.getLocation())); return node.getType(); } else if (encl != null && encl.getAccess().getPure() && !(def instanceof AAssignmentDefinition)) { TypeCheckerErrors.report(3338, "Cannot update state in a pure operation", name.getLocation(), name); } else if (def instanceof AExternalDefinition) { AExternalDefinition d = (AExternalDefinition) def; if (d.getReadOnly()) { TypeCheckerErrors.report(3248, "Cannot assign to 'ext rd' state " + name, name.getLocation(), name); } } // else just state access in (say) an explicit operation node.setType(question.assistantFactory.createPDefinitionAssistant().getType(def)); return node.getType(); } } @Override public PType caseAMapSeqStateDesignator(AMapSeqStateDesignator node, TypeCheckInfo question) throws AnalysisException { PType etype = node.getExp().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, NameScope.NAMESANDSTATE)); PType rtype = node.getMapseq().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env)); PTypeSet result = new PTypeSet(question.assistantFactory); if (question.assistantFactory.createPTypeAssistant().isMap(rtype)) { node.setMapType(question.assistantFactory.createPTypeAssistant().getMap(rtype)); if (!question.assistantFactory.getTypeComparator().compatible(node.getMapType().getFrom(), etype)) { TypeCheckerErrors.report(3242, "Map element assignment of wrong type", node.getLocation(), node); TypeCheckerErrors.detail2("Expect", node.getMapType().getFrom(), "Actual", etype); } else { result.add(node.getMapType().getTo()); } } if (question.assistantFactory.createPTypeAssistant().isSeq(rtype)) { node.setSeqType(question.assistantFactory.createPTypeAssistant().getSeq(rtype)); if (!question.assistantFactory.createPTypeAssistant().isNumeric(etype)) { TypeCheckerErrors.report(3243, "Seq index is not numeric", node.getLocation(), node); TypeCheckerErrors.detail("Actual", etype); } else { result.add(node.getSeqType().getSeqof()); } } if (question.assistantFactory.createPTypeAssistant().isFunction(rtype)) { // Error case, but improves errors if we work out the return type AFunctionType ftype = question.assistantFactory.createPTypeAssistant().getFunction(rtype); result.add(ftype.getResult()); } if (question.assistantFactory.createPTypeAssistant().isOperation(rtype)) { // Error case, but improves errors if we work out the return type AOperationType otype = question.assistantFactory.createPTypeAssistant().getOperation(rtype); result.add(otype.getResult()); } if (result.isEmpty()) { TypeCheckerErrors.report(3244, "Expecting a map or 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 caseASelfObjectDesignator(ASelfObjectDesignator node, TypeCheckInfo question) { PDefinition def = question.env.findName(node.getSelf(), NameScope.NAMES); if (def == null) { TypeCheckerErrors.report(3263, "Cannot reference 'self' from here", node.getSelf().getLocation(), node.getSelf()); return AstFactory.newAUnknownType(node.getSelf().getLocation()); } return question.assistantFactory.createPDefinitionAssistant().getType(def); } @Override public PType caseAApplyObjectDesignator(AApplyObjectDesignator node, TypeCheckInfo question) throws AnalysisException { LinkedList<PType> argtypes = new LinkedList<PType>(); for (PExp a : node.getArgs()) { argtypes.add(a.apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, NameScope.NAMESANDSTATE))); } PType type = node.getObject().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, null, argtypes)); boolean unique = !question.assistantFactory.createPTypeAssistant().isUnion(type); PTypeSet result = new PTypeSet(question.assistantFactory); if (question.assistantFactory.createPTypeAssistant().isMap(type)) { SMapType map = question.assistantFactory.createPTypeAssistant().getMap(type); result.add(mapApply(node, map, question.env, NameScope.NAMESANDSTATE, unique, THIS)); } if (question.assistantFactory.createPTypeAssistant().isSeq(type)) { SSeqType seq = question.assistantFactory.createPTypeAssistant().getSeq(type); result.add(seqApply(node, seq, question.env, NameScope.NAMESANDSTATE, unique, THIS, question)); } if (question.assistantFactory.createPTypeAssistant().isFunction(type)) { AFunctionType ft = question.assistantFactory.createPTypeAssistant().getFunction(type); question.assistantFactory.createPTypeAssistant().typeResolve(ft, null, THIS, new TypeCheckInfo(question.assistantFactory, question.env)); result.add(functionApply(node, ft, question.env, NameScope.NAMESANDSTATE, unique, THIS)); } if (question.assistantFactory.createPTypeAssistant().isOperation(type)) { AOperationType ot = question.assistantFactory.createPTypeAssistant().getOperation(type); question.assistantFactory.createPTypeAssistant().typeResolve(ot, null, THIS, new TypeCheckInfo(question.assistantFactory, question.env)); result.add(operationApply(node, ot, question.env, NameScope.NAMESANDSTATE, unique, THIS)); } if (result.isEmpty()) { TypeCheckerErrors.report(3249, "Object designator is not a map, sequence, function or operation", node.getLocation(), node); TypeCheckerErrors.detail2("Designator", node.getObject(), "Type", type); return AstFactory.newAUnknownType(node.getLocation()); } return result.getType(node.getLocation()); } @Override public PType caseANewObjectDesignator(ANewObjectDesignator node, TypeCheckInfo question) throws AnalysisException { return node.getExpression().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, NameScope.NAMESANDSTATE, question.qualifiers)); } @Override public PType caseAIdentifierObjectDesignator( AIdentifierObjectDesignator node, TypeCheckInfo question) throws AnalysisException { return node.getExpression().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, NameScope.NAMESANDSTATE, question.qualifiers)); } @Override public PType caseAFieldObjectDesignator(AFieldObjectDesignator node, TypeCheckInfo question) throws AnalysisException { PType type = node.getObject().apply(THIS, new TypeCheckInfo(question.assistantFactory, question.env, null, question.qualifiers)); PTypeSet result = new PTypeSet(question.assistantFactory); boolean unique = !question.assistantFactory.createPTypeAssistant().isUnion(type); if (question.assistantFactory.createPTypeAssistant().isClass(type, question.env)) { AClassType ctype = question.assistantFactory.createPTypeAssistant().getClassType(type, question.env); if (node.getClassName() == null) { node.setField(new LexNameToken(ctype.getName().getName(), node.getFieldName().getName(), node.getFieldName().getLocation())); } else { node.setField(node.getClassName()); } ILexNameToken field = node.getField(); field.setTypeQualifier(question.qualifiers); PDefinition fdef = question.assistantFactory.createPDefinitionAssistant().findName(ctype.getClassdef(), field, NameScope.NAMESANDSTATE); if (fdef == null) { TypeCheckerErrors.concern(unique, 3260, "Unknown class member name, '" + field + "'", node.getLocation(), node); result.add(AstFactory.newAUnknownType(node.getLocation())); } else if (!question.assistantFactory.createSClassDefinitionAssistant().isAccessible(question.env, fdef, false)) { TypeCheckerErrors.concern(unique, 3260, "Inaccessible class member name, '" + field + "'", node.getLocation(), node); result.add(AstFactory.newAUnknownType(node.getLocation())); } else { result.add(question.assistantFactory.createPDefinitionAssistant().getType(fdef)); } } if (question.assistantFactory.createPTypeAssistant().isRecord(type)) { String sname = node.getFieldName() != null ? node.getFieldName().getName() : node.getClassName().toString(); ARecordInvariantType rec = question.assistantFactory.createPTypeAssistant().getRecord(type); AFieldField rf = question.assistantFactory.createARecordInvariantTypeAssistant().findField(rec, sname); if (rf == null) { TypeCheckerErrors.concern(unique, 3261, "Unknown field name, '" + sname + "'", node.getLocation(), node); result.add(AstFactory.newAUnknownType(node.getLocation())); } else { result.add(rf.getType()); } } if (result.isEmpty()) { TypeCheckerErrors.report(3262, "Field assignment is not of a class or record type", node.getLocation(), node); TypeCheckerErrors.detail2("Expression", node.getObject(), "Type", type); return AstFactory.newAUnknownType(node.getLocation()); } return result.getType(node.getLocation()); } public PType mapApply(AApplyObjectDesignator node, SMapType map, Environment env, NameScope scope, boolean unique, IQuestionAnswer<TypeCheckInfo, PType> rootVisitor) throws AnalysisException { if (node.getArgs().size() != 1) { TypeCheckerErrors.concern(unique, 3250, "Map application must have one argument", node.getLocation(), node); return AstFactory.newAUnknownType(node.getLocation()); } PType argtype = node.getArgs().get(0).apply(rootVisitor, new TypeCheckInfo(env.af, env, scope)); if (!env.af.getTypeComparator().compatible(map.getFrom(), argtype)) { TypeCheckerErrors.concern(unique, 3251, "Map application argument is incompatible type", node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Map domain", map.getFrom(), "Argument", argtype); } return map.getTo(); } public PType seqApply(AApplyObjectDesignator node, SSeqType seq, Environment env, NameScope scope, boolean unique, IQuestionAnswer<TypeCheckInfo, PType> rootVisitor, TypeCheckInfo question) throws AnalysisException { if (node.getArgs().size() != 1) { TypeCheckerErrors.concern(unique, 3252, "Sequence application must have one argument", node.getLocation(), node); return AstFactory.newAUnknownType(node.getLocation()); } PType argtype = node.getArgs().get(0).apply(rootVisitor, new TypeCheckInfo(question.assistantFactory, env, scope)); if (!env.af.createPTypeAssistant().isNumeric(argtype)) { TypeCheckerErrors.concern(unique, 3253, "Sequence argument is not numeric", node.getLocation(), node); TypeCheckerErrors.detail(unique, "Type", argtype); } return seq.getSeqof(); } public PType functionApply(AApplyObjectDesignator node, AFunctionType ftype, Environment env, NameScope scope, boolean unique, IQuestionAnswer<TypeCheckInfo, PType> rootVisitor) throws AnalysisException { LinkedList<PType> ptypes = ftype.getParameters(); if (node.getArgs().size() > ptypes.size()) { TypeCheckerErrors.concern(unique, 3254, "Too many arguments", node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Args", node.getArgs(), "Params", ptypes); return ftype.getResult(); } else if (node.getArgs().size() < ptypes.size()) { TypeCheckerErrors.concern(unique, 3255, "Too few arguments", node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Args", node.getArgs(), "Params", ptypes); return ftype.getResult(); } int i = 0; for (PExp a : node.getArgs()) { PType at = a.apply(rootVisitor, new TypeCheckInfo(env.af, env, scope)); PType pt = ptypes.get(i++); if (!env.af.getTypeComparator().compatible(pt, at)) { // TypeCheckerErrors.concern(unique, 3256, "Inappropriate type for argument " + i // +". (Expected: "+pt+" Actual: "+at+")" ,node.getLocation(),node); TypeCheckerErrors.concern(unique, 3256, "Inappropriate type for argument " + i, node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Expect", pt, "Actual", at); } } return ftype.getResult(); } public PType operationApply(AApplyObjectDesignator node, AOperationType optype, Environment env, NameScope scope, boolean unique, IQuestionAnswer<TypeCheckInfo, PType> rootVisitor) throws AnalysisException { LinkedList<PType> ptypes = optype.getParameters(); if (node.getArgs().size() > ptypes.size()) { TypeCheckerErrors.concern(unique, 3257, "Too many arguments", node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Args", node.getArgs(), "Params", ptypes); return optype.getResult(); } else if (node.getArgs().size() < ptypes.size()) { TypeCheckerErrors.concern(unique, 3258, "Too few arguments", node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Args", node.getArgs(), "Params", ptypes); return optype.getResult(); } int i = 0; for (PExp a : node.getArgs()) { PType at = a.apply(rootVisitor, new TypeCheckInfo(env.af, env, scope)); PType pt = ptypes.get(i++); if (!env.af.getTypeComparator().compatible(pt, at)) { // + ". (Expected: "+pt+" Actual: "+at+")" TypeCheckerErrors.concern(unique, 3259, "Inappropriate type for argument " + i, node.getLocation(), node); TypeCheckerErrors.detail2(unique, "Expect", pt, "Actual", at); } } return optype.getResult(); } }