Difference between revisions of "User talk:Schuetzm/scope2"
(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(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 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
// --------------------------------------------------- | // --------------------------------------------------- | ||
// => satisfiable, now let's check the assignments: | // => satisfiable, now let's check the assignments: | ||
− | int** b = a; // [a] | + | int** b = a; // [a] := [a] => OK |
int d; | int d; | ||
− | int* c = &d; // [a] | + | int* c = &d; // [a] := [d] => BAD |
− | *b = c; // [a] | + | *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 | + | // 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(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] = [ | + | // tmp := SCOPE(a) | SCOPE(b) | SCOPE(c) = [a] | [] | [d] = [a] |
− | // SCOPE(a) := tmp = [ | + | // SCOPE(a) := tmp = [a] |
− | // SCOPE(b) := tmp = [ | + | // SCOPE(b) := tmp = [a] |
− | // SCOPE(c) := tmp = [ | + | // SCOPE(c) := tmp = [a] |
// => all resolved | // => all resolved | ||
// --------------------------------------------------- | // --------------------------------------------------- | ||
− | // | + | // => satisfiable, now let's check the assignments: |
− | // a: [a] > | + | |
− | // | + | 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 | ||
} | } | ||
</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
}