[svn] r7581: nemerle/trunk/ncc: generation/Typer3.n
testsuite/negative/base-calls.n testsuite/positive/bas...
divan
svnadmin at nemerle.org
Mon Apr 9 06:57:37 CEST 2007
Log:
Add very simple control flow analysis tool, fix 976.
Author: divan
Date: Mon Apr 9 06:57:34 2007
New Revision: 7581
Modified:
nemerle/trunk/ncc/generation/Typer3.n
nemerle/trunk/ncc/testsuite/negative/base-calls.n
nemerle/trunk/ncc/testsuite/positive/base-calls.n
Modified: nemerle/trunk/ncc/generation/Typer3.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer3.n (original)
+++ nemerle/trunk/ncc/generation/Typer3.n Mon Apr 9 06:57:34 2007
@@ -30,6 +30,7 @@
using Nemerle.Utility;
using Nemerle.Compiler;
+using PT = Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Compiler.SolverMacros;
@@ -91,6 +92,8 @@
// typer of our typer method or null for top-level methods
parent : Typer3;
+ is_ctor : bool;
+
// current method we're working on
the_method : MethodBuilder;
@@ -169,6 +172,7 @@
}
this.parent = parent;
+ is_ctor = current_local_fun.name == ".ctor";
}
@@ -992,26 +996,304 @@
initializers
}
+ #region ctors, base calls, etc
+ /*
+ Simple execution flow analysis tool
+ Computes [result] : T for expression [e]
+ [f] is used to find atomic results,
+ i.e. when f(e) isn't None result is f(e)
+ if it's None we transform expression to
+ - sequence, and pass it to [seq]
+ - several sequences, pass them to [fork]
+ for all other expressions we return [default]
+ */
+ SimpleFlow[T] (e : TExpr,
+ f : TExpr -> option[T],
+ default : T,
+ seq : list[TExpr] -> T,
+ fork : list[list[TExpr]] -> T) : T
+ {
+ def SimpleFlow = SimpleFlow(_, f, default, seq, fork);
+ match (f (e)) {
+ | Some (t) => t
+ | _ =>
+ match (e) {
+ | TExpr.FieldMember (e, _)
+ | TExpr.MethodRef (e, _, _, _)
+ | TExpr.Throw (e)
+ | TExpr.DefFunctionsIn (_, e)
+ | TExpr.HasType (e, _)
+ | TExpr.MacroEnvelope (_, _, e)
+ | TExpr.TypeConversion (e, _, _, _)
+ | TExpr.Label (_, e)
+ => SimpleFlow (e)
+
+ | TExpr.Call (e, p, _)
+ => def lst = List.Map (p, x => x.expr);
+ def lst = lst.Append ([e]);
+ seq (lst);
+
+ | TExpr.DefValIn (_, v, e)
+ => seq ( [v, e] )
+
+ | TExpr.Assign (t, s)
+ => seq ( [t, s] )
+
+ | TExpr.TryFinally (b, h)
+ => fork ([h] :: [b, h] :: [])
+
+ //TODO: analyze catchs?
+ //like fork ( [b] :: List.Map (cs, x => [b, x.handler]) +
+ // [ ] :: List.Map (cs, x => [ x.handler]) )
+ | TExpr.Try (b, _)
+ => fork ([] :: [b] :: [])
+
+ | TExpr.Sequence (a, b)
+ => seq ( [a, b] )
+ | TExpr.MultipleAssign (la)
+ => seq (List.Map (la, x => x[1]))
+ | TExpr.Tuple (l)
+ => seq (l)
+ | TExpr.Array (l, d)
+ => seq (l + d)
+ | TExpr.ArrayIndexer (a, l)
+ => seq (a :: l)
+ | TExpr.TupleIndexer (a, _, _)
+ => SimpleFlow (a)
+
+ | TExpr.If (c, a, b)
+ => fork ( [c, a] :: [c, b] :: [] )
+ | TExpr.Switch (e, Some (c), cs)
+ => fork ([e, c] :: List.Map (cs, x => [e, x[1]]))
+ | TExpr.Switch (e, None, cs)
+ => fork ([e ] :: List.Map (cs, x => [e, x[1]]))
+ | TExpr.Match (e, cs)
+ => fork (List.Map (cs, x => [e, x.body]))
+
+ | TExpr.StaticRef | TExpr.LocalRef | TExpr.LocalFunRef
+ | TExpr.Literal | TExpr.This | TExpr.DefaultValue
+ | TExpr.ImplicitValueTypeCtor
+ | TExpr.Base | TExpr.SelfTailCall
+ | TExpr.MethodAddress
+ | TExpr.TypeOf
+ | TExpr.OpCode
+ | TExpr.Goto
+ => default;
+
+ //invalid things
+ | TExpr.PropertyMember
+ | TExpr.StaticPropertyRef
+ | TExpr.EventMember
+ | TExpr.StaticEventRef
+ | TExpr.ConstantObjectRef
+ | TExpr.Block
+ | TExpr.Delayed
+ | TExpr.Cache
+ | TExpr.CacheRef
+ | TExpr.Error
+ => Util.ice ("invalid expression in Typer3")
+ }
+ }
+ }
- GetBaseCall () : option [TExpr]
+ IsCtor (_ : TExpr) : bool
{
- // put base () / this () call before storing 'this' in closure inside constructor
- if (current_local_fun.name == ".ctor" && !CurrentType.IsValueType)
- match (current_local_fun.body) {
- | FunBody.Typed (TExpr.Sequence (TExpr.Call as basecall, rest)) =>
- current_local_fun.body = FunBody.Typed (rest);
- Some (Walk (basecall))
-
- | FunBody.Typed (TExpr.Call as basecall) =>
- current_local_fun.body = FunBody.Typed (BuildRevSequence ([]));
- Some (Walk (basecall))
+ | TExpr.Base => true
+ | TExpr.MacroEnvelope (_, _, e) => IsCtor (e)
+ | _ => false
+ }
- // ctor call is (if not, it's a bug) placed somewhere inside, but this case disallows using 'this' in closures
- | FunBody.Typed (_) => Some (null)
+ IsBaseCtor (_ : TExpr) : bool
+ {
+ | TExpr.Base (mth) =>
+ !CurrentType.GetConstructors (). Contains (mth)
+ | TExpr.MacroEnvelope (_, _, e) => IsBaseCtor (e)
+ | _ => false
+ }
- | _ => assert (false)
+ /*
+ Inject expressions before base ctor call, after this ctor call
+ If expression is null then don't inject it.
+ Used to inject field inits before and closure init after.
+ */
+ InjectAroundCtor (e : TExpr, beforeBase : TExpr, afterThis : TExpr) : TExpr
+ {
+ def inject (e : TExpr, inits : TExpr, post_init : TExpr)
+ {
+ def inject = inject (_, inits, post_init);
+ def o = e;
+ match (e) {
+ | TExpr.StaticRef | TExpr.LocalRef | TExpr.LocalFunRef
+ | TExpr.Literal | TExpr.This | TExpr.DefaultValue
+ | TExpr.ImplicitValueTypeCtor
+ | TExpr.Base | TExpr.SelfTailCall
+ | TExpr.MethodAddress
+ | TExpr.TypeOf
+ | TExpr.OpCode | TExpr.Goto
+ => e
+
+ | TExpr.FieldMember (e, z) =>
+ TExpr.FieldMember (o.loc, o.ty, inject (e), z)
+
+ | TExpr.MethodRef (e, z, x, c) =>
+ TExpr.MethodRef (o.loc, o.ty, inject (e), z, x, c)
+
+ | TExpr.Throw (e) => TExpr.Throw (o.loc, o.ty, inject (e))
+
+ | TExpr.DefFunctionsIn (q, e) =>
+ TExpr.DefFunctionsIn (o.loc, o.ty, q, inject (e))
+
+ | TExpr.DefValIn (z, v, e) =>
+ TExpr.DefValIn (o.loc, o.ty, z, inject (v), inject (e))
+
+ | TExpr.HasType (e, z) =>
+ TExpr.HasType (o.loc, o.ty, inject (e), z)
+
+ | TExpr.MacroEnvelope (z, x, e) =>
+ TExpr.MacroEnvelope (o.loc, o.ty, z, x, inject (e))
+
+ | TExpr.TypeConversion (e, z, x, c) =>
+ TExpr.TypeConversion (o.loc, o.ty, inject (e), z, x, c)
+
+ | TExpr.Label (z, e) =>
+ TExpr.Label (o.loc, o.ty, z, inject (e))
+
+ | TExpr.Call (e, p, t) when IsBaseCtor (e) =>
+ def p = List.Map (p,
+ x => Parm (x.kind, inject (x.expr), x.name, x.required_type)
+ );
+ def expr = TExpr.Call (o.loc, o.ty, e, p, t);
+ match ((inits, post_init)) {
+ | (null, null) => expr
+ | (_, null) => TExpr.Sequence (o.loc, o.ty, inits, expr)
+ | (null, _) => TExpr.Sequence (o.loc, o.ty, expr, post_init);
+ | _ => TExpr.Sequence (o.loc, o.ty,
+ inits,
+ TExpr.Sequence (o.loc, o.ty, expr, post_init)
+ )
+ }
+
+ | TExpr.Call (e, p, t) when IsCtor (e) =>
+ def p = List.Map (p,
+ x => Parm (x.kind, inject (x.expr), x.name, x.required_type)
+ );
+ def expr = TExpr.Call (o.loc, o.ty, e, p, t);
+ match (post_init) {
+ | null => expr
+ | _ => TExpr.Sequence (o.loc, o.ty, expr, post_init)
+ }
+
+ | TExpr.Call => e
+
+ | TExpr.Assign (a, b) =>
+ TExpr.Assign (o.loc, o.ty, inject (a), inject (b))
+
+ | TExpr.TryFinally (b, h) =>
+ TExpr.TryFinally (o.loc, o.ty, inject (b), inject (h))
+
+ | TExpr.Try (b, cs) =>
+ TExpr.Try (o.loc, o.ty, inject (b), cs)
+
+ | TExpr.Sequence (a, b) =>
+ TExpr.Sequence (o.loc, o.ty, inject (a), inject (b))
+
+ | TExpr.MultipleAssign (la) =>
+ TExpr.MultipleAssign (o.loc, o.ty,
+ List.Map ( la, x => (x[0], inject (x[1])) )
+ )
+
+ | TExpr.Tuple (l) =>
+ TExpr.Tuple (o.loc, o.ty, List.Map (l, inject))
+
+ | TExpr.Array (l, d) =>
+ TExpr.Array (o.loc, o.ty,
+ List.Map (l, inject), List.Map (d, inject)
+ )
+
+ | TExpr.ArrayIndexer (a, l) =>
+ TExpr.ArrayIndexer (o.loc, o.ty,
+ inject (a),
+ List.Map (l, inject)
+ )
+
+ | TExpr.TupleIndexer (a, z, x) =>
+ TExpr.TupleIndexer (o.loc, o.ty, inject (a), z, x)
+
+ | TExpr.If (c, a, b) =>
+ TExpr.If (o.loc, o.ty, inject (c), inject (a), inject (b))
+
+ | TExpr.Switch (e, Some (c), cs) =>
+ TExpr.Switch (o.loc, o.ty,
+ inject (e),
+ Some (inject (c)),
+ List.Map ( cs, x => (x[0], inject (x[1])) )
+ )
+
+ | TExpr.Switch (e, None, cs) =>
+ TExpr.Switch (o.loc, o.ty,
+ inject (e),
+ None (),
+ List.Map ( cs, x => (x[0], inject (x[1])) )
+ )
+
+ | TExpr.Match (e, cs) =>
+ TExpr.Match (o.loc, o.ty,
+ inject (e),
+ List.Map (cs, x =>
+ Match_case (x.patterns, inject (x.body), x.disable_warnings)
+ )
+ )
+
+ //invalid things
+ | TExpr.PropertyMember
+ | TExpr.StaticPropertyRef
+ | TExpr.EventMember
+ | TExpr.StaticEventRef
+ | TExpr.ConstantObjectRef
+ | TExpr.Block
+ | TExpr.Delayed
+ | TExpr.Cache
+ | TExpr.CacheRef
+ | TExpr.Error
+ => Util.ice ("invalid expression in Typer3")
+ }
+ }
+ inject (e, beforeBase, afterThis);
+ }
+#endregion
+
+ FixBaseCall (clo_ini : TExpr = null) : void
+ {
+ // put base () / this () call before storing 'this' in closure inside constructor
+ when (is_ctor && !CurrentType.IsValueType)
+ {
+ def ini = null;
+ mutable e = match (current_local_fun.body) {
+ | FunBody.Typed (e) => e
+ | _ => Util.ice ("bad function body")
+ }
+ when (clo_ini != null)
+ {
+ def f (_) {
+ | TExpr.Call (e, _, _) when IsCtor (e) => Some (true)
+ | _ => None ()
+ }
+ and ctor_calls (e) {
+ SimpleFlow (e, f, false, seq, fork)
+ }
+ and seq (_) {
+ | e :: _ => ctor_calls (e)
+ | _ => false
+ }
+ and fork (l) {
+ List.ForAll (l, seq)
+ }
+ when (!ctor_calls (e))
+ Message.Error ("closure utilizing 'this' reference is not allowed when base ctor call is not placed at the beginning of current ctor");
+ }
+ e = InjectAroundCtor (e, ini, clo_ini);
+ current_local_fun.body = FunBody.Typed (e);
}
- else None ()
}
@@ -1036,27 +1318,21 @@
initializers = LoadParameters () + initializers;
- mutable base_call_missing = false;
- match (GetBaseCall ()) {
- | Some (null) => base_call_missing = true;
- | Some (call) =>
- initializers = call :: initializers;
- | None => {}
- }
-
+ mutable ini = null;
// store 'this' into closure object
foreach (d in current_local_fun.closure_vars)
when (d.InClosure &&
d.ValKind is LocalValue.Kind.ClosurisedThisPointer) {
- when (base_call_missing)
- Message.Error ("closure utilizing 'this' reference is not allowed when base ctor call is not placed at the beginning of current ctor");
- def ini =
+ ini =
TExpr.Assign (InternalType.Void,
LocalRef (d, for_store = true),
TExpr.This (CurrentType.GetMemType ()));
- initializers = ini :: initializers;
}
+ FixBaseCall (ini);
+ unless (is_ctor && !CurrentType.IsValueType)
+ when (ini != null)
+ initializers ::= ini;
initializers
}
#endregion
Modified: nemerle/trunk/ncc/testsuite/negative/base-calls.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/negative/base-calls.n (original)
+++ nemerle/trunk/ncc/testsuite/negative/base-calls.n Mon Apr 9 06:57:34 2007
@@ -13,3 +13,21 @@
myfun ();
}
}
\ No newline at end of file
+
+class A {
+ mutable x : int;
+ static q () : void {}
+ static w (_ : void -> void) : void {}
+ public this (mutable y : int = 7) { // E: closure utilizing 'this' reference is not allowed when base ctor call is not placed at the beginning of current ctor
+ q ();
+ --y;
+ base ();
+ this.x = 1;
+ def f() {++x};
+ f ();
+ w (f);
+ }
+ public static Main () : void {
+ System.Console.WriteLine (A ().x)
+ }
+}
\ No newline at end of file
Modified: nemerle/trunk/ncc/testsuite/positive/base-calls.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/base-calls.n (original)
+++ nemerle/trunk/ncc/testsuite/positive/base-calls.n Mon Apr 9 06:57:34 2007
@@ -49,6 +49,7 @@
b.Prop += 3;
def _ = Inherit(1);
_ = Closurising (5);
+ System.Console.WriteLine (A976 ().x)
}
}
@@ -81,7 +82,23 @@
myfun ();
}
}
-
+class A976 {
+ public mutable x : int;
+ static q () : void {}
+ static w (_ : void -> void) : void {}
+ public this (mutable y : int = 7) {
+ if (y == 1)
+ base ();
+ else
+ base ();
+ q ();
+ --y;
+ this.x = 1;
+ def f() {++x};
+ f ();
+ w (f);
+ }
+}
/*
BEGIN-OUTPUT
A.m
@@ -95,5 +112,6 @@
fun 5 and aaa and no fld
A()
fun 5 and bbb and no fld
+2
END-OUTPUT
*/
More information about the svn
mailing list