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

From D Wiki
Jump to: navigation, search
Line 7: Line 7:
 
<source lang="D">
 
<source lang="D">
 
void foo(scope int** a) {
 
void foo(scope int** a) {
     // no inference for `a`
+
     // no inference for `a` => self-owned
 
     // ("mystery scope" in your terms)
 
     // ("mystery scope" in your terms)
 
     // => SCOPE(a) := [a] (final)
 
     // => SCOPE(a) := [a] (final)
Line 13: Line 13:
 
     // => SCOPE(b) := [] (incomplete)
 
     // => SCOPE(b) := [] (incomplete)
 
     b = a;
 
     b = a;
     // first assignment to `b`:
+
     // scope of `a` is fixed => do nothing
    // => SCOPE(b) |= SCOPE(a) = [a] (incomplete)
 
 
     int d;
 
     int d;
 
     int* c;
 
     int* c;
 
     // => SCOPE(c) := [] (incomplete)
 
     // => SCOPE(c) := [] (incomplete)
 
     c = &d;
 
     c = &d;
    // only access to `&d`:
 
    // => SCOPE(&d) := [d] (final)
 
    // assignment to `c`:
 
    // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
 
 
     *b = c;
 
     *b = c;
 
     // assignment from `c`:
 
     // assignment from `c`:
     // => SCOPE(c) |= SCOPE(*b)
+
     // => SCOPE(c) |= SCOPE(*b) = [] | [static] (final)
    // => DEFER because SCOPE(*b) = SCOPE(b) is incomplete
+
     // (dereferencing loses information => static)
    // 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:
 
     // we now have:
 
     // SCOPE(a) = [a]
 
     // SCOPE(a) = [a]
     // SCOPE(b) = [a]
+
     // SCOPE(b) = []
     // SCOPE(c) = [d]
+
     // SCOPE(c) = [static]
    // 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
 
     // => all resolved
 
     // ---------------------------------------------------
 
     // ---------------------------------------------------
 
     // => satisfiable, now let's check the assignments:
 
     // => satisfiable, now let's check the assignments:
  
     int** b = a;        // [a] := [a]   => OK
+
     int** b = a;        // []       := [a]         => OK
 
     int d;
 
     int d;
     int* c = &d;        // [a] := [d]   => BAD
+
     int* c = &d;        // [static] := [d]         => BAD
     *b = c;            // [a] := [a]   => OK
+
     *b = c;            // [static] := [static]   => OK
     // => invalid assignments
+
     // => invalid assignment
 
     // note how it even traces where the bad value comes from
 
     // note how it even traces where the bad value comes from
 
}
 
}
Line 61: Line 44:
 
<source lang="D">
 
<source lang="D">
 
void foo(T)(T** a) {
 
void foo(T)(T** a) {
     // for parameters, start with self-owned scope
+
     // start with empty scope params
     // => SCOPE(a) := [a] (incomplete)
+
     // => SCOPE(a) := [] (incomplete)
 
     T** b;
 
     T** b;
 
     // start with empty scope for locals
 
     // start with empty scope for locals
Line 70: Line 53:
 
     // => SCOPE(a) |= SCOPE(b)
 
     // => SCOPE(a) |= SCOPE(b)
 
     // => DEFER because SCOPE(b) is incomplete
 
     // => DEFER because SCOPE(b) is incomplete
    // first assignment to `b`:
 
    // => SCOPE(b) |= SCOPE(a)
 
    // => DEFER because SCOPE(a) is incomplete
 
 
     T d;
 
     T d;
 
     T* c;
 
     T* c;
 
     // => SCOPE(c) = [] (incomplete)
 
     // => SCOPE(c) = [] (incomplete)
 
     c = &d;
 
     c = &d;
    // only access to `&d`:
 
    // => SCOPE(&d) := [d] (final)
 
    // assignment to `c`:
 
    // => SCOPE(c) |= SCOPE(&d) = [d] (incomplete)
 
 
     *b = c;
 
     *b = c;
 
     // assignment from `c`:
 
     // assignment from `c`:
     // => SCOPE(c) |= SCOPE(*b)
+
     // => SCOPE(c) |= SCOPE(*b) = [] | [static] = [static]
    // => 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:
 
     // we now have:
     // SCOPE(a) = [a]
+
     // SCOPE(a) = []
 
     // SCOPE(b) = []
 
     // SCOPE(b) = []
     // SCOPE(c) = [d]
+
     // SCOPE(c) = [static]
 
     // unresolved:
 
     // unresolved:
 
     // SCOPE(a) |= SCOPE(b)
 
     // SCOPE(a) |= SCOPE(b)
     // SCOPE(b) |= SCOPE(a)
+
     // resolve:
     // SCOPE(b) |= SCOPE(c)
+
     // SCOPE(a) := [] | [] = []
    // 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
 
     // => all resolved
 
     // ---------------------------------------------------
 
     // ---------------------------------------------------
 
     // => satisfiable, now let's check the assignments:
 
     // => satisfiable, now let's check the assignments:
  
     int** b = a;        // [a] := [a]   => OK
+
     int** b = a;        // []       := []         => OK
 
     int d;
 
     int d;
     int* c = &d;        // [a] := [d]   => BAD
+
     int* c = &d;        // [static] := [d]       => BAD
     *b = c;            // [a] := [a]  => OK
+
     *b = c;            // [static] := [static]  => OK
     // => invalid assignments
+
     // => invalid assignment
 
     // again, the culprit can be detected
 
     // again, the culprit can be detected
 
}
 
}
 
</source>
 
</source>

Revision as of 10:41, 28 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` => self-owned
    // ("mystery scope" in your terms)
    // => SCOPE(a) := [a] (final)
    int** b;
    // => SCOPE(b) := [] (incomplete)
    b = a;
    // scope of `a` is fixed => do nothing
    int d;
    int* c;
    // => SCOPE(c) := [] (incomplete)
    c = &d;
    *b = c;
    // assignment from `c`:
    // => SCOPE(c) |= SCOPE(*b) = [] | [static] (final)
    // (dereferencing loses information => static)
    // ---------------------------------------------------
    // we now have:
    // SCOPE(a) = [a]
    // SCOPE(b) = []
    // SCOPE(c) = [static]
    // => all resolved
    // ---------------------------------------------------
    // => satisfiable, now let's check the assignments:

    int** b = a;        // []       := [a]         => OK
    int d;
    int* c = &d;        // [static] := [d]         => BAD
    *b = c;             // [static] := [static]    => OK
    // => invalid assignment
    // 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) {
    // start with empty scope params
    // => SCOPE(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
    T d;
    T* c;
    // => SCOPE(c) = [] (incomplete)
    c = &d;
    *b = c;
    // assignment from `c`:
    // => SCOPE(c) |= SCOPE(*b) = [] | [static] = [static]
    // ---------------------------------------------------
    // we now have:
    // SCOPE(a) = []
    // SCOPE(b) = []
    // SCOPE(c) = [static]
    // unresolved:
    // SCOPE(a) |= SCOPE(b)
    // resolve:
    // SCOPE(a) := [] | [] = []
    // => all resolved
    // ---------------------------------------------------
    // => satisfiable, now let's check the assignments:

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