Difference between revisions of "User talk:Schuetzm/scope2"

From D Wiki
Jump to: navigation, search
(Created page with "== Example for the inference algorithm == Applied to the function deadalnix used to demonstrate the rvalue/lvalue problem: (1) <code>foo()</code> is <code>@safe</code>, maki...")
 
Line 10: Line 10:
 
     // ("mystery scope" in your terms)
 
     // ("mystery scope" in your terms)
 
     // => SCOPE(a) := [a] (final)
 
     // => SCOPE(a) := [a] (final)
     int** b = a;
+
     int** b;
 +
    // => SCOPE(b) := [] (incomplete)
 +
    b = a;
 
     // first assignment to `b`:
 
     // first assignment to `b`:
 
     // => SCOPE(b) |= SCOPE(a) = [a] (incomplete)
 
     // => SCOPE(b) |= SCOPE(a) = [a] (incomplete)
 
     int d;
 
     int d;
     int* c = &d;
+
     int* c;
 +
    // => SCOPE(c) := [] (incomplete)
 +
    c = &d;
 
     // only access to `&d`:
 
     // only access to `&d`:
 
     // => SCOPE(&d) := [d] (final)
 
     // => SCOPE(&d) := [d] (final)
 
     // assignment to `c`:
 
     // assignment to `c`:
     // => SCOPE(c) := SCOPE(&d) = [d] (incomplete)
+
     // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
 
     *b = c;
 
     *b = c;
 
     // assignment from `c`:
 
     // assignment from `c`:
Line 41: Line 45:
 
     // SCOPE(c) := tmp = [a]
 
     // SCOPE(c) := tmp = [a]
 
     // => all resolved
 
     // => all resolved
    // ---------------------------------------------------
 
    // validate dependencies:
 
    // a: [a] <= [a]    // OK
 
    // b: [b] <= [a]    // OK
 
    // c: [c] <= [a]    // OK
 
    // => ok, all depending on higher scopes
 
 
     // ---------------------------------------------------
 
     // ---------------------------------------------------
 
     // => satisfiable, now let's check the assignments:
 
     // => satisfiable, now let's check the assignments:
  
     int** b = a;        // [a] <= [a]  => OK
+
     int** b = a;        // [a] := [a]  => OK
 
     int d;
 
     int d;
     int* c = &d;        // [a] > [c]   => BAD
+
     int* c = &d;        // [a] := [d]   => BAD
     *b = c;            // [a] > [c]   => BAD
+
     *b = c;            // [a] := [a]   => OK
 
     // => invalid assignments
 
     // => invalid assignments
 
     // note how it even traces where the bad value comes from
 
     // note how it even traces where the bad value comes from
Line 63: Line 61:
 
<source lang="D">
 
<source lang="D">
 
void foo(T)(T** a) {
 
void foo(T)(T** a) {
     // start with empty scope for `a`
+
     // for parameters, start with self-owned scope
     // => SCOPE(a) := [] (incomplete)
+
     // => SCOPE(a) := [a] (incomplete)
     T** b = a;
+
     T** b;
 +
    // start with empty scope for locals
 +
    // => SCOPE(b) := [] (incomplete)
 +
    b = a;
 
     // only access to `a`:
 
     // only access to `a`:
 
     // => SCOPE(a) |= SCOPE(b)
 
     // => SCOPE(a) |= SCOPE(b)
Line 73: Line 74:
 
     // => DEFER because SCOPE(a) is incomplete
 
     // => DEFER because SCOPE(a) is incomplete
 
     T d;
 
     T d;
     T* c = &d;
+
     T* c;
 +
    // => SCOPE(c) = [] (incomplete)
 +
    c = &d;
 
     // only access to `&d`:
 
     // only access to `&d`:
 
     // => SCOPE(&d) := [d] (final)
 
     // => SCOPE(&d) := [d] (final)
 
     // assignment to `c`:
 
     // assignment to `c`:
     // => SCOPE(c) := SCOPE(&d) = [d] (incomplete)
+
     // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
 
     *b = c;
 
     *b = c;
 
     // assignment from `c`:
 
     // assignment from `c`:
 
     // => SCOPE(c) |= SCOPE(*b)
 
     // => SCOPE(c) |= SCOPE(*b)
 
     // => DEFER because SCOPE(*b) = SCOPE(b) is incomplete
 
     // => DEFER because SCOPE(*b) = SCOPE(b) is incomplete
     // assignment to `b`:
+
     // assignment to `*b`:
 
     // (treated as assignment to all vars in the lvalue)
 
     // (treated as assignment to all vars in the lvalue)
 
     // => SCOPE(b) |= SCOPE(c)
 
     // => SCOPE(b) |= SCOPE(c)
Line 88: Line 91:
 
     // ---------------------------------------------------
 
     // ---------------------------------------------------
 
     // we now have:
 
     // we now have:
     // SCOPE(a) = []
+
     // SCOPE(a) = [a]
 
     // SCOPE(b) = []
 
     // SCOPE(b) = []
 
     // SCOPE(c) = [d]
 
     // SCOPE(c) = [d]
Line 98: Line 101:
 
     // break cycles:
 
     // break cycles:
 
     // UNION(a, b, c)
 
     // UNION(a, b, c)
     // tmp := SCOPE(a) | SCOPE(b) | SCOPE(c) = [] | [] | [d] = [d]
+
     // tmp := SCOPE(a) | SCOPE(b) | SCOPE(c) = [a] | [] | [d] = [a]
     // SCOPE(a) := tmp = [d]
+
     // SCOPE(a) := tmp = [a]
     // SCOPE(b) := tmp = [d]
+
     // SCOPE(b) := tmp = [a]
     // SCOPE(c) := tmp = [d]
+
     // SCOPE(c) := tmp = [a]
 
     // => all resolved
 
     // => all resolved
 
     // ---------------------------------------------------
 
     // ---------------------------------------------------
     // validate dependencies:
+
     // => satisfiable, now let's check the assignments:
     // a: [a] > [d]    // BAD
+
 
     // b: [b] > [d]     // BAD
+
     int** b = a;        // [a] := [a]   => OK
     // c: [c] <= [d]   // OK
+
    int d;
     // => not ok, there are vars depending on lower (or disjunct) scopes
+
     int* c = &d;        // [a] := [d]   => BAD
     // ---------------------------------------------------
+
     *b = c;            // [a] := [a]   => OK
    // => not satisfiable
+
     // => invalid assignments
 +
     // again, the culprit can be detected
 
}
 
}
 
</source>
 
</source>

Revision as of 23:14, 27 February 2015

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
}