def test_scope_preservation_when_reconnect_graph():
        """
        If the _replace_var is doing reconnection of the graph, without any new op introduced,
        no scope information is going to change.
        """

        def get_prog():
            @mb.program(input_specs=[mb.TensorSpec(shape=(2, 4))])
            def prog(x):
                with mb.scope(
                    ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data=["module_1"]),
                ):
                    relu = mb.relu(x=x)

                with mb.scope(
                    ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data=["module_2"]),
                ):
                    sin = mb.sin(x=x)

                with mb.scope(
                    ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data=["module_3"]),
                ):
                    return mb.relu(x=relu)

            return prog

        # Case 1: No graph pass is involved, and only reconnect graph is done.
        # Scope information will not change.
        prog = get_prog()
        block = prog.functions["main"]
        ops = list(block.operations)
        var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
        }

        block._replace_var(var_1, var_2)
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
        }

        # Case 2: Even the reconnection happens under graph pass, nothing will change.
        prog = get_prog()
        block = prog.functions["main"]
        ops = list(block.operations)
        var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]

        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["dummy_pass"])):
            block._replace_var(var_1, var_2)
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
        }

        # Case 3: old_var and new_var are created under a graph pass, and the reconnection happens under the
        # same graph pass. Nothing will change still.
        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["dummy_pass"])):
            prog = get_prog()
            block = prog.functions["main"]
            ops = list(block.operations)
            var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]
            assert var_1.scopes == {
                ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
                ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
            }
            assert var_2.scopes == {
                ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
                ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
            }

            block._replace_var(var_1, var_2)
            assert var_2.scopes == {
                ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
                ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
            }

        # Case 4: Ops are created under a graph pass, and the reconnection happens outside the graph pass.
        # Nothing happens.
        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["dummy_pass"])):
            prog = get_prog()
            block = prog.functions["main"]
            ops = list(block.operations)
            var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }

        block._replace_var(var_1, var_2)
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }

        # Case 5: Ops are created under a graph pass 1, and the reconnection happens under graph pass2.
        # Nothing happens.
        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["dummy_pass"])):
            prog = get_prog()
            block = prog.functions["main"]
            ops = list(block.operations)
            var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]
        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }

        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["dummy_pass_2"])):
            block._replace_var(var_1, var_2)

        assert var_1.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_1"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }
        assert var_2.scopes == {
            ScopeSource.TORCHSCRIPT_MODULE_TYPE: ["module_2"],
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["dummy_pass"],
        }

        # Case 6. old_var and new_var are created under the same graph pass
        @mb.program(input_specs=[mb.TensorSpec(shape=(2, 4))])
        def prog(x):
            with mb.scope(
                ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["pass_1"]),
            ):
                relu = mb.relu(x=x)

            with mb.scope(
                ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["pass_1"]),
            ):
                sin = mb.sin(x=x)

            with mb.scope(
                ScopeInfo(source=ScopeSource.TORCHSCRIPT_MODULE_TYPE, data=["module_3"]),
            ):
                return mb.relu(x=relu)

        block = prog.functions["main"]
        ops = list(block.operations)
        var_1, var_2 = ops[0].outputs[0], ops[1].outputs[0]

        with mb.scope(ScopeInfo(source=ScopeSource.COREMLTOOLS_GRAPH_PASS, data=["pass_1"])):
            block._replace_var(var_1, var_2)

        assert var_1.scopes == {
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["pass_1"],
        }
        assert var_2.scopes == {
            ScopeSource.COREMLTOOLS_GRAPH_PASS: ["pass_1"],
        }

        If the _replace_var is doing reconnection of the graph, without any new op introduced,
        no scope information is going to change.
        
coremltools/converters/mil/mil/tests/test_programs.py