@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); } }
@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(); } }