+2004-01-21 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldInfo.AddressOf): Revert patch from previous
+ #52730 bug, and instead compute correctly the need to use a
+ temporary variable when requesting an address based on the
+ static/instace modified of the field and the constructor.
+
+2004-01-21 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (SimpleName.ResolveAsTypeStep): Lookup in the current
+ class and namespace before looking up aliases. Fixes #52517.
+
+2004-01-21 Martin Baulig <martin@ximian.com>
+
+ * flowanalysis.cs (UsageVector.Merge): Allow variables being
+ assinged in a 'try'; fixes exception4.cs.
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+ * class.cs : Implemented parameter-less constructor for TypeContainer
+
+ * decl.cs: Attributes are now stored here. New property OptAttributes
+
+ * delegate.cs, enum.cs, interface.cs: Removed attribute member.
+
+ * rootcontext.cs, tree.cs: Now use parameter-less constructor of TypeContainer
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+
+ * typemanager.cs (CSharpSignature): Now reports also inner class name.
+ (CSharpSignature): New method for indexer and property signature.
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+
+ * pending.cs (IsVirtualFilter): Faster implementation.
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+
+ * typemanager.cs: Avoid inclusion of same assembly more than once.
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+
+ * cs-parser.jay: Fixed problem where the last assembly attribute
+ has been applied also to following declaration (class, struct, etc.)
+
+2004-01-21 Marek Safar <marek.safar@seznam.cz>
+
+ * class.cs: Added error CS0538, CS0539 reporting.
+ Fixed crash on Microsoft runtime when field type is void.
+
+ * cs-parser.jay: Added error CS0537 reporting.
+
+ * pending.cs: Added error CS0535 reporting.
+ Improved error report for errors CS0536, CS0534.
+
+2004-01-20 Miguel de Icaza <miguel@ximian.com>
+
+ Merge a few bits from the Anonymous Method MCS tree.
+
+ * statement.cs (ToplevelBlock): New class for toplevel methods,
+ will hold anonymous methods, lifted variables.
+
+ * cs-parser.jay: Create toplevel blocks for delegates and for
+ regular blocks of code.
+
+2004-01-20 Martin Baulig <martin@ximian.com>
+
+ * codegen.cs (EmitContext): Removed `InTry', `InCatch',
+ `InFinally', `InLoop', `TryCatchLevel', `LoopBeginTryCatchLevel'
+ and `NeedExplicitReturn'; added `IsLastStatement'.
+ (EmitContext.EmitTopBlock): Emit the explicit "ret" if we either
+ have a `ReturnLabel' or we're not unreachable.
+
+ * flowanalysis.cs (FlowBranching.MergeChild): Actually merge the
+ child's reachability; don't just override ours with it. Fixes
+ #58058 (lluis's example).
+ (FlowBranching): Added public InTryOrCatch(), InCatch(),
+ InFinally(), InLoop(), InSwitch() and
+ BreakCrossesTryCatchBoundary() methods.
+
+ * statement.cs (Return): Do all error checking in Resolve().
+ Unless we are the last statement in a top-level block, always
+ create a return label and jump to it.
+ (Break, Continue): Do all error checking in Resolve(); also make
+ sure we aren't leaving a `finally'.
+ (Block.DoEmit): Set `ec.IsLastStatement' when emitting the last
+ statement in a top-level block.
+ (Block.Flags): Added `IsDestructor'.
+ (Block.IsDestructor): New public property.
+
+2004-01-20 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Break.DoEmit): Set ec.NeedExplicitReturn; fixes #52427.
+
+2004-01-20 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Statement.ResolveUnreachable): New public method.
+ (If, While): Do the dead-code elimination in Resolve(), not in Emit().
+ (Block.Resolve): Resolve unreachable statements.
+
+2004-01-19 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * expression.cs: We need to fix the case where we do
+ not have a temp variable here.
+
+ * assign.cs: Only expression compound assignments need
+ temporary variables.
+
+2004-01-19 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * flowanalysis.cs: Reduce memory allocation in a few ways:
+ - A block with no variables should not allocate a bit
+ vector for itself.
+ - A method with no out parameters does not need any tracking
+ for assignment of the parameters, so we need not allocate
+ any data for it.
+ - The arrays:
+ public readonly Type[] VariableTypes;
+ public readonly string[] VariableNames;
+ Are redundant. The data is already stored in the variable
+ map, so we need not allocate another array for it.
+ - We need to add alot of checks for if (params | locals) == null
+ due to the first two changes.
+
+2004-01-18 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.AddressOf): For ValueTypes that do not
+ implement IMemoryLocation, we store a copy on a local variable and
+ take the address of it. Patch from Benjamin Jemlich
+
+ * cs-parser.jay: Applied patch from Ben Maurer to the "type" rule
+ to use a special "type_name_expression" rule which reduces the
+ number of "QualifiedIdentifier" classes created, and instead
+ directly creates MemberAccess expressions.
+
+2004-01-17 Miguel de Icaza <miguel@ximian.com>
+
+ * convert.cs: Applied patch from Benjamin Jemlich (pcgod@gmx.net)
+ that fixes #52853. Null literal assignment to ValueType
+
+ * class.cs (MethodData.Emit): Instead of checking the name of the
+ method to determine if its a destructor, create a new derived
+ class from Method called Destructor, and test for that.
+
+ * cs-parser.jay: Create a Destructor object instead of a Method.
+
+ Based on a fix from Benjamin Jemlich (pcgod@gmx.net)
+
+ Fixes: 52933
+
+2004-01-16 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): Perform an implicit
+ conversion from MethodGroups to their delegate types on the
+ Addition operation.
+
+ * delegate.cs: Introduce a new class DelegateCreation that is the
+ base class for `NewDelegate' and `ImplicitDelegateCreation',
+ factor some code in here.
+
+ * convert.cs (Convert.ImplicitConversionStandard): Add an implicit
+ conversion from MethodGroups to compatible delegate types.
+
+ * ecore.cs (Expression.Resolve): Do not flag error 654
+ (Methodgroupd needs parenthesis) if running on the V2 compiler, as
+ we allow conversions from MethodGroups to delegate types now.
+
+ * assign.cs (Assign.DoResolve): Do not flag errors on methodgroup
+ assignments in v2 either.
+
+2004-01-10 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.AddressOf): Fix generated IL for accessing
+ static read-only fields in ctors.
+
+ Applied patch from Benjamin Jemlich
+
+ * expression.cs (UnaryMutator): Avoid leaking local variables.
+
+2004-01-09 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs (IsCastToken): Allow the various native types
+ here to return true, as they can be used like this:
+
+ (XXX) int.MEMBER ()
+
+ Fixed 49836 and all the other dups
+
+2004-01-09 Zoltan Varga <vargaz@freemail.hu>
+
+ * driver.cs: Implement /win32res and /win32icon.
+
+2004-01-08 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add a rule to improve error handling for the
+ common mistake of placing modifiers after the type.
+
+2004-01-07 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (interface_event_declaration): Catch
+ initialization of events on interfaces, and report cs0068
+
+ * cs-parser.jay (interface_event_declaration): Catch
+ initialization of events.
+
+ * ecore.cs: Better report missing constructors.
+
+ * expression.cs (Binary.ResolveOperator): My previous bug fix had
+ the error reporting done in the wrong place. Fix.
+
+ * expression.cs (Binary.ResolveOperator): Catch the
+ operator + (E x, E y) error earlier, and later allow for implicit
+ conversions in operator +/- (E e, U x) from U to the underlying
+ type of E.
+
+ * class.cs (TypeContainer.DefineDefaultConstructor): Fix bug
+ 52596, if the container class is abstract, the default constructor
+ is protected otherwise its public (before, we were always public).
+
+ * statement.cs (Fixed.Resolve): Catch a couple more errors in the
+ fixed statement.
+
+ (Using.EmitLocalVariableDecls): Applied patch from Benjamin
+ Jemlich that fixes bug #52597, MCS was generating invalid code for
+ idisposable structs. Thanks to Ben for following up with this
+ bug as well.
+
+2004-01-06 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Allow assemblies without code to be generated, fixes
+ 52230.
+
+2004-01-07 Nick Drochak <ndrochak@gol.com>
+
+ * attribute.cs: Remove unneeded catch variables. Eliminates a warning.
+
+2004-01-05 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add rules to improve error reporting if fields or
+ methods are declared at the namespace level (error 116)
+
+ * Add rules to catch event add/remove
+
+2004-01-04 David Sheldon <dave-mono@earth.li>
+
+ * expression.cs: Added matching ")" to error message for
+ CS0077
+
+2004-01-03 Todd Berman <tberman@gentoo.org>
+
+ * ecore.cs, attribute.cs:
+ Applying fix from #52429.
+
+2004-01-03 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * ecore.cs, expression.cs, statement.cs:
+ Total rewrite of how we handle branching. We
+ now handle complex boolean expressions with fewer
+ jumps. As well if (x == 0) no longer emits a ceq.
+
+ if (x is Foo) is much faster now, because we generate
+ better code.
+
+ Overall, we get a pretty big improvement on our benchmark
+ tests. The code we generate is smaller and more readable.
+
+ I did a full two-stage bootstrap. The patch was reviewed
+ by Martin and Miguel.
+
+2004-01-03 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * cs-parser.jay: Make primary_expression not take a QI.
+ we dont need this because the member_access rule covers
+ us here. So we replace the rule with just IDENTIFIER.
+
+ This has two good effects. First, we remove a s/r conflict.
+ Second, we allocate many fewer QualifiedIdentifier objects.
+
+2004-01-03 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * attribute.cs: Handle MarshalAs attributes as pseudo, and
+ set the correct information via SRE. This prevents
+ hanging on the MS runtime. Fixes #29374.
+
+2004-01-03 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * convert.cs: correctly handle conversions to value types
+ from Enum and ValueType as unboxing conversions.
+
+ Fixes bug #52569. Patch by Benjamin Jemlich.
+
+2004-01-02 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (BetterConversion): Prefer int -> uint
+ over int -> ulong (csc's behaviour). This fixed bug #52046.
+
+2004-01-02 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * decl.cs (MemberCache.FindMembers): now returns a
+ MemberInfo [].
+
+ * typemanager.cs: In general, go with with ^^.
+ (CopyNewMethods): take an IList.
+ (RealMemberLookup): Only allocate an arraylist
+ if we copy from two sets of methods.
+
+ This change basically does two things:
+ 1) Fewer array lists allocated due to CopyNewMethods.
+ 2) the explicit cast in MemberList costed ALOT.
+
+2004-01-02 Zoltan Varga <vargaz@freemail.hu>
+
+ * cs-tokenizer.cs (consume_identifier) driver.cs: Cache identifiers in
+ a hashtable to avoid needless string allocations when an identifier is
+ used more than once (the common case).
+
+2004-01-01 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * pending.cs: MS's TypeBuilder.GetInterfaces ()
+ is broken, it will not return anything. So, we
+ have to use the information we have in mcs to
+ do the task.
+
+ * typemanager.cs: Add a cache for GetInterfaces,
+ since this will now be used more often (due to ^^)
+
+ (GetExplicitInterfaces) New method that gets the
+ declared, not effective, interfaces on a type
+ builder (eg, if you have interface IFoo, interface
+ IBar, Foo : IFoo, Bar : Foo, IBar, GetExplInt (Bar) ==
+ { IBar }.
+
+ This patch makes MCS able to bootstrap itself on
+ Windows again.
+
+2004-01-01 Ben Maurer <bmaurer@users.sourceforge.net>
+
+ * expression.cs: Remove the Nop's that Miguel put
+ in by mistake.
+
2003-12-31 Ben Maurer <bmaurer@users.sourceforge.net>
* report.cs, codegen.cs: Give the real stack trace to
@ rm -f ../class/lib/mscorlib.dll
@ (cd ../class/corlib ; make BOOTSTRAP_MCS="$(FRIENDLY_TIME) mono ../../mcs/mcs.exe" > /dev/null ) || (echo FAILED; exit 1)
+do-corlib:
+ @ echo -n "corlib: "
+ @ rm -f ../class/lib/mscorlib.dll
+ @ (cd ../class/corlib ; make BOOTSTRAP_MCS="$(FRIENDLY_TIME) mono ../../mcs/mcs.exe" > /dev/null ) || (echo FAILED; exit 1)
+
PROFILER=default
profile : mcs.exe
if ((source.eclass == ExprClass.Type) && (source is TypeExpr)) {
source.Error_UnexpectedKind ("variable or value");
return null;
- } else if (source is MethodGroupExpr){
+ } else if (!RootContext.V2 && (source is MethodGroupExpr)){
((MethodGroupExpr) source).ReportUsageError ();
return null;
+
}
if (target_type == source_type)
//
IAssignMethod am = (IAssignMethod) target;
- if (this is CompoundAssign){
+ if (this is CompoundAssign)
am.CacheTemporaries (ec);
- use_temporaries = true;
- }
if (!is_statement)
use_temporaries = true;
result = ((ArrayCreation) e).EncodeAsAttribute ();\r
if (result != null)\r
return true;\r
+ } else if (e is EmptyCast) {\r
+ result = e;\r
+ if (((EmptyCast) e).Child is Constant) {\r
+ result = ((Constant) ((EmptyCast)e).Child).GetValue();\r
+ }\r
+ return true;\r
}\r
\r
result = null;\r
\r
} else if (e is TypeOf) {\r
prop_values.Add (((TypeOf) e).TypeArg);\r
+ } else if (e is ArrayCreation) {\r
+ prop_values.Add (((ArrayCreation) e).EncodeAsAttribute());\r
} else {\r
Error_AttributeArgumentNotValid (Location);\r
return null;\r
\r
static UnmanagedMarshal GetMarshal (Attribute a)\r
{\r
- UnmanagedMarshal marshal;\r
-\r
- if (a.UnmanagedType == UnmanagedType.CustomMarshaler) {\r
+ object o = GetFieldValue (a, "ArraySubType");\r
+ UnmanagedType array_sub_type = o == null ? UnmanagedType.I4 : (UnmanagedType) o;\r
+ switch (a.UnmanagedType) {\r
+ case UnmanagedType.CustomMarshaler:\r
MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom",\r
BindingFlags.Static | BindingFlags.Public);\r
- if (define_custom == null) {\r
+ if (define_custom == null)\r
return null;\r
- }\r
- object[] args = new object [4];\r
+\r
+ object [] args = new object [4];\r
args [0] = GetFieldValue (a, "MarshalTypeRef");\r
args [1] = GetFieldValue (a, "MarshalCookie");\r
args [2] = GetFieldValue (a, "MarshalType");\r
args [3] = Guid.Empty;\r
- marshal = (UnmanagedMarshal) define_custom.Invoke (null, args);\r
- /*\r
- * need to special case other special marshal types\r
- */\r
- } else {\r
- marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
+ return (UnmanagedMarshal) define_custom.Invoke (null, args);\r
+\r
+ case UnmanagedType.LPArray: \r
+ return UnmanagedMarshal.DefineLPArray (array_sub_type);\r
+\r
+ case UnmanagedType.SafeArray:\r
+ return UnmanagedMarshal.DefineSafeArray (array_sub_type);\r
+\r
+ case UnmanagedType.ByValArray:\r
+ return UnmanagedMarshal.DefineByValArray ((int) GetFieldValue (a, "SizeConst"));\r
+\r
+ case UnmanagedType.ByValTStr:\r
+ return UnmanagedMarshal.DefineByValTStr ((int) GetFieldValue (a, "SizeConst"));\r
+\r
+ default:\r
+ return UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
}\r
- return marshal;\r
}\r
\r
/// <summary>\r
} else if (kind is Constructor) {\r
((ConstructorBuilder) builder).SetCustomAttribute (cb);\r
} else if (kind is Field) {\r
- ((FieldBuilder) builder).SetCustomAttribute (cb);\r
+ if (attr_type == TypeManager.marshal_as_attr_type) {\r
+ UnmanagedMarshal marshal = GetMarshal (a);\r
+ if (marshal == null) {\r
+ Report.Warning (-24, loc,\r
+ "The Microsoft Runtime cannot set this marshal info. " +\r
+ "Please use the Mono runtime instead.");\r
+ } else {\r
+ ((FieldBuilder) builder).SetMarshal (marshal);\r
+ }\r
+ } else { \r
+ ((FieldBuilder) builder).SetCustomAttribute (cb);\r
+ }\r
} else if (kind is Property || kind is Indexer ||\r
kind is InterfaceProperty || kind is InterfaceIndexer) {\r
((PropertyBuilder) builder).SetCustomAttribute (cb);\r
\r
try {\r
((TypeBuilder) builder).SetCustomAttribute (cb);\r
- } catch (System.ArgumentException e) {\r
+ } catch (System.ArgumentException) {\r
Report.Warning (\r
-21, loc,\r
"The CharSet named property on StructLayout\n"+\r
}\r
try {\r
((TypeBuilder) builder).SetCustomAttribute (cb);\r
- } catch (System.ArgumentException e) {\r
+ } catch (System.ArgumentException) {\r
Report.Warning (\r
-21, loc,\r
"The CharSet named property on StructLayout\n"+\r
ArrayList type_bases;
- // Attributes for this type
- protected Attributes attributes;
-
// Information in the case we are an attribute type
public AttributeTargets Targets = AttributeTargets.All;
//
public string IndexerName;
- public TypeContainer (NamespaceEntry ns, TypeContainer parent, string name, Location l)
- : base (ns, parent, name, l)
+ public TypeContainer ():
+ this (null, null, "", null, new Location (-1)) {
+ }
+
+ public TypeContainer (NamespaceEntry ns, TypeContainer parent, string name, Attributes attrs, Location l)
+ : base (ns, parent, name, attrs, l)
{
types = new ArrayList ();
}
}
- public Attributes OptAttributes {
- get {
- return attributes;
- }
- }
-
public bool HaveStaticConstructor {
get {
return have_static_constructor;
if (is_static)
mods = Modifiers.STATIC;
+ //
+ // If the class is abstract, the default constructor is protected
+ //
+ if ((ModFlags & Modifiers.ABSTRACT) != 0)
+ mods |= Modifiers.PROTECTED;
+
c.ModFlags = mods;
AddConstructor (c);
- c.Block = new Block (null);
+ c.Block = new ToplevelBlock (null, Location);
}
default_constructor = null;
default_static_constructor = null;
type_bases = null;
- attributes = null;
+ OptAttributes = null;
ifaces = null;
parent_container = null;
member_cache = null;
return true;
}
- public static void Error_ExplicitInterfaceNotMemberInterface (Location loc, string name)
- {
- Report.Error (539, loc, "Explicit implementation: `" + name + "' is not a member of the interface");
- }
-
//
// IMemberContainer
//
Modifiers.UNSAFE;
public Class (NamespaceEntry ns, TypeContainer parent, string name, int mod, Attributes attrs, Location l)
- : base (ns, parent, name, l)
+ : base (ns, parent, name, attrs, l)
{
int accmods;
accmods = Modifiers.PRIVATE;
this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l);
- this.attributes = attrs;
}
//
Modifiers.PRIVATE;
public Struct (NamespaceEntry ns, TypeContainer parent, string name, int mod, Attributes attrs, Location l)
- : base (ns, parent, name, l)
+ : base (ns, parent, name, attrs, l)
{
int accmods;
this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l);
this.ModFlags |= Modifiers.SEALED;
- this.attributes = attrs;
-
}
//
Expression parent_constructor_group;
Type t;
- ec.CurrentBlock = new Block (null, Block.Flags.Implicit, parameters);
+ ec.CurrentBlock = new ToplevelBlock (Block.Flags.Implicit, parameters, loc);
if (argument_list != null){
foreach (Argument a in argument_list){
public class Constructor : MethodCore {
public ConstructorBuilder ConstructorBuilder;
public ConstructorInitializer Initializer;
- new public Attributes OptAttributes;
// <summary>
// Modifiers allowed for a constructor.
member.InterfaceType, name, ReturnType, ParameterTypes);
if (member.InterfaceType != null && implementing == null){
- TypeContainer.Error_ExplicitInterfaceNotMemberInterface (
- Location, name);
+ Report.Error (539, Location, "'{0}' in explicit interface declaration is not an interface", method_name);
return false;
}
}
//
// FIXME: This code generates buggy code
//
- if (member.Name == "Finalize" && ReturnType == TypeManager.void_type)
+ if (member is Destructor)
EmitDestructor (ec, block);
else {
SymbolWriter sw = CodeGen.SymbolWriter;
ILGenerator ig = ec.ig;
Label finish = ig.DefineLabel ();
- bool old_in_try = ec.InTry;
+
+ block.SetDestructor ();
ig.BeginExceptionBlock ();
- ec.InTry = true;
ec.ReturnLabel = finish;
ec.HasReturnLabel = true;
ec.EmitTopBlock (block, null, Location);
- ec.InTry = old_in_try;
// ig.MarkLabel (finish);
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
ig.BeginFinallyBlock ();
if (ec.ContainerType.BaseType != null) {
ig.Emit (OpCodes.Call, (MethodInfo) parent_destructor.Methods [0]);
}
}
- ec.InFinally = old_in_finally;
ig.EndExceptionBlock ();
//ig.MarkLabel (ec.ReturnLabel);
}
}
+ public class Destructor : Method {
+
+ public Destructor (DeclSpace ds, Expression return_type, int mod, string name,
+ Parameters parameters, Attributes attrs, Location l)
+ : base (ds, return_type, mod, name, parameters, attrs, l)
+ { }
+
+ }
+
abstract public class MemberBase : MemberCore {
public Expression Type;
- public readonly Attributes OptAttributes;
protected MethodAttributes flags;
//
protected MemberBase (Expression type, int mod, int allowed_mod, int def_mod, string name,
Attributes attrs, Location loc)
- : base (name, loc)
+ : base (name, attrs, loc)
{
explicit_mod_flags = mod;
Type = type;
ModFlags = Modifiers.Check (allowed_mod, mod, def_mod, loc);
- OptAttributes = attrs;
}
protected virtual bool CheckBase (TypeContainer container)
if (InterfaceType == null)
return false;
+ if (InterfaceType.IsClass) {
+ Report.Error (538, Location, "'{0}' in explicit interface declaration is not an interface", ExplicitInterfaceName);
+ return false;
+ }
+
// Compute the full name that we need to export.
Name = InterfaceType.FullName + "." + ShortName;
return false;
}
+ try {
FieldBuilder = container.TypeBuilder.DefineField (
Name, t, Modifiers.FieldAttr (ModFlags));
TypeManager.RegisterFieldBase (FieldBuilder, this);
+ }
+ catch (ArgumentException) {
+ Report.Warning (-24, Location, "The Microsoft runtime is unable to use [void|void*] as a field type, try using the Mono runtime.");
+ return false;
+ }
+
return true;
}
/// </summary>
public bool HasReturnLabel;
- /// <summary>
- /// Whether we are in a Finally block
- /// </summary>
- public bool InFinally;
-
- /// <summary>
- /// Whether we are in a Try block
- /// </summary>
- public bool InTry;
-
/// <summary>
/// Whether we are inside an iterator block.
/// </summary>
public bool InIterator;
- /// <summary>
- /// Whether we need an explicit return statement at the end of the method.
- /// </summary>
- public bool NeedExplicitReturn;
+ public bool IsLastStatement;
/// <summary>
/// Whether remapping of locals, parameters and fields is turned on.
/// </summary>
public bool RemapToProxy;
- /// <summary>
- /// Whether we are in a Catch block
- /// </summary>
- public bool InCatch;
-
/// <summary>
/// Whether we are inside an unsafe block
/// </summary>
public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
{
- bool has_ret = false;
+ bool unreachable = false;
if (!Location.IsNull (loc))
CurrentFile = loc.File;
block.Emit (this);
- if ((reachability.Returns == FlowBranching.FlowReturns.Always) ||
- (reachability.Throws == FlowBranching.FlowReturns.Always) ||
- (reachability.Reachable == FlowBranching.FlowReturns.Never))
- has_ret = true;
+ if (reachability.AlwaysReturns ||
+ reachability.AlwaysThrows ||
+ reachability.IsUnreachable)
+ unreachable = true;
}
} catch (Exception e) {
Console.WriteLine ("Exception caught by the compiler while compiling:");
Console.WriteLine (" Block being compiled: [{0},{1}]",
CurrentBlock.StartLocation, CurrentBlock.EndLocation);
}
-
Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
Console.WriteLine (Report.FriendlyStackTrace (e));
}
}
- if (ReturnType != null && !has_ret){
- //
- // FIXME: we need full flow analysis to implement this
- // correctly and emit an error instead of a warning.
- //
- //
+ if (ReturnType != null && !unreachable){
if (!InIterator){
Report.Error (161, loc, "Not all code paths return a value");
return;
ig.Emit (OpCodes.Ldloc, return_value);
ig.Emit (OpCodes.Ret);
} else {
- if (!InTry){
- if (InIterator)
- has_ret = true;
-
- if (!has_ret || HasReturnLabel) {
- ig.Emit (OpCodes.Ret);
- NeedExplicitReturn = false;
- }
- }
-
- // Unfortunately, System.Reflection.Emit automatically emits a leave
- // to the end of a finally block. This is a problem if no code is
- // following the try/finally block since we may jump to a point after
- // the end of the method. As a workaround, emit an explicit ret here.
+ //
+ // If `HasReturnLabel' is set, then we already emitted a
+ // jump to the end of the method, so we must emit a `ret'
+ // there.
+ //
+ // Unfortunately, System.Reflection.Emit automatically emits
+ // a leave to the end of a finally block. This is a problem
+ // if no code is following the try/finally block since we may
+ // jump to a point after the end of the method.
+ // As a workaround, we're always creating a return label in
+ // this case.
+ //
- if (NeedExplicitReturn) {
+ if ((block != null) && block.IsDestructor) {
+ // Nothing to do; S.R.E automatically emits a leave.
+ } else if (HasReturnLabel || (!unreachable && !InIterator)) {
if (ReturnType != null)
ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
ig.Emit (OpCodes.Ret);
/// </summary>
public Label LoopBegin, LoopEnd;
- /// <summary>
- /// Whether we are inside a loop and break/continue are possible.
- /// </summary>
- public bool InLoop;
-
- /// <summary>
- /// This is incremented each time we enter a try/catch block and
- /// decremented if we leave it.
- /// </summary>
- public int TryCatchLevel;
-
- /// <summary>
- /// The TryCatchLevel at the begin of the current loop.
- /// </summary>
- public int LoopBeginTryCatchLevel;
-
/// <summary>
/// Default target in a switch statement. Only valid if
/// InSwitch is true
return return_value;
}
+ public void NeedReturnLabel ()
+ {
+ if (!HasReturnLabel) {
+ ReturnLabel = ig.DefineLabel ();
+ HasReturnLabel = true;
+ }
+ }
+
//
// Creates a field `name' with the type `t' on the proxy class
//
in_transit = true;
int errors = Report.Errors;
+ //
+ // We might have cleared Expr ourselves in a recursive definition
+ //
+ if (Expr == null)
+ return null;
+
Expr = Expr.Resolve (const_ec);
in_transit = false;
if (TypeManager.IsValueType (expr_type))
return new BoxedCast (expr);
if (expr is NullLiteral)
- return new BoxedCast (expr);
+ return new NullCast (expr, target_type);
} else if (expr_type.IsSubclassOf (target_type)) {
//
// Special case: enumeration to System.Enum.
Type expr_type = expr.Type;
Expression e;
+ if (expr.eclass == ExprClass.MethodGroup){
+ if (!TypeManager.IsDelegateType (target_type)){
+ Report.Error (428, loc,
+ String.Format (
+ "Cannot convert method group to `{0}', since it is not a delegate",
+ TypeManager.CSharpName (target_type)));
+ return null;
+ }
+
+ return ImplicitDelegateCreation.Create (ec, (MethodGroupExpr) expr, target_type, loc);
+ }
+
if (expr_type.Equals (target_type) && !(expr is NullLiteral))
return expr;
if (source_type == TypeManager.object_type && !target_is_value_type)
return new ClassCast (source, target_type);
+ //
+ // Unboxing conversion.
+ //
+ if (((source_type == TypeManager.enum_type &&
+ !(source is EmptyCast)) ||
+ source_type == TypeManager.value_type) && target_is_value_type)
+ return new UnboxCast (source, target_type);
//
// From any class S to any class-type T, provided S is a base class of T
IIteratorContainer iterator_container;
- // <summary>
- // Current block is used to add statements as we find
- // them.
- // </summary>
+ /// <summary>
+ /// Current block is used to add statements as we find
+ /// them.
+ /// </summary>
Block current_block;
- // <summary>
- // Current interface is used by the various declaration
- // productions in the interface declaration to "add"
- // the interfaces as we find them.
- // </summary>
+ /// <summary>
+ /// If true, creates a toplevel block in the block production
+ /// This is flagged by the delegate creation
+ /// </summary>
+ bool create_toplevel_block;
+
+ /// <summary>
+ /// <summary>
+ /// Current interface is used by the various declaration
+ /// productions in the interface declaration to "add"
+ /// the interfaces as we find them.
+ /// </summary>
Interface current_interface;
- // <summary>
- // This is used by the unary_expression code to resolve
- // a name against a parameter.
- // </summary>
+ /// <summary>
+ /// This is used by the unary_expression code to resolve
+ /// a name against a parameter.
+ /// </summary>
Parameters current_local_parameters;
- // <summary>
- // Using during property parsing to describe the implicit
- // value parameter that is passed to the "set" and "get"accesor
- // methods (properties and indexers).
- // </summary>
+ /// <summary>
+ /// Using during property parsing to describe the implicit
+ /// value parameter that is passed to the "set" and "get"accesor
+ /// methods (properties and indexers).
+ /// </summary>
Expression implicit_value_parameter_type;
Parameters indexer_parameters;
- // <summary>
- // Used to determine if we are parsing the get/set pair
- // of an indexer or a property
- // </summmary>
+ /// <summary>
+ /// Used to determine if we are parsing the get/set pair
+ /// of an indexer or a property
+ /// </summmary>
bool parsing_indexer;
- //
- // An out-of-band stack.
- //
+ ///
+ /// An out-of-band stack.
+ ///
Stack oob_stack;
- //
- // Switch stack.
- //
+ ///
+ /// Switch stack.
+ ///
Stack switch_stack;
public bool yacc_verbose_flag;
// Name of the file we are parsing
public string name;
- //
- // The current file.
- //
+ ///
+ /// The current file.
+ ///
SourceFile file;
%}
| namespace_declaration {
current_namespace.DeclarationFound = true;
}
+
+ | field_declaration {
+ Report.Error (116, lexer.Location, "A namespace can only contain types and namespace declarations");
+ }
+ | method_declaration {
+ Report.Error (116, lexer.Location, "A namespace can only contain types and namespace declarations");
+ }
;
type_declaration
{
AttributeSection sect = (AttributeSection) $1;
- if (sect.Target == "assembly")
+ if (sect.Target == "assembly") {
RootContext.AddGlobalAttributeSection (current_container, sect);
-
-
- $$ = new Attributes ((AttributeSection) $1);
+ $$ = null;
+ }
+ else
+ $$ = new Attributes (sect);
}
| attribute_sections attribute_section
{
- Attributes attrs = null;
+ Attributes attrs = $1 as Attributes;
AttributeSection sect = (AttributeSection) $2;
- if (sect.Target == "assembly")
+ if (sect.Target == "assembly") {
RootContext.AddGlobalAttributeSection (current_container, sect);
-
- if ($1 != null) {
- attrs = (Attributes) $1;
+ } else {
+ if (attrs == null)
+ attrs = new Attributes (sect);
+ else
attrs.AddAttributeSection (sect);
}
GenericMethod generic = null;
if ($5 != null) {
generic = new GenericMethod (current_namespace, current_container,
- (string) $4, lexer.Location);
+ (string) $4, (Attributes) $1,
+ lexer.Location);
CheckDef (generic.SetParameterInfo ((ArrayList) $5, (ArrayList) $10), generic.Name, generic.Location);
method = new Method (generic, (Expression) $3, (int) $2, (string) $4,
GenericMethod generic = null;
if ($5 != null) {
generic = new GenericMethod (current_namespace, current_container,
- (string) $4, lexer.Location);
+ (string) $4, (Attributes) $1,
+ lexer.Location);
CheckDef (generic.SetParameterInfo ((ArrayList) $5, (ArrayList) $10), generic.Name, generic.Location);
current_local_parameters = (Parameters) $7;
+ $$ = method;
+ }
+ | opt_attributes
+ opt_modifiers
+ type
+ modifiers member_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ Report.Error (1585, lexer.Location,
+ String.Format ("Modifier {0} should appear before type",
+ Modifiers.Name ((int) $4)));
+ Method method = new Method (current_container, TypeManager.system_void_expr, 0,
+ (string) $5, (Parameters) $7, (Attributes) $1,
+ lexer.Location);
+
+ current_local_parameters = (Parameters) $7;
$$ = method;
}
;
}
| interface_event_declaration
{
+ if ($1 != null){
InterfaceEvent e = (InterfaceEvent) $1;
-
CheckDef (current_interface.AddEvent (e), e.Name, lexer.Location);
}
+ }
| interface_indexer_declaration
{
InterfaceIndexer i = (InterfaceIndexer) $1;
CheckIdentifierToken (yyToken);
$$ = null;
}
+ | opt_attributes opt_new EVENT type IDENTIFIER ASSIGN {
+ Report.Error (68, lexer.Location, "Event declarations on interfaces can not be initialized.");
+ $$ = null;
+ }
+ | opt_attributes opt_new EVENT type IDENTIFIER OPEN_BRACE event_accessor_declarations CLOSE_BRACE {
+ Report.Error (69, lexer.Location, "Event accessors not valid on interfaces");
+ $$ = null;
+ }
;
interface_indexer_declaration
}
}
- Method d = new Method (
+ Method d = new Destructor (
current_container, TypeManager.system_void_expr, m, "Finalize",
new Parameters (null, null, l), (Attributes) $1, l);
{
Location loc = (Location) oob_stack.Pop ();
+ if ($8 == null){
+ Report.Error (65, lexer.Location, "Event must have both add and remove accesors");
+ $$ = null;
+ } else {
Pair pair = (Pair) $8;
Accessor add_accessor = null;
Accessor rem_accessor = null;
CheckDef (current_container.AddEvent (e), e.Name, loc);
implicit_value_parameter_type = null;
}
+ }
;
event_accessor_declarations
{
$$ = new Pair ($2, $1);
}
+ | add_accessor_declaration { $$ = null; }
+ | remove_accessor_declaration { $$ = null; }
;
add_accessor_declaration
}
;
+type_name_expression
+ : IDENTIFIER { $$ = new SimpleName ((string) $1, lexer.Location);}
+ | type_name_expression DOT IDENTIFIER {
+ $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location);
+ }
+ ;
+
/*
* Before you think of adding a return_type, notice that we have been
* using two rules in the places where it matters (one rule using type
: DELEGATE opt_anonymous_method_signature {
oob_stack.Push (current_local_parameters);
current_local_parameters = (Parameters)$2;
+ create_toplevel_block = true;
} block {
+ create_toplevel_block = false;
if (!RootContext.V2){
Report.Error (-213, lexer.Location, "Anonymous methods are only supported in V2");
$$ = null;
if ($6 != null)
CheckDef (new_class.SetParameterInfo ((ArrayList) $6, (ArrayList) $8), new_class.Name, new_class.Location);
- if ($7 != null)
+ if ($7 != null) {
+ if (new_class.Name == "System.Object") {
+ Report.Error (537, new_class.Location, "The class System.Object cannot have a base class or implement an interface.");
+ }
+
new_class.Bases = (ArrayList) $7;
+ }
current_container = current_container.Parent;
CheckDef (current_container.AddClass (new_class), new_class.Name, new_class.Location);
block
: OPEN_BRACE
{
+ if (current_block == null || create_toplevel_block){
+ current_block = new ToplevelBlock (current_local_parameters, lexer.Location);
+ } else {
current_block = new Block (current_block, current_local_parameters,
lexer.Location, Location.Null);
+ }
}
opt_statement_list CLOSE_BRACE
{
const int max_id_size = 512;\r
static char [] id_builder = new char [max_id_size];\r
\r
+ static CharArrayHashtable [] identifiers = new CharArrayHashtable [max_id_size + 1];\r
+\r
const int max_number_size = 128;\r
static char [] number_builder = new char [max_number_size];\r
static int number_pos;\r
Mono.CSharp.Location.Push (file);\r
}\r
\r
+ public static void Cleanup () {\r
+ identifiers = null;\r
+ }\r
+\r
bool is_identifier_start_character (char c)\r
{\r
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || Char.IsLetter (c);\r
case Token.TYPEOF:\r
case Token.UNCHECKED:\r
case Token.UNSAFE:\r
+\r
+ //\r
+ // These can be part of a member access\r
+ //\r
+ case Token.INT:\r
+ case Token.UINT:\r
+ case Token.SHORT:\r
+ case Token.USHORT:\r
+ case Token.LONG:\r
+ case Token.ULONG:\r
+ case Token.DOUBLE:\r
+ case Token.FLOAT:\r
+ case Token.CHAR:\r
return true;\r
\r
default:\r
return keyword;\r
}\r
\r
+ //\r
+ // Keep identifiers in an array of hashtables to avoid needless\r
+ // allocations\r
+ //\r
+\r
+ if (identifiers [pos] != null) {\r
+ val = identifiers [pos][id_builder];\r
+ if (val != null) {\r
+ return Token.IDENTIFIER;\r
+ }\r
+ }\r
+ else\r
+ identifiers [pos] = new CharArrayHashtable (pos);\r
+\r
val = new String (id_builder, 0, pos);\r
\r
+ char [] chars = new char [pos];\r
+ Array.Copy (id_builder, chars, pos);\r
+\r
+ identifiers [pos] [chars] = val;\r
+\r
return Token.IDENTIFIER;\r
}\r
\r
}\r
\r
}\r
-\r
}\r
}\r
\r
/// </summary>
public readonly Location Location;
- public MemberCore (string name, Location loc)
+ /// <summary>
+ /// Attributes for this type
+ /// </summary>
+ Attributes attributes;
+
+ public MemberCore (string name, Attributes attrs, Location loc)
{
Name = name;
Location = loc;
+ attributes = attrs;
}
public abstract bool Define (TypeContainer parent);
+ public Attributes OptAttributes
+ {
+ get {
+ return attributes;
+ }
+ set {
+ attributes = value;
+ }
+ }
+
//
// Whehter is it ok to use an unsafe pointer in this type container
//
TypeContainer parent;
- public DeclSpace (NamespaceEntry ns, TypeContainer parent, string name, Location l)
- : base (name, l)
+ public DeclSpace (NamespaceEntry ns, TypeContainer parent, string name, Attributes attrs, Location l)
+ : base (name, attrs, l)
{
NamespaceEntry = ns;
Basename = name.Substring (1 + name.LastIndexOf ('.'));
public class Delegate : DeclSpace {\r
public Expression ReturnType;\r
public Parameters Parameters;\r
- public Attributes OptAttributes;\r
\r
public ConstructorBuilder ConstructorBuilder;\r
public MethodBuilder InvokeBuilder;\r
public Delegate (NamespaceEntry ns, TypeContainer parent, Expression type,\r
int mod_flags, string name, Parameters param_list,\r
Attributes attrs, Location l)\r
- : base (ns, parent, name, l)\r
+ : base (ns, parent, name, attrs, l)
+
{\r
this.ReturnType = type;\r
ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,\r
IsTopLevel ? Modifiers.INTERNAL :\r
Modifiers.PRIVATE, l);\r
- Parameters = param_list;\r
- OptAttributes = attrs;\r
- }\r
+ Parameters = param_list;\r }\r
\r
public override TypeBuilder DefineType ()\r
{\r
\r
}\r
\r
- public class NewDelegate : Expression {\r
-\r
- public ArrayList Arguments;\r
+ //\r
+ // Base class for `NewDelegate' and `ImplicitDelegateCreation'\r
+ //\r
+ public abstract class DelegateCreation : Expression {\r
+ protected MethodBase constructor_method;\r
+ protected MethodBase delegate_method;\r
+ protected Expression delegate_instance_expr;\r
\r
- MethodBase constructor_method;\r
- MethodBase delegate_method;\r
- Expression delegate_instance_expr;\r
+ public DelegateCreation () {}\r
\r
- public NewDelegate (Type type, ArrayList Arguments, Location loc)\r
+ public static void Error_NoMatchingMethodForDelegate (MethodGroupExpr mg, Type t, MethodBase method, Location loc)\r
{\r
- this.type = type;\r
- this.Arguments = Arguments;\r
- this.loc = loc; \r
+ string method_desc;\r
+\r
+ if (mg.Methods.Length > 1)\r
+ method_desc = mg.Methods [0].Name;\r
+ else\r
+ method_desc = Invocation.FullMethodDesc (mg.Methods [0]);\r
+\r
+ ParameterData param = Invocation.GetParameterData (method);\r
+ string delegate_desc = Delegate.FullDelegateDesc (t, method, param);\r
+\r
+ Report.Error (123, loc, "Method '" + method_desc + "' does not " +\r
+ "match delegate '" + delegate_desc + "'");\r
}\r
\r
- public override Expression DoResolve (EmitContext ec)\r
+ public override void Emit (EmitContext ec)\r
{\r
- if (Arguments == null || Arguments.Count != 1) {\r
- Report.Error (149, loc,\r
- "Method name expected");\r
- return null;\r
- }\r
+ if (delegate_instance_expr == null ||\r
+ delegate_method.IsStatic)\r
+ ec.ig.Emit (OpCodes.Ldnull);\r
+ else\r
+ delegate_instance_expr.Emit (ec);\r
+ \r
+ if (delegate_method.IsVirtual) {\r
+ ec.ig.Emit (OpCodes.Dup);\r
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);\r
+ } else\r
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);\r
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);\r
+ }\r
\r
+ protected bool ResolveConstructorMethod (EmitContext ec)\r
+ {\r
Expression ml = Expression.MemberLookup (\r
ec, type, ".ctor", loc);\r
\r
if (!(ml is MethodGroupExpr)) {\r
Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");\r
- return null;\r
+ return false;\r
}\r
\r
constructor_method = ((MethodGroupExpr) ml).Methods [0];\r
- Argument a = (Argument) Arguments [0];\r
- \r
- if (!a.ResolveMethodGroup (ec, Location))\r
- return null;\r
- \r
- Expression e = a.Expr;\r
-\r
- Expression invoke_method = Expression.MemberLookup (\r
- ec, type, "Invoke", MemberTypes.Method,\r
- Expression.AllBindingFlags, loc);\r
-\r
- if (invoke_method == null) {\r
- Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");\r
- return null;\r
- }\r
-\r
- if (e is MethodGroupExpr) {\r
- MethodGroupExpr mg = (MethodGroupExpr) e;\r
+ return true;\r
+ }\r
\r
+ protected Expression ResolveMethodGroupExpr (EmitContext ec, MethodGroupExpr mg)\r
+ {\r
foreach (MethodInfo mi in mg.Methods){\r
delegate_method = Delegate.VerifyMethod (ec, type, mi, loc);\r
\r
}\r
\r
if (delegate_method == null) {\r
- string method_desc;\r
- if (mg.Methods.Length > 1)\r
- method_desc = mg.Methods [0].Name;\r
- else\r
- method_desc = Invocation.FullMethodDesc (mg.Methods [0]);\r
-\r
- MethodBase dm = ((MethodGroupExpr) invoke_method).Methods [0];\r
- ParameterData param = Invocation.GetParameterData (dm);\r
- string delegate_desc = Delegate.FullDelegateDesc (type, dm, param);\r
-\r
- Report.Error (123, loc, "Method '" + method_desc + "' does not " +\r
- "match delegate '" + delegate_desc + "'");\r
-\r
+ Error_NoMatchingMethodForDelegate (mg, type, delegate_method, loc);\r
return null;\r
}\r
\r
eclass = ExprClass.Value;\r
return this;\r
}\r
+ }\r
+\r
+ //\r
+ // Created from the conversion code\r
+ //\r
+ public class ImplicitDelegateCreation : DelegateCreation {\r
+\r
+ ImplicitDelegateCreation (Type t, Location l)\r
+ {\r
+ type = t;\r
+ loc = l;\r
+ }\r
+\r
+ public override Expression DoResolve (EmitContext ec)\r
+ {\r
+ return this;\r
+ }\r
+ \r
+ static public Expression Create (EmitContext ec, MethodGroupExpr mge, Type target_type, Location loc)\r
+ {\r
+ ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, loc);\r
+ if (d.ResolveConstructorMethod (ec))\r
+ return d.ResolveMethodGroupExpr (ec, mge);\r
+ else\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // A delegate-creation-expression, invoked from the `New' class \r
+ //\r
+ public class NewDelegate : DelegateCreation {\r
+ public ArrayList Arguments;\r
+\r
+ //\r
+ // This constructor is invoked from the `New' expression\r
+ //\r
+ public NewDelegate (Type type, ArrayList Arguments, Location loc)\r
+ {\r
+ this.type = type;\r
+ this.Arguments = Arguments;\r
+ this.loc = loc; \r
+ }\r
+\r
+ public override Expression DoResolve (EmitContext ec)\r
+ {\r
+ if (Arguments == null || Arguments.Count != 1) {\r
+ Report.Error (149, loc,\r
+ "Method name expected");\r
+ return null;\r
+ }\r
+\r
+ if (!ResolveConstructorMethod (ec))\r
+ return null;\r
+\r
+ Argument a = (Argument) Arguments [0];\r
+ \r
+ Expression invoke_method = Expression.MemberLookup (\r
+ ec, type, "Invoke", MemberTypes.Method,\r
+ Expression.AllBindingFlags, loc);\r
+\r
+ if (invoke_method == null) {\r
+ Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");\r
+ return null;\r
+ }\r
+\r
+ if (!a.ResolveMethodGroup (ec, loc))\r
+ return null;\r
+ \r
+ Expression e = a.Expr;\r
+\r
+ MethodGroupExpr mg = e as MethodGroupExpr;\r
+ if (mg != null)\r
+ return ResolveMethodGroupExpr (ec, mg);\r
\r
Type e_type = e.Type;\r
\r
\r
public override void Emit (EmitContext ec)\r
{\r
- if (delegate_instance_expr == null ||\r
- delegate_method.IsStatic)\r
+ if (delegate_instance_expr == null || delegate_method.IsStatic)\r
ec.ig.Emit (OpCodes.Ldnull);\r
else\r
delegate_instance_expr.Emit (ec);\r
//
static ArrayList resources;
static ArrayList embedded_resources;
+ static string win32ResourceFile;
+ static string win32IconFile;
//
// An array of the defines from the command line
"Resources:\n" +
" -linkresource:FILE[,ID] Links FILE as a resource\n" +
" -resource:FILE[,ID] Embed FILE as a resource\n" +
+ " -win32res:FILE Specifies Win32 resource file (.res)\n" +
+ " -win32icon:FILE Use this icon for the output\n" +
" --mcs-debug X Sets MCS debugging level to X\n" +
" @file Read response file for more options\n\n" +
"Options can be of the form -option or /option");
}
return true;
}
+ case "/win32res": {
+ if (value == "") {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ win32ResourceFile = value;
+ return true;
+ }
+ case "/win32icon": {
+ if (value == "") {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ win32IconFile = value;
+ return true;
+ }
case "/doc": {
if (value == ""){
Report.Error (5, arg + " requires an argument");
case "/fullpaths":
return true;
- case "/win32icon":
- Report.Error (5, "/win32icon is currently not supported");
- return true;
-
case "/v2":
case "/2":
SetupV2 ();
if (tokenize)
return true;
+ //
+ // If we are an exe, require a source file for the entry point
+ //
+ if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe){
if (first_source == null){
Report.Error (2008, "No files to compile were specified");
return false;
}
+ }
+
+ //
+ // If there is nothing to put in the assembly, and we are not a library
+ //
+ if (first_source == null && embedded_resources == null && resources == null){
+ Report.Error (2008, "No files to compile were specified");
+ return false;
+ }
+
if (Report.Errors > 0)
return false;
if (parse_only)
return true;
+ Tokenizer.Cleanup ();
+
//
// Load Core Library for default compilation
//
}
}
+ //
+ // Add Win32 resources
+ //
+
+ CodeGen.AssemblyBuilder.DefineVersionInfoResource ();
+
+ if (win32ResourceFile != null) {
+ try {
+ CodeGen.AssemblyBuilder.DefineUnmanagedResource (win32ResourceFile);
+ }
+ catch (ArgumentException) {
+ Report.Warning (0, new Location (-1), "Cannot embed win32 resources on this runtime: try the Mono runtime instead.");
+ }
+ }
+
+ if (win32IconFile != null) {
+ MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+ if (define_icon == null) {
+ Report.Warning (0, new Location (-1), "Cannot embed icon resource on this runtime: try the Mono runtime instead.");
+ }
+ define_icon.Invoke (CodeGen.AssemblyBuilder, new object [] { win32IconFile });
+ }
+
if (Report.Errors > 0)
return false;
break;
case ExprClass.MethodGroup:
+ if (!RootContext.V2){
if ((flags & ResolveFlags.MethodGroup) == 0) {
((MethodGroupExpr) e).ReportUsageError ();
return null;
}
+ }
break;
case ExprClass.Value:
/// </remarks>
public abstract void Emit (EmitContext ec);
+ public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ Emit (ec);
+ ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ }
+
/// <summary>
/// Protected constructor. Only derivate types should
/// be able to be created
Report.Error (
122, loc, "`" + TypeManager.CSharpName (qualifier_type) + "." +
name + "' is inaccessible due to its protection level");
- else
+ else if (name == ".ctor") {
+ Report.Error (143, loc, String.Format ("The type {0} has no constructors defined",
+ TypeManager.CSharpName (queried_type)));
+ } else {
Report.Error (
122, loc, "`" + name + "' is inaccessible due to its " +
"protection level");
}
+ }
static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
{
public class EmptyCast : Expression {
protected Expression child;
+ public Expression Child {
+ get {
+ return child;
+ }
+ }
+
public EmptyCast (Expression child, Type return_type)
{
eclass = child.eclass;
alias_value = null;
if (ec.ResolvingTypeTree){
- if (alias_value != null){
- if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
- return new TypeExpression (t, loc);
- }
-
int errors = Report.Errors;
- Type dt = ec.DeclSpace.FindType (loc, Name);
+ Type dt = ds.FindType (loc, Name);
if (Report.Errors != errors)
return null;
if (dt != null)
return new TypeExpression (dt, loc);
+
+ if (alias_value != null){
+ if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
+ return new TypeExpression (t, loc);
+ }
}
//
// Handle initonly fields specially: make a copy and then
// get the address of the copy.
//
- if (FieldInfo.IsInitOnly && !ec.IsConstructor){
+ bool need_copy;
+ if (FieldInfo.IsInitOnly){
+ need_copy = true;
+ if (ec.IsConstructor){
+ if (FieldInfo.IsStatic){
+ if (ec.IsStatic)
+ need_copy = false;
+ } else
+ need_copy = false;
+ }
+ } else
+ need_copy = false;
+
+ if (need_copy){
LocalBuilder local;
-
Emit (ec);
local = ig.DeclareLocal (type);
ig.Emit (OpCodes.Stloc, local);
return;
}
- if (FieldInfo.IsStatic)
+
+ if (FieldInfo.IsStatic){
ig.Emit (OpCodes.Ldsflda, FieldInfo);
- else {
+ } else {
//
// In the case of `This', we call the AddressOf method, which will
// only load the pointer, and not perform an Ldobj immediately after
ArrayList ordered_enums;
public Expression BaseType;
- public Attributes OptAttributes;
public Type UnderlyingType;
public Enum (NamespaceEntry ns, TypeContainer parent, Expression type, int mod_flags,
string name, Attributes attrs, Location l)
- : base (ns, parent, name, l)
+ : base (ns, parent, name, attrs, l)
{
this.BaseType = type;
ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l);
- OptAttributes = attrs;
ordered_enums = new ArrayList ();
member_to_location = new Hashtable ();
}
}
- /// <summary>
- /// This will emit the child expression for `ec' avoiding the logical
- /// not. The parent will take care of changing brfalse/brtrue
- /// </summary>
- public void EmitLogicalNot (EmitContext ec)
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
{
- if (Oper != Operator.LogicalNot)
- throw new Exception ("EmitLogicalNot can only be called with !expr");
-
- Expr.Emit (ec);
+ if (Oper == Operator.LogicalNot)
+ Expr.EmitBranchable (ec, target, !onTrue);
+ else
+ base.EmitBranchable (ec, target, onTrue);
}
public override string ToString ()
ILGenerator ig = ec.ig;
if (temporary != null){
- if (have_temporary){
+ if (have_temporary) {
temporary.Emit (ec);
- return;
- }
+ } else {
expr.Emit (ec);
ec.ig.Emit (OpCodes.Dup);
temporary.Store (ec);
have_temporary = true;
+ }
} else
expr.Emit (ec);
ia.EmitAssign (ec, temp_storage);
break;
}
+
+ temp_storage.Release (ec);
}
public override void Emit (EmitContext ec)
throw new Exception ("never reached");
}
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ ILGenerator ig = ec.ig;
+
+ switch (action){
+ case Action.AlwaysFalse:
+ if (! onTrue)
+ ig.Emit (OpCodes.Br, target);
+
+ return;
+ case Action.AlwaysTrue:
+ if (onTrue)
+ ig.Emit (OpCodes.Br, target);
+
+ return;
+ case Action.LeaveOnStack:
+ // the `e != null' rule.
+ expr.Emit (ec);
+ ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ return;
+ case Action.Probe:
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Isinst, probe_type);
+ ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ return;
+ }
+ throw new Exception ("never reached");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
Expression e = base.DoResolve (ec);
}
}
- //
- // Step 2: Default operations on CLI native types.
- //
-
//
// Step 0: String concatenation (because overloading will get this wrong)
//
// +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
//
if (oper == Operator.Addition || oper == Operator.Subtraction) {
- if (l.IsSubclassOf (TypeManager.delegate_type) &&
- r.IsSubclassOf (TypeManager.delegate_type)) {
+ if (l.IsSubclassOf (TypeManager.delegate_type)){
+ if (right.eclass == ExprClass.MethodGroup && RootContext.V2){
+ Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+ if (tmp == null)
+ return null;
+ right = tmp;
+ r = right.Type;
+ }
+
+ if (r.IsSubclassOf (TypeManager.delegate_type)){
MethodInfo method;
ArrayList args = new ArrayList (2);
return new BinaryDelegate (l, method, args);
}
+ }
//
// Pointer arithmetic:
Expression temp;
// U operator - (E e, E f)
- if (lie && rie && oper == Operator.Subtraction){
+ if (lie && rie){
+ if (oper == Operator.Subtraction){
if (l == r){
type = TypeManager.EnumToUnderlying (l);
return this;
Error_OperatorCannotBeApplied ();
return null;
}
+ }
//
// operator + (E e, U x)
Type enum_type = lie ? l : r;
Type other_type = lie ? r : l;
Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
-;
if (underlying_type != other_type){
+ temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
+ if (temp != null){
+ if (lie)
+ right = temp;
+ else
+ left = temp;
+ type = enum_type;
+ return this;
+ }
+
Error_OperatorCannotBeApplied ();
return null;
}
/// The expression's code is generated, and we will generate a branch to `target'
/// if the resulting expression value is equal to isTrue
/// </remarks>
- public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
{
ILGenerator ig = ec.ig;
// but on top of that we want for == and != to use a special path
// if we are comparing against null
//
- if (oper == Operator.Equality || oper == Operator.Inequality){
+ if (oper == Operator.Equality || oper == Operator.Inequality) {
bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
- if (left is NullLiteral){
+ if (left is NullLiteral || left is IntConstant && ((IntConstant) left).Value == 0) {
right.Emit (ec);
if (my_on_true)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
- } else if (right is NullLiteral){
+
+ return;
+ } else if (right is NullLiteral || right is IntConstant && ((IntConstant) right).Value == 0){
left.Emit (ec);
if (my_on_true)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
+
+ return;
} else if (left is BoolConstant){
right.Emit (ec);
if (my_on_true != ((BoolConstant) left).Value)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
+
+ return;
} else if (right is BoolConstant){
left.Emit (ec);
if (my_on_true != ((BoolConstant) right).Value)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
+
+ return;
}
- } else if (oper == Operator.LogicalAnd){
- if (left is Binary){
- Binary left_binary = (Binary) left;
+ } else if (oper == Operator.LogicalAnd) {
- if (onTrue){
+ if (onTrue) {
Label tests_end = ig.DefineLabel ();
- if (left_binary.EmitBranchable (ec, tests_end, false)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
-
- if (right_binary.EmitBranchable (ec, target, true)){
- ig.MarkLabel (tests_end);
- return true;
- }
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brtrue, target);
+ left.EmitBranchable (ec, tests_end, false);
+ right.EmitBranchable (ec, target, true);
ig.MarkLabel (tests_end);
- return true;
- }
} else {
- if (left_binary.EmitBranchable (ec, target, false)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
-
- if (right_binary.EmitBranchable (ec, target, false))
- return true;
- }
- right.Emit (ec);
- if (onTrue)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
- return true;
- }
+ left.EmitBranchable (ec, target, false);
+ right.EmitBranchable (ec, target, false);
}
- //
- // Give up, and let the regular Emit work, but we could
- // also optimize the left-non-Branchable, but-right-Branchable
- //
- }
- return false;
- } else if (oper == Operator.LogicalOr){
- if (left is Binary){
- Binary left_binary = (Binary) left;
- if (onTrue){
- if (left_binary.EmitBranchable (ec, target, true)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
+ return;
- if (right_binary.EmitBranchable (ec, target, true))
- return true;
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brtrue, target);
- return true;
- }
+ } else if (oper == Operator.LogicalOr){
+ if (onTrue) {
+ left.EmitBranchable (ec, target, true);
+ right.EmitBranchable (ec, target, true);
- //
- // Give up, and let the regular Emit work, but we could
- // also optimize the left-non-Branchable, but-right-Branchable
- //
} else {
Label tests_end = ig.DefineLabel ();
+ left.EmitBranchable (ec, tests_end, true);
+ right.EmitBranchable (ec, target, false);
+ ig.MarkLabel (tests_end);
+ }
- if (left_binary.EmitBranchable (ec, tests_end, true)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
+ return;
- if (right_binary.EmitBranchable (ec, target, false)){
- ig.MarkLabel (tests_end);
- return true;
- }
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brfalse, target);
- ig.MarkLabel (tests_end);
- return true;
- }
- }
+ } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
+ oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.Equality || oper == Operator.Inequality)) {
+ base.EmitBranchable (ec, target, onTrue);
+ return;
}
- return false;
- } else if (!(oper == Operator.LessThan ||
- oper == Operator.GreaterThan ||
- oper == Operator.LessThanOrEqual ||
- oper == Operator.GreaterThanOrEqual))
- return false;
-
left.Emit (ec);
right.Emit (ec);
else
ig.Emit (OpCodes.Blt, target);
break;
-
default:
- return false;
+ Console.WriteLine (oper);
+ throw new Exception ("what is THAT");
}
-
- return true;
}
public override void Emit (EmitContext ec)
// Handle short-circuit operators differently
// than the rest
//
- if (oper == Operator.LogicalAnd){
+ if (oper == Operator.LogicalAnd) {
Label load_zero = ig.DefineLabel ();
Label end = ig.DefineLabel ();
- bool process = true;
-
- if (left is Binary){
- Binary left_binary = (Binary) left;
- if (left_binary.EmitBranchable (ec, load_zero, false)){
+ left.EmitBranchable (ec, load_zero, false);
right.Emit (ec);
ig.Emit (OpCodes.Br, end);
- process = false;
- }
- }
- if (process){
- left.Emit (ec);
- ig.Emit (OpCodes.Brfalse, load_zero);
- right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
- }
ig.MarkLabel (load_zero);
ig.Emit (OpCodes.Ldc_I4_0);
ig.MarkLabel (end);
return;
- } else if (oper == Operator.LogicalOr){
+ } else if (oper == Operator.LogicalOr) {
Label load_one = ig.DefineLabel ();
Label end = ig.DefineLabel ();
- bool process = true;
- if (left is Binary){
- Binary left_binary = (Binary) left;
-
- if (left_binary.EmitBranchable (ec, load_one, true)){
+ left.EmitBranchable (ec, load_one, true);
right.Emit (ec);
ig.Emit (OpCodes.Br, end);
- process = false;
- }
- }
- if (process){
- left.Emit (ec);
- ig.Emit (OpCodes.Brtrue, load_one);
- right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
- }
ig.MarkLabel (load_one);
ig.Emit (OpCodes.Ldc_I4_1);
ig.MarkLabel (end);
ig.Emit (OpCodes.Nop);
- Statement.EmitBoolExpression (ec, is_and ? op_false : op_true, false_target, false);
+ (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
left.Emit (ec);
ig.Emit (OpCodes.Br, end_target);
ig.MarkLabel (false_target);
Label false_target = ig.DefineLabel ();
Label end_target = ig.DefineLabel ();
- Statement.EmitBoolExpression (ec, expr, false_target, false);
+ expr.EmitBranchable (ec, false_target, false);
trueExpr.Emit (ec);
ig.Emit (OpCodes.Br, end_target);
ig.MarkLabel (false_target);
// we can optimize this case: a positive int32
// always fits on a uint64
//
+
+ //
+ // This special case is needed because csc behaves like this.
+ // int -> uint is better than int -> ulong!
+ //
+ if (q == TypeManager.uint32_type)
+ return 0;
+
if (q == TypeManager.int64_type)
return 0;
else if (value >= 0)
ig.Emit (OpCodes.Ldelema, etype);
}
- ig.Emit (OpCodes.Nop);
e.Emit (ec);
- ig.Emit (OpCodes.Nop);
- ig.Emit (OpCodes.Nop);
if (dims == 1)
ArrayAccess.EmitStoreOpcode (ig, array_element_type);
return null;
}
- if (ec.InCatch || ec.InFinally){
+ if (ec.CurrentBranching.InCatch () ||
+ ec.CurrentBranching.InFinally (true)) {
Error (255,
"stackalloc can not be used in a catch or finally block");
return null;
Conditional,
// A loop block.
- LoopBlock,
+ Loop,
// Try/Catch block.
Exception,
return cloned;
}
+ // <summary>
+ // Performs an `And' operation on the FlowReturns status
+ // (for instance, a block only returns Always if all its siblings
+ // always return).
+ // </summary>
+ public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
+ {
+ if (a == FlowReturns.Undefined)
+ return b;
+
+ switch (a) {
+ case FlowReturns.Never:
+ if (b == FlowReturns.Never)
+ return FlowReturns.Never;
+ else
+ return FlowReturns.Sometimes;
+
+ case FlowReturns.Sometimes:
+ return FlowReturns.Sometimes;
+
+ case FlowReturns.Always:
+ if (b == FlowReturns.Always)
+ return FlowReturns.Always;
+ else
+ return FlowReturns.Sometimes;
+
+ default:
+ throw new ArgumentException ();
+ }
+ }
+
+ public static FlowReturns OrFlowReturns (FlowReturns a, FlowReturns b)
+ {
+ if (a == FlowReturns.Undefined)
+ return b;
+
+ switch (a) {
+ case FlowReturns.Never:
+ return b;
+
+ case FlowReturns.Sometimes:
+ if (b == FlowReturns.Always)
+ return FlowReturns.Always;
+ else
+ return FlowReturns.Sometimes;
+
+ case FlowReturns.Always:
+ return FlowReturns.Always;
+
+ default:
+ throw new ArgumentException ();
+ }
+ }
+
public static void And (ref Reachability a, Reachability b, bool do_break)
{
if (a == null) {
a.reachable = AndFlowReturns (a.reachable, b.reachable);
}
+ public void Or (Reachability b)
+ {
+ returns = OrFlowReturns (returns, b.returns);
+ breaks = OrFlowReturns (breaks, b.breaks);
+ throws = OrFlowReturns (throws, b.throws);
+ barrier = OrFlowReturns (barrier, b.barrier);
+
+ update ();
+ }
+
public static Reachability Never ()
{
return new Reachability (
{
switch (type) {
case BranchingType.Exception:
- return new FlowBranchingException (parent, type, block, loc);
+ return new FlowBranchingException (parent, block, loc);
case BranchingType.Switch:
return new FlowBranchingBlock (parent, type, SiblingType.SwitchSection, block, loc);
static int next_id = 0;
int id;
- // <summary>
- // Performs an `And' operation on the FlowReturns status
- // (for instance, a block only returns Always if all its siblings
- // always return).
- // </summary>
- public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
- {
- if (a == FlowReturns.Undefined)
- return b;
-
- switch (a) {
- case FlowReturns.Never:
- if (b == FlowReturns.Never)
- return FlowReturns.Never;
- else
- return FlowReturns.Sometimes;
-
- case FlowReturns.Sometimes:
- return FlowReturns.Sometimes;
-
- case FlowReturns.Always:
- if (b == FlowReturns.Always)
- return FlowReturns.Always;
- else
- return FlowReturns.Sometimes;
-
- default:
- throw new ArgumentException ();
- }
- }
-
// <summary>
// The vector contains a BitArray with information about which local variables
// and parameters are already initialized at the current code position.
this.CountLocals = num_locals;
if (parent != null) {
+ if (num_locals > 0)
locals = new MyBitVector (parent.locals, CountLocals);
+
if (num_params > 0)
parameters = new MyBitVector (parent.parameters, num_params);
reachability = parent.Reachability.Clone ();
} else {
+ if (num_locals > 0)
locals = new MyBitVector (null, CountLocals);
+
if (num_params > 0)
parameters = new MyBitVector (null, num_params);
{
UsageVector retval = new UsageVector (Type, null, Location, CountParameters, CountLocals);
+ if (retval.locals != null)
retval.locals = locals.Clone ();
+
if (parameters != null)
retval.parameters = parameters.Clone ();
+
retval.reachability = reachability.Clone ();
return retval;
Report.Debug (2, " MERGING CHILD", this, IsDirty,
result.ParameterVector, result.LocalVector,
- result.Reachability, Type);
+ result.Reachability, reachability, Type);
- reachability = result.Reachability;
+ Reachability new_r = result.Reachability;
- if (branching.Type == BranchingType.LoopBlock) {
- bool may_leave_loop = reachability.MayBreak;
- reachability.ResetBreaks ();
+ if (branching.Type == BranchingType.Loop) {
+ bool may_leave_loop = new_r.MayBreak;
+ new_r.ResetBreaks ();
if (branching.Infinite && !may_leave_loop) {
- if (reachability.Returns == FlowReturns.Sometimes) {
+ if (new_r.Returns == FlowReturns.Sometimes) {
// If we're an infinite loop and do not break,
// the code after the loop can never be reached.
// However, if we may return from the loop,
// then we do always return (or stay in the
// loop forever).
- reachability.SetReturns ();
+ new_r.SetReturns ();
}
- reachability.SetBarrier ();
+ new_r.SetBarrier ();
} else {
- if (reachability.Returns == FlowReturns.Always) {
+ if (new_r.Returns == FlowReturns.Always) {
// We're either finite or we may leave the loop.
- reachability.SetReturnsSometimes ();
+ new_r.SetReturnsSometimes ();
}
}
} else if (branching.Type == BranchingType.Switch)
- reachability.ResetBreaks ();
+ new_r.ResetBreaks ();
//
// We've now either reached the point after the branching or we will
// we need to look at (see above).
//
- if ((Type == SiblingType.SwitchSection) && !reachability.IsUnreachable) {
+ if ((Type == SiblingType.SwitchSection) && !new_r.IsUnreachable) {
Report.Error (163, Location,
"Control cannot fall through from one " +
"case label to another");
return result;
}
- if (result.LocalVector != null)
+ if (locals != null && result.LocalVector != null)
locals.Or (result.LocalVector);
if (result.ParameterVector != null)
parameters.Or (result.ParameterVector);
- Report.Debug (2, " MERGING CHILD DONE", this, result);
+ reachability.Or (new_r);
+
+ Report.Debug (2, " MERGING CHILD DONE", this, result,
+ new_r, reachability);
IsDirty = true;
MergeFinally (branching, f_origins, parameters);
}
- if (f_vector != null)
+ if (f_vector != null && f_vector.LocalVector != null)
MyBitVector.Or (ref locals, f_vector.LocalVector);
}
Report.Debug (1, " MERGING JUMP ORIGIN", vector);
if (first) {
+ if (locals != null && vector.Locals != null)
locals.Or (vector.locals);
+
if (parameters != null)
parameters.Or (vector.parameters);
first = false;
} else {
+ if (locals != null && vector.Locals != null)
locals.And (vector.locals);
if (parameters != null)
parameters.And (vector.parameters);
// </summary>
public MyBitVector Locals {
get {
+ if (locals != null)
return locals.Clone ();
+ else
+ return null;
}
}
StringBuilder sb = new StringBuilder ();
sb.Append ("Vector (");
+ sb.Append (Type);
+ sb.Append (",");
sb.Append (id);
sb.Append (",");
sb.Append (IsDirty);
UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
vector = new UsageVector (stype, parent_vector, loc, param_map.Length, local_map.Length);
+
+
} else {
param_map = Parent.param_map;
local_map = Parent.local_map;
continue;
Report.Error (177, loc, "The out parameter `" +
- param_map.VariableNames [i] + "' must be " +
+ var.Name + "' must be " +
"assigned before control leave the current method.");
}
}
for (UsageVector child = sibling_list; child != null; child = child.Next) {
bool do_break = (Type != BranchingType.Switch) &&
- (Type != BranchingType.LoopBlock);
+ (Type != BranchingType.Loop);
Report.Debug (2, " MERGING SIBLING ", child,
- child.Parameters, child.Locals,
+ child.ParameterVector, child.LocalVector,
reachability, child.Reachability, do_break);
Reachability.And (ref reachability, child.Reachability, do_break);
//
bool do_break_2 = (child.Type != SiblingType.Block) &&
(child.Type != SiblingType.SwitchSection);
- bool unreachable = (do_break_2 && child.Reachability.AlwaysBreaks) ||
- child.Reachability.AlwaysThrows ||
+ bool always_throws = (child.Type != SiblingType.Try) &&
+ child.Reachability.AlwaysThrows;
+ bool unreachable = always_throws ||
+ (do_break_2 && child.Reachability.AlwaysBreaks) ||
child.Reachability.AlwaysReturns ||
child.Reachability.AlwaysHasBarrier;
Report.Debug (2, " MERGING SIBLING #1", reachability,
Type, child.Type, child.Reachability.IsUnreachable,
- do_break_2, unreachable);
+ do_break_2, always_throws, unreachable);
- if (!unreachable)
+ if (!unreachable && (child.LocalVector != null))
MyBitVector.And (ref locals, child.LocalVector);
// An `out' parameter must be assigned in all branches which do
return result.Reachability;
}
- public virtual bool InTryBlock ()
+ //
+ // Checks whether we're in a `try' block.
+ //
+ public virtual bool InTryOrCatch (bool is_return)
+ {
+ if ((Block != null) && Block.IsDestructor)
+ return true;
+ else if (!is_return &&
+ ((Type == BranchingType.Loop) || (Type == BranchingType.Switch)))
+ return false;
+ else if (Parent != null)
+ return Parent.InTryOrCatch (is_return);
+ else
+ return false;
+ }
+
+ //
+ // Checks whether we're in a `catch' block.
+ //
+ public virtual bool InCatch ()
{
if (Parent != null)
- return Parent.InTryBlock ();
+ return Parent.InCatch ();
+ else
+ return false;
+ }
+
+ //
+ // Checks whether we're in a `finally' block.
+ //
+ public virtual bool InFinally (bool is_return)
+ {
+ if (!is_return &&
+ ((Type == BranchingType.Loop) || (Type == BranchingType.Switch)))
+ return false;
+ else if (Parent != null)
+ return Parent.InFinally (is_return);
+ else
+ return false;
+ }
+
+ public virtual bool InLoop ()
+ {
+ if (Type == BranchingType.Loop)
+ return true;
+ else if (Parent != null)
+ return Parent.InLoop ();
+ else
+ return false;
+ }
+
+ public virtual bool InSwitch ()
+ {
+ if (Type == BranchingType.Switch)
+ return true;
+ else if (Parent != null)
+ return Parent.InSwitch ();
+ else
+ return false;
+ }
+
+ public virtual bool BreakCrossesTryCatchBoundary ()
+ {
+ if ((Type == BranchingType.Loop) || (Type == BranchingType.Switch))
+ return false;
+ else if (Parent != null)
+ return Parent.BreakCrossesTryCatchBoundary ();
else
return false;
}
{
if (Parent != null)
Parent.AddFinallyVector (vector);
- else
+ else if ((Block == null) || !Block.IsDestructor)
throw new NotSupportedException ();
}
{
UsageVector sibling_list = null;
- public FlowBranchingBlock (FlowBranching parent, BranchingType type, SiblingType stype,
- Block block, Location loc)
+ public FlowBranchingBlock (FlowBranching parent, BranchingType type,
+ SiblingType stype, Block block, Location loc)
: base (parent, type, stype, block, loc)
{ }
UsageVector catch_vectors;
UsageVector finally_vector;
UsageVector finally_origins;
+ bool in_try;
- public FlowBranchingException (FlowBranching parent, BranchingType type, Block block, Location loc)
- : base (parent, type, SiblingType.Try, block, loc)
+ public FlowBranchingException (FlowBranching parent, Block block, Location loc)
+ : base (parent, BranchingType.Exception, SiblingType.Try, block, loc)
{ }
protected override void AddSibling (UsageVector sibling)
if (sibling.Type == SiblingType.Try) {
sibling.Next = catch_vectors;
catch_vectors = sibling;
+ in_try = true;
} else if (sibling.Type == SiblingType.Catch) {
sibling.Next = catch_vectors;
catch_vectors = sibling;
+ in_try = false;
} else if (sibling.Type == SiblingType.Finally) {
sibling.MergeFinallyOrigins (finally_origins);
finally_vector = sibling;
+ in_try = false;
} else
throw new InvalidOperationException ();
get { return current_vector; }
}
- public override bool InTryBlock ()
+ public override bool InTryOrCatch (bool is_return)
+ {
+ return finally_vector == null;
+ }
+
+ public override bool InCatch ()
+ {
+ return !in_try && (finally_vector == null);
+ }
+
+ public override bool InFinally (bool is_return)
+ {
+ return finally_vector != null;
+ }
+
+ public override bool BreakCrossesTryCatchBoundary ()
{
return true;
}
// <summary>
public readonly int Length;
- // <summary>
- // Type and name of all the variables.
- // Note that this is null for variables for which we do not need to compute
- // assignment info.
- // </summary>
- public readonly Type[] VariableTypes;
- public readonly string[] VariableNames;
-
VariableInfo[] map;
public VariableMap (InternalParameters ip)
{
Count = ip != null ? ip.Count : 0;
- map = new VariableInfo [Count];
- VariableNames = new string [Count];
- VariableTypes = new Type [Count];
+
+ // Dont bother allocating anything!
+ if (Count == 0)
+ return;
+
Length = 0;
for (int i = 0; i < Count; i++) {
if ((mod & Parameter.Modifier.OUT) == 0)
continue;
- VariableNames [i] = ip.ParameterName (i);
- VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i));
+ // Dont allocate till we find an out var.
+ if (map == null)
+ map = new VariableInfo [Count];
+
+ map [i] = new VariableInfo (ip.ParameterName (i),
+ TypeManager.GetElementType (ip.ParameterType (i)), i, Length);
- map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length);
Length += map [i].Length;
}
}
public VariableMap (VariableMap parent, LocalInfo[] locals)
{
int offset = 0, start = 0;
- if (parent != null) {
+ if (parent != null && parent.map != null) {
offset = parent.Length;
start = parent.Count;
}
Count = locals.Length + start;
+
+ if (Count == 0)
+ return;
+
map = new VariableInfo [Count];
- VariableNames = new string [Count];
- VariableTypes = new Type [Count];
Length = offset;
- if (parent != null) {
+ if (parent != null && parent.map != null) {
parent.map.CopyTo (map, 0);
- parent.VariableNames.CopyTo (VariableNames, 0);
- parent.VariableTypes.CopyTo (VariableTypes, 0);
}
for (int i = start; i < Count; i++) {
if (li.VariableType == null)
continue;
- VariableNames [i] = li.Name;
- VariableTypes [i] = li.VariableType;
-
map [i] = li.VariableInfo = new VariableInfo (li, Length);
Length += map [i].Length;
}
// </summary>
public VariableInfo this [int index] {
get {
+ if (map == null)
+ return null;
+
return map [index];
}
}
public class GenericMethod : DeclSpace
{
- public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name, Location l)
- : base (ns, parent, name, l)
+ public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
+ Attributes attrs, Location l)
+ : base (ns, parent, name, attrs, l)
{ }
public override TypeBuilder DefineType ()
ArrayList property_builders;
ArrayList event_builders;
- Attributes OptAttributes;
public string IndexerName;
public Interface (NamespaceEntry ns, TypeContainer parent, string name, int mod,
Attributes attrs, Location l)
- : base (ns, parent, name, l)
+ : base (ns, parent, name, attrs, l)
{
ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
- OptAttributes = attrs;
method_builders = new ArrayList ();
property_builders = new ArrayList ();
public static bool CheckContext (EmitContext ec, Location loc)
{
- if (ec.InFinally){
+ if (ec.CurrentBranching.InFinally (true)){
Report.Error (-208, loc, "yield statement can not appear in finally clause");
return false;
}
- if (ec.InCatch){
+ if (ec.CurrentBranching.InCatch ()){
Report.Error (-209, loc, "yield statement can not appear in the catch clause");
return false;
}
static bool IsVirtualFilter (MemberInfo m, object filterCriteria)
{
- if (!(m is MethodInfo))
- return false;
-
- return ((MethodInfo) m).IsVirtual;
+ MethodInfo mi = m as MethodInfo;
+ return (mi == null) ? false : mi.IsVirtual;
}
/// <summary>
// Notice that TypeBuilders will only return the interfaces that the Type
// is supposed to implement, not all the interfaces that the type implements.
//
- // Completely broken. Anyways, we take advantage of this, so we only register
- // the implementations that we need, as they are those that are listed by the
- // TypeBuilder.
+ // Even better -- on MS it returns an empty array, no matter what.
+ //
+ // Completely broken. So we do it ourselves!
//
- Type [] implementing_ifaces = type_builder.GetInterfaces ();
- int count = implementing_ifaces.Length;
+ TypeExpr [] impl = TypeManager.GetExplicitInterfaces (type_builder);
- if (implementing_ifaces.Length == 0)
+ if (impl == null || impl.Length == 0)
return EmptyMissingInterfacesInfo;
- MissingInterfacesInfo [] missing_info = new MissingInterfacesInfo [count];
+ MissingInterfacesInfo [] ret = new MissingInterfacesInfo [impl.Length];
- for (int i = 0; i < count; i++)
- missing_info [i] = new MissingInterfacesInfo (implementing_ifaces [i]);
+ for (int i = 0; i < impl.Length; i++)
+ ret [i] = new MissingInterfacesInfo (impl [i].Type);
+
+ // we really should not get here because Object doesnt implement any
+ // interfaces. But it could implement something internal, so we have
+ // to handle that case.
+ if (type_builder.BaseType == null)
+ return ret;
+ TypeExpr [] parent_impls = TypeManager.GetInterfaces (type_builder.BaseType);
- //
- // Now, we have to extract the interfaces implements by our parents, and
- // remove them from the implementing_ifaces array.
- //
- for (Type t = type_builder.BaseType; t != null; t = t.BaseType){
- Type [] base_ifaces = t.GetInterfaces ();
+ foreach (TypeExpr te in parent_impls) {
+ Type t = te.Type;
- foreach (Type base_iface in base_ifaces){
- for (int i = 0; i < count; i++){
- if (implementing_ifaces [i] == base_iface)
- missing_info [i].Optional = true;
+ for (int i = 0; i < ret.Length; i ++) {
+ if (t == ret [i].Type) {
+ ret [i].Optional = true;
+ break;
}
}
-
- //
- // When we reach a `Type' instead of `TypeBuilder', the GetInterfaces
- // call would have returned all of the parent implementations, so we can end.
- //
- if (!(t is TypeBuilder))
- break;
}
-
- return missing_info;
+ return ret;
}
//
if (pending_implementations [i].optional)
continue;
- string extra = "";
-
- if (pending_implementations [i].found [j])
- extra = ". (method might be non-public or static)";
- Report.Error (
- 536, container.Location,
- "`" + container.Name + "' does not implement " +
- "interface member `" +
- type.FullName + "." + mi.Name + "'" + extra);
+ if (pending_implementations [i].found [j]) {
+ string[] methodLabel = TypeManager.CSharpSignature (mi).Split ('.');
+ Report.Error (536, container.Location, "'{0}' does not implement interface member '{1}'. '{2}.{3}' is either static, not public, or has the wrong return type",
+ container.Name, methodLabel, container.Name, methodLabel[methodLabel.Length - 1]);
+ }
+ else {
+ Report.Error (535, container.Location, "'{0}' does not implement interface member '{1}'",
+ container.Name, TypeManager.CSharpSignature (mi));
+ }
} else {
- Report.Error (
- 534, container.Location,
- "`" + container.Name + "' does not implement " +
- "inherited abstract member `" +
- type.FullName + "." + mi.Name + "'");
+ Report.Error (534, container.Location, "'{0}' does not implement inherited abstract member '{1}'",
+ container.Name, TypeManager.CSharpSignature (mi));
}
errors = true;
j++;
//
if (global_attributes.Count > 0){
AssemblyBuilder ab = CodeGen.AssemblyBuilder;
- TypeContainer dummy = new TypeContainer (null, null, "", new Location (-1));
+ TypeContainer dummy = new TypeContainer ();
EmitContext temp_ec = new EmitContext (
dummy, Mono.CSharp.Location.Null, null, null, 0, false);
public abstract class Statement {
public Location loc;
- ///
+ /// <summary>
/// Resolves the statement, true means that all sub-statements
/// did resolve ok.
- //
+ // </summary>
public virtual bool Resolve (EmitContext ec)
{
return true;
}
+ /// <summary>
+ /// We already know that the statement is unreachable, but we still
+ /// need to resolve it to catch errors.
+ /// </summary>
+ public virtual bool ResolveUnreachable (EmitContext ec, bool warn)
+ {
+ //
+ // This conflicts with csc's way of doing this, but IMHO it's
+ // the right thing to do.
+ //
+ // If something is unreachable, we still check whether it's
+ // correct. This means that you cannot use unassigned variables
+ // in unreachable code, for instance.
+ //
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ bool ok = Resolve (ec);
+ ec.KillFlowBranching ();
+
+ if (!ok)
+ return false;
+
+ if (warn)
+ Report.Warning (162, loc, "Unreachable code detected");
+ return true;
+ }
+
/// <summary>
/// Return value indicates whether all code paths emitted return.
/// </summary>
protected abstract void DoEmit (EmitContext ec);
/// <summary>
- /// Return value indicates whether all code paths emitted return.
+ /// Utility wrapper routine for Error, just to beautify the code
/// </summary>
- public virtual void Emit (EmitContext ec)
+ public void Error (int error, string format, params object[] args)
{
- ec.Mark (loc, true);
- DoEmit (ec);
+ Error (error, String.Format (format, args));
}
- /// <remarks>
- /// Encapsulates the emission of a boolean test and jumping to a
- /// destination.
- ///
- /// This will emit the bool expression in `bool_expr' and if
- /// `target_is_for_true' is true, then the code will generate a
- /// brtrue to the target. Otherwise a brfalse.
- /// </remarks>
- public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
- Label target, bool target_is_for_true)
+ public void Error (int error, string s)
{
- ILGenerator ig = ec.ig;
-
- bool invert = false;
- if (bool_expr is Unary){
- Unary u = (Unary) bool_expr;
-
- if (u.Oper == Unary.Operator.LogicalNot){
- invert = true;
-
- u.EmitLogicalNot (ec);
- }
- } else if (bool_expr is Binary){
- Binary b = (Binary) bool_expr;
-
- if (b.EmitBranchable (ec, target, target_is_for_true))
- return;
- }
-
- if (!invert)
- bool_expr.Emit (ec);
-
- if (target_is_for_true){
- if (invert)
- ig.Emit (OpCodes.Brfalse, target);
- else
- ig.Emit (OpCodes.Brtrue, target);
- } else {
- if (invert)
- ig.Emit (OpCodes.Brtrue, target);
+ if (!Location.IsNull (loc))
+ Report.Error (error, loc, s);
else
- ig.Emit (OpCodes.Brfalse, target);
- }
+ Report.Error (error, s);
}
- public static void Warning_DeadCodeFound (Location loc)
+ /// <summary>
+ /// Return value indicates whether all code paths emitted return.
+ /// </summary>
+ public virtual void Emit (EmitContext ec)
{
- Report.Warning (162, loc, "Unreachable code detected");
+ ec.Mark (loc, true);
+ DoEmit (ec);
}
}
return false;
}
- ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+ //
+ // Dead code elimination
+ //
+ if (expr is BoolConstant){
+ bool take = ((BoolConstant) expr).Value;
+
+ if (take){
+ if (!TrueStatement.Resolve (ec))
+ return false;
+
+ if ((FalseStatement != null) &&
+ !FalseStatement.ResolveUnreachable (ec, true))
+ return false;
+ FalseStatement = null;
+ } else {
+ if (!TrueStatement.ResolveUnreachable (ec, true))
+ return false;
+ TrueStatement = null;
- if (!TrueStatement.Resolve (ec)) {
- ec.KillFlowBranching ();
+ if ((FalseStatement != null) &&
+ !FalseStatement.Resolve (ec))
return false;
}
+ return true;
+ }
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
+
+ bool ok = TrueStatement.Resolve (ec);
+
is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
- if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
- ec.KillFlowBranching ();
- return false;
- }
+ if ((FalseStatement != null) && !FalseStatement.Resolve (ec))
+ ok = false;
ec.EndFlowBranching ();
Report.Debug (1, "END IF BLOCK", loc);
- return true;
+ return ok;
}
protected override void DoEmit (EmitContext ec)
Label end;
//
- // Dead code elimination
+ // If we're a boolean expression, Resolve() already
+ // eliminated dead code for us.
//
if (expr is BoolConstant){
bool take = ((BoolConstant) expr).Value;
- if (take){
- if (FalseStatement != null){
- Warning_DeadCodeFound (FalseStatement.loc);
- }
+ if (take)
TrueStatement.Emit (ec);
- return;
- } else {
- Warning_DeadCodeFound (TrueStatement.loc);
- if (FalseStatement != null) {
+ else if (FalseStatement != null)
FalseStatement.Emit (ec);
+
return;
}
- }
- }
- EmitBoolExpression (ec, expr, false_target, false);
+ expr.EmitBranchable (ec, false_target, false);
TrueStatement.Emit (ec);
{
bool ok = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
if (!EmbeddedStatement.Resolve (ec))
ok = false;
Label loop = ig.DefineLabel ();
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
ig.MarkLabel (loop);
EmbeddedStatement.Emit (ec);
if (res)
ec.ig.Emit (OpCodes.Br, loop);
} else
- EmitBoolExpression (ec, expr, loop, true);
+ expr.EmitBranchable (ec, loop, true);
ig.MarkLabel (ec.LoopEnd);
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
}
}
public class While : Statement {
public Expression expr;
public readonly Statement Statement;
- bool empty, infinite;
+ bool infinite, empty;
public While (Expression boolExpr, Statement statement, Location l)
{
if (expr == null)
return false;
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
-
//
// Inform whether we are infinite or not
//
BoolConstant bc = (BoolConstant) expr;
if (bc.Value == false){
- Warning_DeadCodeFound (Statement.loc);
+ if (!Statement.ResolveUnreachable (ec, true))
+ return false;
empty = true;
+ return true;
} else
infinite = true;
- } else {
- //
- // We are not infinite, so the loop may or may not be executed.
- //
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
}
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+
if (!Statement.Resolve (ec))
ok = false;
- if (empty)
- ec.KillFlowBranching ();
- else {
ec.CurrentBranching.Infinite = infinite;
ec.EndFlowBranching ();
- }
return ok;
}
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
//
// Inform whether we are infinite or not
ig.MarkLabel (ec.LoopBegin);
- EmitBoolExpression (ec, expr, while_loop, true);
+ expr.EmitBranchable (ec, while_loop, true);
+
ig.MarkLabel (ec.LoopEnd);
}
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
BoolConstant bc = (BoolConstant) Test;
if (bc.Value == false){
- Warning_DeadCodeFound (Statement.loc);
+ if (!Statement.ResolveUnreachable (ec, true))
+ return false;
+ if ((Increment != null) &&
+ !Increment.ResolveUnreachable (ec, false))
+ return false;
empty = true;
+ return true;
} else
infinite = true;
}
} else
infinite = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
if (!infinite)
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
ok = false;
}
- if (empty)
- ec.KillFlowBranching ();
- else {
ec.CurrentBranching.Infinite = infinite;
ec.EndFlowBranching ();
- }
return ok;
}
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
Label loop = ig.DefineLabel ();
Label test = ig.DefineLabel ();
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
ig.Emit (OpCodes.Br, test);
ig.MarkLabel (loop);
//
if (Test != null){
//
- // The Resolve code already catches the case for Test == BoolConstant (false)
- // so we know that this is true
+ // The Resolve code already catches the case for
+ // Test == BoolConstant (false) so we know that
+ // this is true
//
if (Test is BoolConstant)
ig.Emit (OpCodes.Br, loop);
else
- EmitBoolExpression (ec, Test, loop, true);
+ Test.EmitBranchable (ec, loop, true);
+
} else
ig.Emit (OpCodes.Br, loop);
ig.MarkLabel (ec.LoopEnd);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
loc = l;
}
+ bool in_exc;
+
public override bool Resolve (EmitContext ec)
{
+ if (ec.ReturnType == null){
if (Expr != null){
+ Error (127, "Return with a value not allowed here");
+ return false;
+ }
+ } else {
+ if (Expr == null){
+ Error (126, "An object of type `{0}' is expected " +
+ "for the return statement",
+ TypeManager.CSharpName (ec.ReturnType));
+ return false;
+ }
+
Expr = Expr.Resolve (ec);
if (Expr == null)
return false;
+
+ if (Expr.Type != ec.ReturnType) {
+ Expr = Convert.ImplicitConversionRequired (
+ ec, Expr, ec.ReturnType, loc);
+ if (Expr == null)
+ return false;
+ }
}
if (ec.InIterator){
- Report.Error (-206, loc, "Return statement not allowed inside iterators");
+ Error (-206, "Return statement not allowed inside iterators");
return false;
}
FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
- if (ec.CurrentBranching.InTryBlock ())
+ if (ec.CurrentBranching.InTryOrCatch (true)) {
ec.CurrentBranching.AddFinallyVector (vector);
- else
+ in_exc = true;
+ } else if (ec.CurrentBranching.InFinally (true)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else
vector.CheckOutParameters (ec.CurrentBranching);
ec.CurrentBranching.CurrentUsageVector.Return ();
protected override void DoEmit (EmitContext ec)
{
- if (ec.InFinally){
- Report.Error (157, loc, "Control can not leave the body of the finally block");
- return;
- }
-
- if (ec.ReturnType == null){
- if (Expr != null){
- Report.Error (127, loc, "Return with a value not allowed here");
- return;
- }
- } else {
- if (Expr == null){
- Report.Error (126, loc, "An object of type `" +
- TypeManager.CSharpName (ec.ReturnType) + "' is " +
- "expected for the return statement");
- return;
- }
-
- if (Expr.Type != ec.ReturnType)
- Expr = Convert.ImplicitConversionRequired (
- ec, Expr, ec.ReturnType, loc);
-
- if (Expr == null)
- return;
-
+ if (Expr != null) {
Expr.Emit (ec);
- if (ec.InTry || ec.InCatch)
+ if (in_exc || !ec.IsLastStatement)
ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
}
- if (ec.InTry || ec.InCatch) {
- if (!ec.HasReturnLabel) {
- ec.ReturnLabel = ec.ig.DefineLabel ();
- ec.HasReturnLabel = true;
- }
+ if (in_exc) {
+ ec.NeedReturnLabel ();
ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
- } else {
+ } else if (ec.IsLastStatement) {
+ // If we are the last statement in a top-level block, simply
+ // emit a `ret'.
ec.ig.Emit (OpCodes.Ret);
- ec.NeedExplicitReturn = false;
+ } else {
+ // Otherwise, we always create a return label and jump to
+ // it.
+ ec.NeedReturnLabel ();
+ ec.ig.Emit (OpCodes.Br, ec.ReturnLabel);
}
}
}
public override bool Resolve (EmitContext ec)
{
+ bool in_catch = ec.CurrentBranching.InCatch ();
+ ec.CurrentBranching.CurrentUsageVector.Throw ();
+
if (expr != null){
expr = expr.Resolve (ec);
if (expr == null)
if ((t != TypeManager.exception_type) &&
!t.IsSubclassOf (TypeManager.exception_type) &&
!(expr is NullLiteral)) {
- Report.Error (155, loc,
+ Error (155,
"The type caught or thrown must be derived " +
"from System.Exception");
return false;
}
+ } else if (!in_catch) {
+ Error (156,
+ "A throw statement with no argument is only " +
+ "allowed in a catch clause");
+ return false;
}
- ec.CurrentBranching.CurrentUsageVector.Throw ();
return true;
}
protected override void DoEmit (EmitContext ec)
{
- if (expr == null){
- if (ec.InCatch)
+ if (expr == null)
ec.ig.Emit (OpCodes.Rethrow);
else {
- Report.Error (
- 156, loc,
- "A throw statement with no argument is only " +
- "allowed in a catch clause");
- }
- return;
- }
-
expr.Emit (ec);
ec.ig.Emit (OpCodes.Throw);
}
}
+ }
public class Break : Statement {
loc = l;
}
+ bool crossing_exc;
+
public override bool Resolve (EmitContext ec)
{
+ if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+ Error (139, "No enclosing loop or switch to continue to");
+ return false;
+ } else if (ec.CurrentBranching.InFinally (false)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else if (ec.CurrentBranching.InTryOrCatch (false))
+ ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector);
+
+ crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
ec.CurrentBranching.CurrentUsageVector.Break ();
return true;
}
{
ILGenerator ig = ec.ig;
- if (ec.InLoop == false && ec.Switch == null){
- Report.Error (139, loc, "No enclosing loop or switch to continue to");
- return;
- }
-
- if (ec.InTry || ec.InCatch)
+ if (crossing_exc)
ig.Emit (OpCodes.Leave, ec.LoopEnd);
- else
+ else {
+ ec.NeedReturnLabel ();
ig.Emit (OpCodes.Br, ec.LoopEnd);
}
}
+ }
public class Continue : Statement {
loc = l;
}
+ bool crossing_exc;
+
public override bool Resolve (EmitContext ec)
{
+ if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+ Error (139, "No enclosing loop to continue to");
+ return false;
+ } else if (ec.CurrentBranching.InFinally (false)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else if (ec.CurrentBranching.InTryOrCatch (false))
+ ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector);
+
+ crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
{
Label begin = ec.LoopBegin;
- if (!ec.InLoop){
- Report.Error (139, loc, "No enclosing loop to continue to");
- return;
- }
-
- //
- // UGH: Non trivial. This Br might cross a try/catch boundary
- // How can we tell?
- //
- // while () {
- // try { ... } catch { continue; }
- // }
- //
- // From:
- // try {} catch { while () { continue; }}
- //
- if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
+ if (crossing_exc)
ec.ig.Emit (OpCodes.Leave, begin);
- else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
- throw new Exception ("Should never happen");
else
ec.ig.Emit (OpCodes.Br, begin);
}
///
/// Implicit blocks are used as labels or to introduce variable
/// declarations.
+ ///
+ /// Top-level blocks derive from Block, and they are called ToplevelBlock
+ /// they contain extra information that is not necessary on normal blocks.
/// </remarks>
public class Block : Statement {
public readonly Block Parent;
Unchecked = 2,
BlockUsed = 4,
VariablesInitialized = 8,
- HasRet = 16
+ HasRet = 16,
+ IsDestructor = 32
}
Flags flags;
// The statements in this block
//
ArrayList statements;
+ int num_statements;
//
// An array of Blocks. We keep track of children just
}
}
+ public bool IsDestructor {
+ get {
+ return (flags & Flags.IsDestructor) != 0;
+ }
+ }
+
+ public void SetDestructor ()
+ {
+ flags |= Flags.IsDestructor;
+ }
+
VariableMap param_map, local_map;
public VariableMap ParameterMap {
Statement s = (Statement) statements [ix];
if (unreachable && !(s is LabeledStatement)) {
- if (!warning_shown && s != EmptyStatement.Value) {
+ if (!s.ResolveUnreachable (ec, !warning_shown))
+ ok = false;
+
+ if (s != EmptyStatement.Value)
warning_shown = true;
- Warning_DeadCodeFound (s.loc);
- }
statements [ix] = EmptyStatement.Value;
continue;
continue;
}
+ num_statements = ix + 1;
+
if (s is LabeledStatement)
unreachable = false;
else
unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
}
- Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+ Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
+ ec.CurrentBranching, statement_count, num_statements);
FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
protected override void DoEmit (EmitContext ec)
{
- int statement_count = statements.Count;
- for (int ix = 0; ix < statement_count; ix++){
+ for (int ix = 0; ix < num_statements; ix++){
Statement s = (Statement) statements [ix];
+
+ // Check whether we are the last statement in a
+ // top-level block.
+
+ if ((Parent == null) && (ix+1 == num_statements))
+ ec.IsLastStatement = true;
+ else
+ ec.IsLastStatement = false;
+
s.Emit (ec);
}
}
}
}
+ //
+ //
+ public class ToplevelBlock : Block {
+ public ToplevelBlock (Parameters parameters, Location start) :
+ base (null, parameters, start, Location.Null)
+ {
+ }
+
+ public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ base (null, flags, parameters, start, Location.Null)
+ {
+ }
+ }
+
public class SwitchLabel {
Expression label;
object converted;
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
+ Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
bool first = true;
if (!got_default)
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
- ec.EndFlowBranching ();
+ FlowBranching.Reachability reachability = ec.EndFlowBranching ();
ec.Switch = old_switch;
+ Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching,
+ reachability);
+
return true;
}
public override bool Resolve (EmitContext ec)
{
expr = expr.Resolve (ec);
- return Statement.Resolve (ec) && expr != null;
+ if (expr == null)
+ return false;
+
+ if (expr.Type.IsValueType){
+ Error (185, "lock statement requires the expression to be " +
+ " a reference type (type is: `{0}'",
+ TypeManager.CSharpName (expr.Type));
+ return false;
+ }
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
+ bool ok = Statement.Resolve (ec);
+ ec.EndFlowBranching ();
+
+ return ok;
}
protected override void DoEmit (EmitContext ec)
{
Type type = expr.Type;
- if (type.IsValueType){
- Report.Error (185, loc, "lock statement requires the expression to be " +
- " a reference type (type is: `" +
- TypeManager.CSharpName (type) + "'");
- return;
- }
-
ILGenerator ig = ec.ig;
LocalBuilder temp = ig.DeclareLocal (type);
// try
ig.BeginExceptionBlock ();
- bool old_in_try = ec.InTry;
- ec.InTry = true;
Label finish = ig.DefineLabel ();
Statement.Emit (ec);
- ec.InTry = old_in_try;
// ig.Emit (OpCodes.Leave, finish);
ig.MarkLabel (finish);
// is present, so we need to test for this particular case.
//
+ if (e is Cast){
+ Report.Error (254, loc, "Cast expression not allowed as right hand expression in fixed statement");
+ return false;
+ }
+
//
// Case 1: & object.
//
data [i].converted = null;
data [i].vi = vi;
i++;
+ continue;
+ }
+
+ //
+ // For other cases, flag a `this is already fixed expression'
+ //
+ if (e is LocalVariableReference || e is ParameterReference ||
+ Convert.ImplicitConversionExists (ec, e, vi.VariableType)){
+
+ Report.Error (245, loc, "right hand expression is already fixed, no need to use fixed statement ");
+ return false;
}
+
+ Report.Error (245, loc, "Fixed statement only allowed on strings, arrays or address-of expressions");
+ return false;
}
ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
- bool old_in_try = ec.InTry;
- ec.InTry = true;
-
if (!Block.Resolve (ec))
ok = false;
- ec.InTry = old_in_try;
-
FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
Report.Debug (1, "START OF CATCH BLOCKS", vector);
vi.VariableInfo = null;
}
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
-
if (!c.Resolve (ec))
ok = false;
-
- ec.InCatch = old_in_catch;
}
Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
-
if (!General.Resolve (ec))
ok = false;
-
- ec.InCatch = old_in_catch;
}
Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Finally);
Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
-
if (!Fini.Resolve (ec))
ok = false;
-
- ec.InFinally = old_in_finally;
}
FlowBranching.Reachability reachability = ec.EndFlowBranching ();
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
// As a workaround, emit an explicit ret here.
- ec.NeedExplicitReturn = true;
+ ec.NeedReturnLabel ();
}
return ok;
ILGenerator ig = ec.ig;
Label finish = ig.DefineLabel ();;
- ec.TryCatchLevel++;
ig.BeginExceptionBlock ();
- bool old_in_try = ec.InTry;
- ec.InTry = true;
Block.Emit (ec);
- ec.InTry = old_in_try;
//
// System.Reflection.Emit provides this automatically:
// ig.Emit (OpCodes.Leave, finish);
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
-
foreach (Catch c in Specific){
LocalInfo vi;
ig.Emit (OpCodes.Pop);
General.Block.Emit (ec);
}
- ec.InCatch = old_in_catch;
ig.MarkLabel (finish);
if (Fini != null){
ig.BeginFinallyBlock ();
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
Fini.Emit (ec);
- ec.InFinally = old_in_finally;
}
ig.EndExceptionBlock ();
- ec.TryCatchLevel--;
}
}
ILGenerator ig = ec.ig;
int i = 0;
- bool old_in_try = ec.InTry;
- ec.InTry = true;
for (i = 0; i < assign.Length; i++) {
assign [i].EmitStatement (ec);
ig.BeginExceptionBlock ();
}
Statement.Emit (ec);
- ec.InTry = old_in_try;
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
var_list.Reverse ();
foreach (DictionaryEntry e in var_list){
LocalVariableReference var = (LocalVariableReference) e.Key;
ig.BeginFinallyBlock ();
+ if (!var.Type.IsValueType) {
var.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
converted_vars [i].Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ } else {
+ Expression ml = Expression.MemberLookup(ec, typeof(IDisposable), var.Type, "Dispose", Mono.CSharp.Location.Null);
+
+ if (!(ml is MethodGroupExpr)) {
+ var.Emit (ec);
+ ig.Emit (OpCodes.Box, var.Type);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ } else {
+ MethodInfo mi = null;
+
+ foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
+ if (mk.GetParameters().Length == 0) {
+ mi = mk;
+ break;
+ }
+ }
+
+ if (mi == null) {
+ Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+ return false;
+ }
+
+ var.AddressOf (ec, AddressOp.Load);
+ ig.Emit (OpCodes.Call, mi);
+ }
+ }
+
ig.MarkLabel (skip);
ig.EndExceptionBlock ();
}
- ec.InFinally = old_in_finally;
return false;
}
expr.Emit (ec);
ig.Emit (OpCodes.Stloc, local_copy);
- bool old_in_try = ec.InTry;
- ec.InTry = true;
ig.BeginExceptionBlock ();
Statement.Emit (ec);
- ec.InTry = old_in_try;
Label skip = ig.DefineLabel ();
- bool old_in_finally = ec.InFinally;
ig.BeginFinallyBlock ();
ig.Emit (OpCodes.Ldloc, local_copy);
ig.Emit (OpCodes.Brfalse, skip);
ig.Emit (OpCodes.Ldloc, local_copy);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (skip);
- ec.InFinally = old_in_finally;
ig.EndExceptionBlock ();
return false;
return false;
}
- ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
bool ok = Statement.Resolve (ec);
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
// As a workaround, emit an explicit ret here.
- ec.NeedExplicitReturn = true;
+ ec.NeedReturnLabel ();
}
return true;
empty = new EmptyExpression (hm.element_type);
}
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
//
//
conv = Convert.ExplicitConversion (ec, empty, var_type, loc);
if (conv == null)
- return false;
+ ok = false;
variable = variable.ResolveLValue (ec, empty);
if (variable == null)
- return false;
+ ok = false;
+
+ bool disposable = (hm != null) && hm.is_disposable;
+ if (disposable)
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
if (!statement.Resolve (ec))
- return false;
+ ok = false;
+
+ if (disposable)
+ ec.EndFlowBranching ();
ec.EndFlowBranching ();
- return true;
+ return ok;
}
//
// Protect the code in a try/finalize block, so that
// if the beast implement IDisposable, we get rid of it
//
- bool old_in_try = ec.InTry;
-
- if (hm.is_disposable) {
+ if (hm.is_disposable)
ig.BeginExceptionBlock ();
- ec.InTry = true;
- }
Label end_try = ig.DefineLabel ();
statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
ig.MarkLabel (end_try);
- ec.InTry = old_in_try;
// The runtime provides this for us.
// ig.Emit (OpCodes.Leave, end);
//
if (hm.is_disposable) {
Label end_finally = ig.DefineLabel ();
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
ig.BeginFinallyBlock ();
disposable.EmitThis ();
disposable.EmitLoad ();
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (end_finally);
- ec.InFinally = old_in_finally;
// The runtime generates this anyways.
// ig.Emit (OpCodes.Endfinally);
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
if (hm != null)
EmitCollectionForeach (ec);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
}
public Tree ()
{
- root_types = new TypeContainer (null, null, "", new Location (-1));
+ root_types = new TypeContainer ();
decls = new Hashtable ();
namespaces = new Hashtable ();
/// </summary>
public static void AddAssembly (Assembly a)
{
+ foreach (Assembly assembly in assemblies) {
+ if (a == assembly)
+ return;
+ }
+
int top = assemblies.Length;
Assembly [] n = new Assembly [top + 1];
+ match.Groups [2].Captures [0].Value;
}
+ /// <summary>
+ /// Returns the signature of the method with full namespace classification
+ /// </summary>
+ static public string GetFullNameSignature (MemberInfo mi)
+ {
+ return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
+ }
+
+ /// <summary>
+ /// Returns the signature of the property and indexer
+ /// </summary>
+ static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
+ {
+ if (!is_indexer) {
+ return GetFullNameSignature (pb);
+ }
+
+ MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
+ string signature = GetFullNameSignature (mb);
+ string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
+ return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
+ }
+
/// <summary>
/// Returns the signature of the method
/// </summary>
}
sig += ")";
- return mb.DeclaringType.Name + "." + mb.Name + sig;
+ return GetFullNameSignature (mb) + sig;
}
/// <summary>
return ret;
}
+ static PtrHashtable iface_cache = new PtrHashtable ();
+
/// <summary>
/// This function returns the interfaces in the type `t'. Works with
/// both types and TypeBuilders.
/// </summary>
public static TypeExpr [] GetInterfaces (Type t)
{
+
+ TypeExpr [] cached = iface_cache [t] as TypeExpr [];
+ if (cached != null)
+ return cached;
+
//
// The reason for catching the Array case is that Reflection.Emit
// will not return a TypeBuilder for Array types of TypeBuilder types,
parent_ifaces.CopyTo (result, 0);
type_ifaces.CopyTo (result, parent_count);
+ iface_cache [t] = result;
return result;
} else {
Type [] ifaces = t.GetInterfaces ();
+ if (ifaces.Length == 0)
+ return NoTypeExprs;
TypeExpr [] result = new TypeExpr [ifaces.Length];
for (int i = 0; i < ifaces.Length; i++)
result [i] = new TypeExpression (ifaces [i], Location.Null);
+
+ iface_cache [t] = result;
return result;
}
}
+ //
+ // gets the interfaces that are declared explicitly on t
+ //
+ public static TypeExpr [] GetExplicitInterfaces (TypeBuilder t)
+ {
+ return (TypeExpr []) builder_to_ifaces [t];
+ }
+
/// <remarks>
/// The following is used to check if a given type implements an interface.
/// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.