Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs/docs
diff options
context:
space:
mode:
authorMartin Baulig <martin@novell.com>2006-09-12 20:38:26 +0400
committerMartin Baulig <martin@novell.com>2006-09-12 20:38:26 +0400
commitec4c7e629828e99f7d0d9b02aecfc97f7bdc5317 (patch)
tree76285df1704639d5819ae798bc31364738649a0f /mcs/docs
parent40640866eb802a902747ce3628317366cc2026cf (diff)
Added a document describing the new anonymous methods design.
svn path=/trunk/mcs/; revision=65328
Diffstat (limited to 'mcs/docs')
-rw-r--r--mcs/docs/new-anonymous-design.txt197
1 files changed, 197 insertions, 0 deletions
diff --git a/mcs/docs/new-anonymous-design.txt b/mcs/docs/new-anonymous-design.txt
new file mode 100644
index 00000000000..402654b5f82
--- /dev/null
+++ b/mcs/docs/new-anonymous-design.txt
@@ -0,0 +1,197 @@
+Anonymous Methods and the TypeContainer resolve order
+-----------------------------------------------------
+
+Anonymous methods add another resolving pass to the TypeContainer framework.
+The new code works like this:
+
+* Everything which may contain anonymous methods or iterators now
+ implements the `IAnonymousHost' interface. This applies to
+ `Method', `Constructor', `Accessor' and `Operator'.
+
+ We can already determine whether or not a method contains anonymous
+ methods or iterators at parsing time, but we can't determine their
+ types yet. If we encounter an anonymous method or iterator while
+ parsing, we add the information to the current `IAnonymousHost'.
+
+ This means that at the end of the parsing stage, we already know
+ about all anonymous methods and iterators, but didn't resolve them
+ yet.
+
+* After parsing, RootContext.ResolveTree() calls DefineType() on all
+ TypeContainers.
+
+* Inside TypeContainer.DefineType(), we do the following:
+
+ - first we have to create our TypeBuilder via DefineTypeBuilder().
+
+ - after that, we scan all methods, constructors, operators and
+ property/indexer accessors for anonymous methods and iterators.
+
+ For each method which either contains anonymous methods or is
+ implemented as iterator, we create a new helper class (the "root
+ scope" of the anonymous method) and add it to the current type as
+ a nested class.
+
+ This is done by the new TypeContainer.ResolveMembers() method.
+
+ - when done, we call DefineNestedTypes() to descend into our nested
+ children.
+
+* RootContext.PopulateTypes() calls TypeContainer.ResolveType() and
+ TypeContainer.DefineMembers() as usual and populates everything.
+
+* In TypeContainer.EmitType(), we call DefineMembers() and EmitType()
+ on all our CompilerGeneratedClass'es once we're done emitting the
+ current type.
+
+One of the hardest parts of the new anonymous methods implementation
+was getting this resolve order right. It may sound complicated, but
+there are reasons why it's done this way.
+
+Let's have a look at a small example:
+
+ =====
+ delegate void Foo ();
+
+ class X {
+ public void Hello<U> (U u)
+
+ public void Test<T> (T t)
+ {
+ T u = t;
+ Hello (u);
+ Foo foo = delegate {
+ Hello (u);
+ };
+ foo ();
+ }
+ }
+ =====
+
+After parsing this file, we already know that Test() contains an
+anonymous method, but we don't know its type until resolving it.
+
+Because Test() is a generic method, we need to create a generic helper
+class and then transform all method type parameters into class type
+parameters.
+
+One key feature of the new code is using the normal TypeContainer
+framework to create and use generic classes. For each method
+containing anonymous methods, we create one "root scope" which deals
+with generics and also hosts any captured parameter and `this'.
+
+In this example, this is done when calling DefineType() on `X's
+TypeContainer, during the ResolveMembers() pass. After that, we can
+handle the helper classes just like normal nested classes, so
+DefineNestedTypes() creates their TypeBuilders.
+
+One important thing to keep in mind is that we neither know the type
+of the anonymous methods nor any captured variables until resolving
+`Test'. Note that a method's block isn't resolved until
+TypeContainer.EmitCode(), so we can't call DefineMembers() on our
+CompilerGeneratedClass'es until we emitted all methods.
+
+
+Anonymous Methods and Scopes:
+-----------------------------
+
+The new code fundamentally changes the concept of CaptureContexts and
+ScopeInfos. CaptureContext is completely gone while the ScopeInfo has
+been completely redesigned.
+
+Each method containing anonymous methods introduces a "root scope" in
+which all other scopes are nested. This root scope is also called the
+anonymous method's host (class `AnonymousMethodHost' in anonymous.cs).
+
+The root scope deals with everything related to generics and also
+hosts the parameters and `this'. All other scopes are nested inside
+the root scope.
+
+Note that if you have child scopes, they're all nested directly inside
+the root scope, not inside each other. Because of that, we don't need
+to link / reparent them.
+
+Anonymous Methods and Generics:
+-------------------------------
+
+Creating and consuming generic types is very difficult and you have to
+follow certain rules to do it right (the most important one is that
+you may not use the class until it's fully created).
+
+GMCS already has working code to do that - and one very important
+policy in the new anonymous methods code is that it must not interfer
+with GMCS's way of resolving and defining generic types; ie. everything
+related to generics is handled during the normal TypeContainer
+resolving process.
+
+When the anonymous methods code kicks in, all the generic types are
+already defined and ready for use.
+
+Adding a new non-generic class to such a generic type is really easy
+and not a problem - non-generic means that the new class does not
+introduce any new type parameters; it may still use its containing
+class'es type parameters:
+
+Example:
+
+ class IAmGeneric<T>
+ {
+ class IAmNot // must derive from System.Object
+ {
+ // using the containing classe's type parameter is ok.
+ public T ButMayStillUseMyParentsT;
+ }
+ }
+
+
+The new `Variable' abstraction:
+-------------------------------
+
+There is a new `Variable' abstraction which is used for locals and
+parameters; all the knowledge about how to access a variable and
+whether it's captured or not is now in that new abstract `Variable'
+class. The `LocalVariableReference' and `ParameterReference' now
+share most of their code and have a common `VariableReference' base
+class, which is also used by `This'.
+
+`Variable' also controls whether or not we need to create a temporary
+copy of a variable.
+
+Before emitting any method, we scan over all its parameters and local
+variables again and check whether any of them have been captured.
+
+`Parameter' and `LocalInfo' both have a new ResolveVariable() method
+which creates an instance of the new `Variable' class for each of
+them.
+
+If we're captured, a `Field' has already been created for the variable
+and since we're called during the normal TypeContainer resolve / emit
+process, there' no additional "magic" required; it "just works".
+
+ CAUTION: Inside the anonymous method, the `Variable's type
+ determines the variable's actual type - outside it
+ is the ParameterReference / LocalVariableReference's
+ type !
+
+ To make it more clear:
+
+ The type of a ParameterReference / LocalVariableReference
+ depends upon whether we're inside our outside the anonymous
+ method - and in case of generic, they are different !!!
+
+ The normal situation is that outside the anonymous method,
+ we may use the generic method parameters directly (ie.
+ MONO_TYPE_MVAR) - but inside the anonymous method, we're in
+ and generic class, not a generic method - so it's a generic
+ type parameter (MONO_TYPE_VAR).
+
+ There are several tests for this in my new test suite.
+
+ This does not only apply to variables; it's the same for types -
+ the same `T' may mean a completely different type depending upon
+ whether we're inside or outside the anonymous method: outside,
+ it's a generic method parameter (MONO_TYPE_MVAR) and inside, it's
+ a generic type parameter (MONO_TYPE_VAR) - so we already need to
+ handle this in the EmitContext to make SimpleNameResolve work.
+
+