public Object visit(TemplateCallExpression node) {
            if (!initialCallExpressionCheck(node)) {
                return null;
            }

            Expression[] exprs = node.getParams().getExpressions();
            int length = exprs.length;
            Type[] actualTypes = new Type[length];
            for (int i=0; i<length; i++) {
                actualTypes[i] = exprs[i].getType();
            }

            Block subParam = node.getSubstitutionParam();
            Compiler compiler = mUnit.getCompiler();
            String name = node.getTarget().getName();

            // Look for a matching template to call.

            CompilationUnit unit = compiler.getCompilationUnit(name, mUnit);
            if (unit == null) {
                error("templatecallexpression.not.found", node);
                return null;
            }

            Template tree = unit.getParseTree();

            Variable[] formalParams = tree.getParams();
            if (formalParams != null) {
                if (formalParams.length != length) {
                    error("templatecallexpression.parameter.count",
                          String.valueOf(formalParams.length),
                          String.valueOf(length), node);
                    return null;
                }

                if (subParam != null && !tree.hasSubstitutionParam()) {
                    error("templatecallexpression.substitution.no",
                          tree.getName().getName(), subParam);
                    return null;
                }
                else if (subParam == null && tree.hasSubstitutionParam()) {
                    error("templatecallexpression.substitution.yes",
                          tree.getName().getName(), node);
                }

                node.setCalledTemplate(unit);
                for (int i=0; i<length; i++) {
                    Type type = formalParams[i].getType();

                    if (type == null) {
                        error("templatecallexpression.parameter.unknown",
                              node);
                        return null;
                    }

                    int cost = type.convertableFrom(actualTypes[i]);
                    if (cost < 0) {
                        node.setCalledTemplate(null);

                        String msg1 = actualTypes[i].getFullName();
                        String msg2 = type.getFullName();

                        ClassLoader CL1 = actualTypes[i].getNaturalClass()
                            .getClassLoader();

                        ClassLoader CL2 = type.getNaturalClass()
                            .getClassLoader();

                        if (CL1 != CL2) {
                            msg1 += "(" + CL1 + ")";
                            msg2 += "(" + CL2 + ")";
                        }

                        error("templatecallexpression.conversion",
                              msg1, msg2, exprs[i]);
                    }
                    else {
                        exprs[i].convertTo(type, false);
                    }
                }
            }

            Type retType = tree.getReturnType();
            if (retType == null) {
                retType = Type.VOID_TYPE;
            }
            node.setType(retType);

            if (Type.VOID_TYPE.equals(retType) &&
                !node.isVoidPermitted()) {

                error("templatecallexpression.template.void", node);
                return null;
            }

            return null;
        }