public TCExplicitFunctionDefinition( TCAccessSpecifier accessSpecifier, TCNameToken name, TCNameList typeParams, TCFunctionType type, TCPatternListList parameters, TCExpression body, TCExpression precondition, TCExpression postcondition, boolean typeInvariant, TCNameToken measure) { super(Pass.DEFS, name.getLocation(), name, NameScope.GLOBAL); this.accessSpecifier = accessSpecifier; this.typeParams = typeParams; this.type = type; this.paramPatternList = parameters; this.precondition = precondition; this.postcondition = postcondition; this.body = body; this.isTypeInvariant = typeInvariant; this.measure = measure; this.isCurried = parameters.size() > 1; type.definitions = new TCDefinitionList(this); type.instantiated = typeParams == null ? null : false; }
@Override public void typeResolve(Environment base) { if (typeParams != null) { FlatCheckedEnvironment params = new FlatCheckedEnvironment(getTypeParamDefinitions(), base, NameScope.NAMES); type = type.typeResolve(params, null); } else { type = type.typeResolve(base, null); } if (base.isVDMPP()) { name.setTypeQualifier(type.parameters); } if (body instanceof TCSubclassResponsibilityExpression || body instanceof TCNotYetSpecifiedExpression) { isUndefined = true; } if (precondition != null) { predef.typeResolve(base); } if (postcondition != null) { postdef.typeResolve(base); } for (TCPatternList pp : paramPatternList) { pp.typeResolve(base); } }
public TCFunctionType getType(TCTypeList actualTypes) { Iterator<TCType> ti = actualTypes.iterator(); TCFunctionType ftype = type; if (typeParams != null) { for (TCNameToken pname : typeParams) { TCType ptype = ti.next(); ftype = (TCFunctionType) ftype.polymorph(pname, ptype); } ftype.instantiated = true; } return ftype; }
private TCExplicitFunctionDefinition getPostDefinition() { TCPatternList last = new TCPatternList(); int psize = paramPatternList.size(); for (TCPattern p : paramPatternList.get(psize - 1)) { last.add(p); } last.add(new TCIdentifierPattern(name.getResultName(location))); TCPatternListList parameters = new TCPatternListList(); if (psize > 1) { parameters.addAll(paramPatternList.subList(0, psize - 1)); } parameters.add(last); TCExplicitFunctionDefinition def = new TCExplicitFunctionDefinition( accessSpecifier, name.getPostName(postcondition.location), typeParams, type.getCurriedPostType(isCurried), parameters, postcondition, null, null, false, null); def.classDefinition = classDefinition; return def; }
private TCExplicitFunctionDefinition getPreDefinition() { TCExplicitFunctionDefinition def = new TCExplicitFunctionDefinition( accessSpecifier, name.getPreName(precondition.location), typeParams, type.getCurriedPreType(isCurried), paramPatternList, precondition, null, null, false, null); def.classDefinition = classDefinition; return def; }
@Override public void typeCheck(Environment base, NameScope scope) { TCDefinitionList defs = new TCDefinitionList(); if (typeParams != null) { defs.addAll(getTypeParamDefinitions()); } TypeComparator.checkComposeTypes(type, base, false); expectedResult = checkParams(paramPatternList.listIterator(), type); paramDefinitionList = getParamDefinitions(); for (TCDefinitionList pdef : paramDefinitionList) { defs.addAll(pdef); // All definitions of all parameter lists } FlatEnvironment local = new FlatCheckedEnvironment(defs, base, scope); FlatCheckedEnvironment checked = (FlatCheckedEnvironment) local; checked.setStatic(accessSpecifier); checked.setEnclosingDefinition(this); checked.setFunctional(true); defs.typeCheck(local, scope); if (base.isVDMPP() && !accessSpecifier.isStatic) { local.add(getSelfDefinition()); } if (predef != null) { TCBooleanType expected = new TCBooleanType(location); TCType b = predef.body.typeCheck(local, null, NameScope.NAMES, expected); if (!b.isType(TCBooleanType.class, location)) { report(3018, "Precondition returns unexpected type"); detail2("Actual", b, "Expected", expected); } TCDefinitionList qualified = predef.body.getQualifiedDefs(local); if (!qualified.isEmpty()) { local = new FlatEnvironment(qualified, local); // NB Not checked! } } if (postdef != null) { TCPattern rp = new TCIdentifierPattern(name.getResultName(location)); TCDefinitionList rdefs = rp.getDefinitions(expectedResult, NameScope.NAMES); FlatCheckedEnvironment post = new FlatCheckedEnvironment(rdefs, local, NameScope.NAMES); TCBooleanType expected = new TCBooleanType(location); TCType b = postdef.body.typeCheck(post, null, NameScope.NAMES, expected); if (!b.isType(TCBooleanType.class, location)) { report(3018, "Postcondition returns unexpected type"); detail2("Actual", b, "Expected", expected); } } // This check returns the type of the function body in the case where // all of the curried parameter sets are provided. actualResult = body.typeCheck(local, null, scope, expectedResult); if (!TypeComparator.compatible(expectedResult, actualResult)) { report(3018, "Function returns unexpected type"); detail2("Actual", actualResult, "Expected", expectedResult); } if (type.narrowerThan(accessSpecifier)) { report(3019, "Function parameter visibility less than function definition"); } if (base.isVDMPP() && accessSpecifier.access == Token.PRIVATE && body instanceof TCSubclassResponsibilityExpression) { report(3329, "Abstract function/operation must be public or protected"); } if (measure == null && recursive) { warning(5012, "Recursive function has no measure"); } else if (measure != null) { if (base.isVDMPP()) measure.setTypeQualifier(getMeasureParams()); measuredef = base.findName(measure, scope); if (measuredef == null) { measure.report(3270, "Measure " + measure + " is not in scope"); } else if (!(measuredef instanceof TCExplicitFunctionDefinition)) { measure.report(3271, "Measure " + measure + " is not an explicit function"); } else if (measuredef == this) { measure.report(3304, "Recursive function cannot be its own measure"); } else { TCExplicitFunctionDefinition efd = (TCExplicitFunctionDefinition) measuredef; if (this.typeParams == null && efd.typeParams != null) { measure.report(3309, "Measure must not be polymorphic"); } else if (this.typeParams != null && efd.typeParams == null) { measure.report(3310, "Measure must also be polymorphic"); } else if (this.typeParams != null && efd.typeParams != null && !this.typeParams.equals(efd.typeParams)) { measure.report(3318, "Measure's type parameters must match function's"); detail2("Actual", efd.typeParams, "Expected", typeParams); } TCFunctionType mtype = (TCFunctionType) measuredef.getType(); if (typeParams != null) // Polymorphic, so compare "shape" of param signature { if (!mtype.parameters.toString().equals(getMeasureParams().toString())) { measure.report(3303, "Measure parameters different to function"); detail2(measure.getName(), mtype.parameters, "Expected", getMeasureParams()); } } else if (!TypeComparator.compatible(mtype.parameters, getMeasureParams())) { measure.report(3303, "Measure parameters different to function"); detail2(measure.getName(), mtype.parameters, "Expected", getMeasureParams()); } if (!(mtype.result instanceof TCNaturalType)) { if (mtype.result.isProduct(location)) { TCProductType pt = mtype.result.getProduct(); for (TCType t : pt.types) { if (!(t instanceof TCNaturalType)) { measure.report(3272, "Measure range is not a nat, or a nat tuple"); measure.detail("Actual", mtype.result); break; } } measureLexical = pt.types.size(); } else { measure.report(3272, "Measure range is not a nat, or a nat tuple"); measure.detail("Actual", mtype.result); } } } } if (!(body instanceof TCNotYetSpecifiedExpression) && !(body instanceof TCSubclassResponsibilityExpression)) { local.unusedCheck(); } }