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; }
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 TCDefinitionListList getParamDefinitions() { TCDefinitionListList defList = new TCDefinitionListList(); TCFunctionType ftype = type; // Start with the overall function Iterator<TCPatternList> piter = paramPatternList.iterator(); while (piter.hasNext()) { TCPatternList plist = piter.next(); TCDefinitionList defs = new TCDefinitionList(); TCTypeList ptypes = ftype.parameters; Iterator<TCType> titer = ptypes.iterator(); if (plist.size() != ptypes.size()) { // This is a type/param mismatch, reported elsewhere. But we // have to create definitions to avoid a cascade of errors. TCType unknown = new TCUnknownType(location); for (TCPattern p : plist) { defs.addAll(p.getDefinitions(unknown, NameScope.LOCAL)); } } else { for (TCPattern p : plist) { defs.addAll(p.getDefinitions(titer.next(), NameScope.LOCAL)); } } defList.add(checkDuplicatePatterns(defs)); if (ftype.result instanceof TCFunctionType) // else??? { ftype = (TCFunctionType) ftype.result; } } return defList; }
@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(); } }