public static CodegenMethod Codegen(
            ExprEqualsNodeForgeNC forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope,
            ExprForge lhs,
            ExprForge rhs)
        {
            var lhsType = lhs.EvaluationType;
            var rhsType = rhs.EvaluationType;

            var methodNode = codegenMethodScope.MakeChild(typeof(bool?), typeof(ExprEqualsNodeForgeNCForgeEquals), codegenClassScope);
            var block = methodNode.Block
                .DeclareVar(lhsType, "left", lhs.EvaluateCodegen(lhsType, methodNode, exprSymbol, codegenClassScope))
                .DeclareVar(rhsType, "right", rhs.EvaluateCodegen(rhsType, methodNode, exprSymbol, codegenClassScope));

            if (!lhsType.IsPrimitive) {
                block.IfRefNullReturnNull("left");
            }

            if (!rhsType.IsPrimitive) {
                block.IfRefNullReturnNull("right");
            }

            CodegenExpression compare;
            if (!lhsType.IsArray) {
                compare = CodegenEqualsNonNullNoCoerce(Ref("left"), lhsType, Ref("right"), rhsType);
            }
            else {
                if (!MultiKeyPlanner.RequiresDeepEquals(lhsType.GetElementType())) {
                    compare = StaticMethod(typeof(Arrays), "AreEqual", Ref("left"), Ref("right"));
                }
                else {
                    compare = StaticMethod(typeof(Arrays), "DeepEquals", Ref("left"), Ref("right"));
                }
            }

            if (!forge.ForgeRenderable.IsNotEquals) {
                block.MethodReturn(compare);
            }
            else {
                block.MethodReturn(Not(compare));
            }

            return methodNode;
        }
        public static CodegenMethod Codegen(
            ExprEqualsNodeForgeNC forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope,
            ExprForge lhs,
            ExprForge rhs)
        {
            var lhsType = lhs.EvaluationType;
            var rhsType = rhs.EvaluationType;

            var methodNode = codegenMethodScope.MakeChild(
                typeof(bool?),
                typeof(ExprEqualsNodeForgeNCEvalEquals),
                codegenClassScope);
            var block = methodNode.Block
                .DeclareVar(lhsType, "left", lhs.EvaluateCodegen(lhsType, methodNode, exprSymbol, codegenClassScope))
                .DeclareVar(rhsType, "right", rhs.EvaluateCodegen(rhsType, methodNode, exprSymbol, codegenClassScope));

            if (lhsType.CanBeNull()) {
                block.IfRefNullReturnNull("left");
            }

            if (rhsType.CanBeNull()) {
                block.IfRefNullReturnNull("right");
            }

            var compare = CodegenEqualsNonNullNoCoerce(Ref("left"), lhsType, Ref("right"), rhsType);
            if (!forge.ForgeRenderable.IsNotEquals) {
                block.MethodReturn(compare);
            }
            else {
                block.MethodReturn(Not(compare));
            }

            return methodNode;
        }
        public static CodegenMethod Codegen(
            ExprEqualsNodeForgeNC forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope,
            ExprForge lhs,
            ExprForge rhs)
        {
            var methodNode = codegenMethodScope.MakeChild(
                typeof(bool),
                typeof(ExprEqualsNodeForgeNCEvalIs),
                codegenClassScope);
            var block = methodNode.Block
                .DeclareVar<object>(
                    "left",
                    lhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope))
                .DeclareVar<object>(
                    "right",
                    rhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope));
            block.DeclareVarNoInit(typeof(bool), "result")
                .IfRefNull("left")
                .AssignRef("result", EqualsNull(Ref("right")))
                .IfElse()
                .AssignRef(
                    "result",
                    And(NotEqualsNull(Ref("right")), StaticMethod<object>("Equals", Ref("left"), Ref("right"))))
                .BlockEnd();
            if (!forge.ForgeRenderable.IsNotEquals) {
                block.MethodReturn(Ref("result"));
            }
            else {
                block.MethodReturn(Not(Ref("result")));
            }

            return methodNode;
        }
        public static CodegenMethod Codegen(
            ExprEqualsNodeForgeNC forge,
            CodegenMethodScope codegenMethodScope,
            ExprForgeCodegenSymbol exprSymbol,
            CodegenClassScope codegenClassScope,
            ExprForge lhs,
            ExprForge rhs)
        {
            var lhsType = lhs.EvaluationType;
            var rhsType = rhs.EvaluationType;
            var methodNode = codegenMethodScope.MakeChild(typeof(bool), typeof(ExprEqualsNodeForgeNCForgeIs), codegenClassScope);

            CodegenExpression compare;
            if (rhsType != null && lhsType != null) {
                if (!lhsType.IsArray) {
                    methodNode.Block
                        .DeclareVar<object>("left", lhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope))
                        .DeclareVar<object>("right", rhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope));
                    compare = StaticMethod<object>("Equals", Ref("left"), Ref("right"));
                }
                else {
                    methodNode.Block
                        .DeclareVar(lhsType, "left", lhs.EvaluateCodegen(lhsType, methodNode, exprSymbol, codegenClassScope))
                        .DeclareVar(rhsType, "right", rhs.EvaluateCodegen(rhsType, methodNode, exprSymbol, codegenClassScope));
                    if (!MultiKeyPlanner.RequiresDeepEquals(lhsType.GetElementType())) {
                        compare = StaticMethod(typeof(Arrays), "AreEqual", Ref("left"), Ref("right"));
                    }
                    else {
                        compare = StaticMethod(typeof(Arrays), "DeepEquals", Ref("left"), Ref("right"));
                    }
                }

                methodNode.Block.DeclareVarNoInit(typeof(bool), "result")
                    .IfRefNull("left")
                    .AssignRef("result", EqualsNull(Ref("right")))
                    .IfElse()
                    .AssignRef("result", And(NotEqualsNull(Ref("right")), compare))
                    .BlockEnd();
            }
            else {
                if (lhsType == null && rhsType == null) {
                    methodNode.Block.DeclareVar<bool>("result", ConstantTrue());
                }
                else if (lhsType == null) {
                    methodNode.Block
                        .DeclareVar<object>("right", rhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope))
                        .DeclareVar<bool>("result", EqualsNull(Ref("right")));
                }
                else {
                    methodNode.Block
                        .DeclareVar<object>("left", lhs.EvaluateCodegen(typeof(object), methodNode, exprSymbol, codegenClassScope))
                        .DeclareVar<bool>("result", EqualsNull(Ref("left")));
                }
            }

            if (!forge.ForgeRenderable.IsNotEquals) {
                methodNode.Block.MethodReturn(Ref("result"));
            }
            else {
                methodNode.Block.MethodReturn(Not(Ref("result")));
            }

            return methodNode;
        }