User talk:Schuetzm/scope2

From D Wiki
Jump to: navigation, search

Example for the inference algorithm

Applied to the function deadalnix used to demonstrate the rvalue/lvalue problem:

(1) foo() is @safe, making its param scoped:

void foo(scope int** a) {
    // no inference for `a`
    // ("mystery scope" in your terms)
    // => SCOPE(a) := [a] (final)
    int** b;
    // => SCOPE(b) := [] (incomplete)
    b = a;
    // first assignment to `b`:
    // => SCOPE(b) |= SCOPE(a) = [a] (incomplete)
    int d;
    int* c;
    // => SCOPE(c) := [] (incomplete)
    c = &d;
    // only access to `&d`:
    // => SCOPE(&d) := [d] (final)
    // assignment to `c`:
    // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
    *b = c;
    // assignment from `c`:
    // => SCOPE(c) |= SCOPE(*b)
    // => DEFER because SCOPE(*b) = SCOPE(b) is incomplete
    // assignment to `*b`:
    // (treated as assignment to all vars in the lvalue)
    // => SCOPE(b) |= SCOPE(c)
    // => DEFER because SCOPE(c) is incomplete
    // ---------------------------------------------------
    // we now have:
    // SCOPE(a) = [a]
    // SCOPE(b) = [a]
    // SCOPE(c) = [d]
    // unresolved:
    // SCOPE(b) |= SCOPE(c)
    // SCOPE(c) |= SCOPE(b)
    // break cycles:
    // UNION(b, c)
    // tmp := SCOPE(b) | SCOPE(d) = [a] | [d] = [a]
    // SCOPE(b) := tmp = [a]
    // SCOPE(c) := tmp = [a]
    // => all resolved
    // ---------------------------------------------------
    // => satisfiable, now let's check the assignments:

    int** b = a;        // [a] := [a]   => OK
    int d;
    int* c = &d;        // [a] := [d]   => BAD
    *b = c;             // [a] := [a]   => OK
    // => invalid assignments
    // note how it even traces where the bad value comes from
}

(2) foo() is in a template, param scope gets inferred

void foo(T)(T** a) {
    // for parameters, start with self-owned scope
    // => SCOPE(a) := [a] (incomplete)
    T** b;
    // start with empty scope for locals
    // => SCOPE(b) := [] (incomplete)
    b = a;
    // only access to `a`:
    // => SCOPE(a) |= SCOPE(b)
    // => DEFER because SCOPE(b) is incomplete
    // first assignment to `b`:
    // => SCOPE(b) |= SCOPE(a)
    // => DEFER because SCOPE(a) is incomplete
    T d;
    T* c;
    // => SCOPE(c) = [] (incomplete)
    c = &d;
    // only access to `&d`:
    // => SCOPE(&d) := [d] (final)
    // assignment to `c`:
    // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
    *b = c;
    // assignment from `c`:
    // => SCOPE(c) |= SCOPE(*b)
    // => DEFER because SCOPE(*b) = SCOPE(b) is incomplete
    // assignment to `*b`:
    // (treated as assignment to all vars in the lvalue)
    // => SCOPE(b) |= SCOPE(c)
    // => DEFER because SCOPE(c) is incomplete
    // ---------------------------------------------------
    // we now have:
    // SCOPE(a) = [a]
    // SCOPE(b) = []
    // SCOPE(c) = [d]
    // unresolved:
    // SCOPE(a) |= SCOPE(b)
    // SCOPE(b) |= SCOPE(a)
    // SCOPE(b) |= SCOPE(c)
    // SCOPE(c) |= SCOPE(b)
    // break cycles:
    // UNION(a, b, c)
    // tmp := SCOPE(a) | SCOPE(b) | SCOPE(c) = [a] | [] | [d] = [a]
    // SCOPE(a) := tmp = [a]
    // SCOPE(b) := tmp = [a]
    // SCOPE(c) := tmp = [a]
    // => all resolved
    // ---------------------------------------------------
    // => satisfiable, now let's check the assignments:

    int** b = a;        // [a] := [a]   => OK
    int d;
    int* c = &d;        // [a] := [d]   => BAD
    *b = c;             // [a] := [a]   => OK
    // => invalid assignments
    // again, the culprit can be detected
}