[csdoc-patches] csdoc/src/mcs/mcs .cvsignore,NONE,1.1 anonymous.cs,NONE,1.1 AssemblyInfo.cs,NONE,1.1
Status: Planning
Brought to you by:
mastergaurav
Update of /cvsroot/csdoc/csdoc/src/mcs/mcs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19706 Added Files: .cvsignore anonymous.cs AssemblyInfo.cs assign.cs attribute.cs cfold.cs ChangeLog class.cs codegen.cs compiler.doc compiler.sln const.cs constant.cs convert.cs cs-parser.jay cs-tokenizer.cs decl.cs delegate.cs driver.cs ecore.cs enum.cs errors.cs expression.cs flowanalysis.cs gen-il.cs gen-treedump.cs generic.cs genericparser.cs interface.cs iterators.cs literal.cs location.cs makefile makefile.gnu makefile.old mcs.exe.config mcs.exe.sources modifiers.cs namespace.cs NOTES old-code.cs OTODO parameter.cs parameterCollection.cs parser.cs pending.cs README report.cs rootcontext.cs statement.cs statementCollection.cs support.cs symbolwriter.cs TODO tree.cs typemanager.cs Log Message: Cleanup. All files have been moved to mcs --- NEW FILE: .cvsignore --- *.mdb *.pdb Web References Web References Web References bin compiler.csproj compiler.csproj.user compiler.exe compiler.pdb compiler.suo cs-parser.cs mcs obj semantic.cache y.output --- NEW FILE: anonymous.cs --- // // anonymous.cs: Support for anonymous methods // // Author: // Miguel de Icaza (mi...@xi...) // // (C) 2003 Ximian, Inc. // using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; namespace Mono.CSharp { public class AnonymousMethod : Expression { // An array list of AnonymousMethodParameter or null Parameters parameters; Block block; public AnonymousMethod (Parameters parameters, Block block, Location l) { this.parameters = parameters; this.block = block; loc = l; } public override Expression DoResolve (EmitContext ec) { // // Set class type, set type // eclass = ExprClass.Value; // // This hack means `The type is not accessible // anywhere', we depend on special conversion // rules. // type = typeof (AnonymousMethod); return this; } public override void Emit (EmitContext ec) { // nothing, as we only exist to not do anything. } } } --- NEW FILE: AssemblyInfo.cs --- using System.Reflection; using System.Runtime.CompilerServices; [assembly: AssemblyVersion("1.1.1")] [assembly: AssemblyTitle ("Mono C# Compiler")] [assembly: AssemblyDescription ("Mono C# Compiler")] [assembly: AssemblyCopyright ("2001, 2002, 2003 Ximian, Inc.")] [assembly: AssemblyCompany ("Ximian, Inc.")] --- NEW FILE: assign.cs --- // // assign.cs: Assignments. // // Author: // Miguel de Icaza (mi...@xi...) // Martin Baulig (ma...@gn...) // // (C) 2001, 2002, 2003 Ximian, Inc. // using System; using System.Reflection; using System.Reflection.Emit; namespace Mono.CSharp { /// <summary> /// This interface is implemented by expressions that can be assigned to. /// </summary> /// <remarks> /// This interface is implemented by Expressions whose values can not /// store the result on the top of the stack. /// /// Expressions implementing this (Properties, Indexers and Arrays) would /// perform an assignment of the Expression "source" into its final /// location. /// /// No values on the top of the stack are expected to be left by /// invoking this method. /// </remarks> public interface IAssignMethod { // // This is an extra version of Emit. If leave_copy is `true' // A copy of the expression will be left on the stack at the // end of the code generated for EmitAssign // void Emit (EmitContext ec, bool leave_copy); // // This method does the assignment // `source' will be stored into the location specified by `this' // if `leave_copy' is true, a copy of `source' will be left on the stack // if `prepare_for_load' is true, when `source' is emitted, there will // be data on the stack that it can use to compuatate its value. This is // for expressions like a [f ()] ++, where you can't call `f ()' twice. // void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load); /* For simple assignments, this interface is very simple, EmitAssign is called with source as the source expression and leave_copy and prepare_for_load false. For compound assignments it gets complicated. EmitAssign will be called as before, however, prepare_for_load will be true. The @source expression will contain an expression which calls Emit. So, the calls look like: this.EmitAssign (ec, source, false, true) -> source.Emit (ec); -> [...] -> this.Emit (ec, false); -> end this.Emit (ec, false); -> end [...] end source.Emit (ec); end this.EmitAssign (ec, source, false, true) When prepare_for_load is true, EmitAssign emits a `token' on the stack that Emit will use for its state. Let's take FieldExpr as an example. assume we are emitting f ().y += 1; Here is the call tree again. This time, each call is annotated with the IL it produces: this.EmitAssign (ec, source, false, true) call f dup Binary.Emit () this.Emit (ec, false); ldfld y end this.Emit (ec, false); IntConstant.Emit () ldc.i4.1 end IntConstant.Emit add end Binary.Emit () stfld end this.EmitAssign (ec, source, false, true) Observe two things: 1) EmitAssign left a token on the stack. It was the result of f (). 2) This token was used by Emit leave_copy (in both EmitAssign and Emit) tells the compiler to leave a copy of the expression at that point in evaluation. This is used for pre/post inc/dec and for a = x += y. Let's do the above example with leave_copy true in EmitAssign this.EmitAssign (ec, source, true, true) call f dup Binary.Emit () this.Emit (ec, false); ldfld y end this.Emit (ec, false); IntConstant.Emit () ldc.i4.1 end IntConstant.Emit add end Binary.Emit () dup stloc temp stfld ldloc temp end this.EmitAssign (ec, source, true, true) And with it true in Emit this.EmitAssign (ec, source, false, true) call f dup Binary.Emit () this.Emit (ec, true); ldfld y dup stloc temp end this.Emit (ec, true); IntConstant.Emit () ldc.i4.1 end IntConstant.Emit add end Binary.Emit () stfld ldloc temp end this.EmitAssign (ec, source, false, true) Note that these two examples are what happens for ++x and x++, respectively. */ } /// <summary> /// An Expression to hold a temporary value. /// </summary> /// <remarks> /// The LocalTemporary class is used to hold temporary values of a given /// type to "simulate" the expression semantics on property and indexer /// access whose return values are void. /// /// The local temporary is used to alter the normal flow of code generation /// basically it creates a local variable, and its emit instruction generates /// code to access this value, return its address or save its value. /// /// If `is_address' is true, then the value that we store is the address to the /// real value, and not the value itself. /// /// This is needed for a value type, because otherwise you just end up making a /// copy of the value on the stack and modifying it. You really need a pointer /// to the origional value so that you can modify it in that location. This /// Does not happen with a class because a class is a pointer -- so you always /// get the indirection. /// /// The `is_address' stuff is really just a hack. We need to come up with a better /// way to handle it. /// </remarks> public class LocalTemporary : Expression, IMemoryLocation { LocalBuilder builder; bool is_address; public LocalTemporary (EmitContext ec, Type t) : this (ec, t, false) {} public LocalTemporary (EmitContext ec, Type t, bool is_address) { type = t; eclass = ExprClass.Value; loc = Location.Null; builder = ec.GetTemporaryLocal (is_address ? TypeManager.GetReferenceType (t): t); this.is_address = is_address; } public LocalTemporary (LocalBuilder b, Type t) { type = t; eclass = ExprClass.Value; loc = Location.Null; builder = b; } public void Release (EmitContext ec) { ec.FreeTemporaryLocal (builder, type); builder = null; } public override Expression DoResolve (EmitContext ec) { return this; } public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; ig.Emit (OpCodes.Ldloc, builder); // we need to copy from the pointer if (is_address) LoadFromPtr (ig, type); } // NB: if you have `is_address' on the stack there must // be a managed pointer. Otherwise, it is the type from // the ctor. public void Store (EmitContext ec) { ILGenerator ig = ec.ig; ig.Emit (OpCodes.Stloc, builder); } public void AddressOf (EmitContext ec, AddressOp mode) { // if is_address, than this is just the address anyways, // so we just return this. ILGenerator ig = ec.ig; if (is_address) ig.Emit (OpCodes.Ldloc, builder); else ig.Emit (OpCodes.Ldloca, builder); } public bool PointsToAddress { get { return is_address; } } } /// <summary> /// The Assign node takes care of assigning the value of source into /// the expression represented by target. /// </summary> public class Assign : ExpressionStatement { protected Expression target, source, real_source; protected LocalTemporary temp = null, real_temp = null; protected Assign embedded = null; protected bool is_embedded = false; protected bool must_free_temp = false; public Assign (Expression target, Expression source, Location l) { this.target = target; this.source = this.real_source = source; this.loc = l; } protected Assign (Assign embedded, Location l) : this (embedded.target, embedded.source, l) { this.is_embedded = true; } protected virtual Assign GetEmbeddedAssign (Location loc) { return new Assign (this, loc); } public Expression Target { get { return target; } set { target = value; } } public Expression Source { get { return source; } set { source = value; } } public static void error70 (EventInfo ei, Location l) { Report.Error (70, l, "The event '" + ei.Name + "' can only appear on the left-side of a += or -= (except when" + " used from within the type '" + ei.DeclaringType + "')"); } // // Will return either `this' or an instance of `New'. // public override Expression DoResolve (EmitContext ec) { // Create an embedded assignment if our source is an assignment. if (source is Assign) source = embedded = ((Assign) source).GetEmbeddedAssign (loc); real_source = source = source.Resolve (ec); if (source == null) return null; // // This is used in an embedded assignment. // As an example, consider the statement "A = X = Y = Z". // if (is_embedded && !(source is Constant)) { // If this is the innermost assignment (the "Y = Z" in our example), // create a new temporary local, otherwise inherit that variable // from our child (the "X = (Y = Z)" inherits the local from the // "Y = Z" assignment). if (embedded == null) { if (this is CompoundAssign) real_temp = temp = new LocalTemporary (ec, target.Type); else real_temp = temp = new LocalTemporary (ec, source.Type); } else temp = embedded.temp; // Set the source to the new temporary variable. // This means that the following target.ResolveLValue () will tell // the target to read it's source value from that variable. source = temp; } // If we have an embedded assignment, use the embedded assignment's temporary // local variable as source. if (embedded != null) source = (embedded.temp != null) ? embedded.temp : embedded.source; target = target.ResolveLValue (ec, source); if (target == null) return null; Type target_type = target.Type; Type source_type = real_source.Type; // If we're an embedded assignment, our parent will reuse our source as its // source, it won't read from our target. if (is_embedded) type = source_type; else type = target_type; eclass = ExprClass.Value; if (target is EventExpr) { EventInfo ei = ((EventExpr) target).EventInfo; Expression ml = MemberLookup ( ec, ec.ContainerType, ei.Name, MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc); if (ml == null) { // // If this is the case, then the Event does not belong // to this Type and so, according to the spec // is allowed to only appear on the left hand of // the += and -= operators // // Note that target will not appear as an EventExpr // in the case it is being referenced within the same type container; // it will appear as a FieldExpr in that case. // if (!(source is BinaryDelegate)) { error70 (ei, loc); return null; } } } if (source is New && target_type.IsValueType && (target.eclass != ExprClass.IndexerAccess) && (target.eclass != ExprClass.PropertyAccess)){ New n = (New) source; if (n.SetValueTypeVariable (target)) return n; else return null; } if (!(target is IAssignMethod) && (target.eclass != ExprClass.EventAccess)) { Report.Error (131, loc, "Left hand of an assignment must be a variable, " + "a property or an indexer"); return null; } if ((source.eclass == ExprClass.Type) && (source is TypeExpr)) { source.Error_UnexpectedKind ("variable or value", loc); return null; } else if ((RootContext.Version == LanguageVersion.ISO_1) && (source is MethodGroupExpr)){ ((MethodGroupExpr) source).ReportUsageError (); return null; } if (target_type == source_type) return this; // // If this assignemnt/operator was part of a compound binary // operator, then we allow an explicit conversion, as detailed // in the spec. // if (this is CompoundAssign){ CompoundAssign a = (CompoundAssign) this; Binary b = source as Binary; if (b != null){ // // 1. if the source is explicitly convertible to the // target_type // source = Convert.ExplicitConversion (ec, source, target_type, loc); if (source == null){ Convert.Error_CannotImplicitConversion (loc, source_type, target_type); return null; } // // 2. and the original right side is implicitly convertible to // the type of target // if (Convert.ImplicitStandardConversionExists (a.original_source, target_type)) return this; // // In the spec 2.4 they added: or if type of the target is int // and the operator is a shift operator... // if (source_type == TypeManager.int32_type && (b.Oper == Binary.Operator.LeftShift || b.Oper == Binary.Operator.RightShift)) return this; Convert.Error_CannotImplicitConversion (loc, a.original_source.Type, target_type); return null; } } source = Convert.ImplicitConversionRequired (ec, source, target_type, loc); if (source == null) return null; // If we're an embedded assignment, we need to create a new temporary variable // for the converted value. Our parent will use this new variable as its source. // The same applies when we have an embedded assignment - in this case, we need // to convert our embedded assignment's temporary local variable to the correct // type and store it in a new temporary local. if (is_embedded || embedded != null) { type = target_type; temp = new LocalTemporary (ec, type); must_free_temp = true; } return this; } Expression EmitEmbedded (EmitContext ec) { // Emit an embedded assignment. if (real_temp != null) { // If we're the innermost assignment, `real_source' is the right-hand // expression which gets assigned to all the variables left of it. // Emit this expression and store its result in real_temp. real_source.Emit (ec); real_temp.Store (ec); } if (embedded != null) embedded.EmitEmbedded (ec); // This happens when we've done a type conversion, in this case source will be // the expression which does the type conversion from real_temp. // So emit it and store the result in temp; this is the var which will be read // by our parent. if (temp != real_temp) { source.Emit (ec); temp.Store (ec); } Expression temp_source = (temp != null) ? temp : source; ((IAssignMethod) target).EmitAssign (ec, temp_source, false, false); return temp_source; } void ReleaseEmbedded (EmitContext ec) { if (embedded != null) embedded.ReleaseEmbedded (ec); if (real_temp != null) real_temp.Release (ec); if (must_free_temp) temp.Release (ec); } void Emit (EmitContext ec, bool is_statement) { if (target is EventExpr) { ((EventExpr) target).EmitAddOrRemove (ec, source); return; } IAssignMethod am = (IAssignMethod) target; Expression temp_source; if (embedded != null) { temp_source = embedded.EmitEmbedded (ec); if (temp != null) { source.Emit (ec); temp.Store (ec); temp_source = temp; } } else temp_source = source; am.EmitAssign (ec, temp_source, !is_statement, this is CompoundAssign); if (embedded != null) { if (temp != null) temp.Release (ec); embedded.ReleaseEmbedded (ec); } } public override void Emit (EmitContext ec) { Emit (ec, false); } public override void EmitStatement (EmitContext ec) { Emit (ec, true); } } // // This class is used for compound assignments. // class CompoundAssign : Assign { Binary.Operator op; public Expression original_source; public CompoundAssign (Binary.Operator op, Expression target, Expression source, Location l) : base (target, source, l) { original_source = source; this.op = op; } protected CompoundAssign (CompoundAssign embedded, Location l) : this (embedded.op, embedded.target, embedded.source, l) { this.is_embedded = true; } protected override Assign GetEmbeddedAssign (Location loc) { return new CompoundAssign (this, loc); } public Expression ResolveSource (EmitContext ec) { return original_source.Resolve (ec); } public override Expression DoResolve (EmitContext ec) { original_source = original_source.Resolve (ec); if (original_source == null) return null; target = target.Resolve (ec); if (target == null) return null; // // Only now we can decouple the original source/target // into a tree, to guarantee that we do not have side // effects. // source = new Binary (op, target, original_source, loc); return base.DoResolve (ec); } } } --- NEW FILE: attribute.cs --- // // attribute.cs: Attribute Handler // // Author: Ravi Pratap (ra...@xi...) // Marek Safar (mar...@se...) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // // using System; using System.Diagnostics; using System.Collections; using System.Collections.Specialized; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; [...1409 lines suppressed...] if (excluded != null) return excluded == TRUE ? true : false; ConditionalAttribute[] attrs = mb.GetCustomAttributes (TypeManager.conditional_attribute_type, true) as ConditionalAttribute[]; if (attrs.Length == 0) { analyzed_method_excluded.Add (mb, FALSE); return false; } foreach (ConditionalAttribute a in attrs) { if (RootContext.AllDefines.Contains (a.ConditionString)) { analyzed_method_excluded.Add (mb, FALSE); return false; } } analyzed_method_excluded.Add (mb, TRUE); return true; } } } --- NEW FILE: cfold.cs --- // // cfold.cs: Constant Folding // // Author: // Miguel de Icaza (mi...@xi...) // // (C) 2002, 2003 Ximian, Inc. // using System; namespace Mono.CSharp { public class ConstantFold { // // Performs the numeric promotions on the left and right expresions // and desposits the results on `lc' and `rc'. // [...1155 lines suppressed...] ((ULongConstant) right).Value; else if (left is LongConstant) bool_res = ((LongConstant) left).Value <= ((LongConstant) right).Value; else if (left is UIntConstant) bool_res = ((UIntConstant) left).Value <= ((UIntConstant) right).Value; else if (left is IntConstant) bool_res = ((IntConstant) left).Value <= ((IntConstant) right).Value; else return null; return new BoolConstant (bool_res); } return null; } } } --- NEW FILE: ChangeLog --- 2004-10-04 Miguel de Icaza <mi...@xi...> * ecore.cs (Expression.Constantity): Add support for turning null into a constant. * const.cs (Const.Define): Allow constants to be reference types as long as the value is Null. 2004-10-04 Juraj Skripsky <js...@ho...> * namespace.cs (NamespaceEntry.Using): No matter which warning level is set, check if this namespace name has already been added. 2004-10-03 Ben Maurer <bm...@xi...> * expression.cs: reftype [!=]= null should always use br[true,false]. # 67410 2004-10-03 Marek Safar <mar...@se...> [...16743 lines suppressed...] 2001-04-27 Miguel de Icaza <mi...@xi...> * System.CodeDOM/CodeBinaryOperatorExpression.cs: Rearrange enum to match the values in System.CodeDOM. Divid renamed to Divide. * System.CodeDOM/CodeForLoopStatement.cs: Always have valid statements. (Statements.set): remove. * System.CodeDOM/CodeCatchClause.cs: always have a valid statements. * System.CodeDOM/CodeIfStatement.cs: trueStatements and falseStatements always have valid values. * cs-parser.jay: Use System.CodeDOM now. --- NEW FILE: class.cs --- // // class.cs: Class and Struct handlers // // Authors: Miguel de Icaza (mi...@gn...) // Martin Baulig (ma...@gn...) // Marek Safar (mar...@se...) // // Licensed under the terms of the GNU GPL // // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com) // // // 2002-10-11 Miguel de Icaza <mi...@xi...> // // * class.cs: Following the comment from 2002-09-26 to AddMethod, I // have fixed a remaining problem: not every AddXXXX was adding a // fully qualified name. // // Now everyone registers a fully qualified name in the DeclSpace as [...7071 lines suppressed...] Type [] args; if (mi != null) args = TypeManager.GetArgumentTypes (mi); else args = TypeManager.GetArgumentTypes (pi); Type [] sigp = sig.Parameters; if (args.Length != sigp.Length) return false; for (int i = args.Length; i > 0; ){ i--; if (args [i] != sigp [i]) return false; } return true; } } } --- NEW FILE: codegen.cs --- // // codegen.cs: The code generator // // Author: // Miguel de Icaza (mi...@xi...) // // (C) 2001 Ximian, Inc. // using System; using System.IO; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; using System.Security.Cryptography; using Mono.Security.Cryptography; [...1055 lines suppressed...] ApplyAttributeBuilder (null, new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0])); } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder) { if (a != null && a.Type == TypeManager.cls_compliant_attribute_type) { Report.Warning (3012, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); return; } Builder.SetCustomAttribute (customBuilder); } public override string[] ValidAttributeTargets { get { return attribute_targets; } } } } --- NEW FILE: compiler.doc --- Compiler operation The compiler has a number of phases: * Parsing. Initially the compiler parses all the source files and keeps a parsed representation in memory. Very syntax error checking is performed at this point. The compiler stores the information in classes whose names represent the language construct, for example, the "if" construct is stored in an `If' class. A class is stored in a `Class'. * The TypeManager The TypeManager loads all the assemblies that were referenced by the programmer. The CLR type system is used as our repository for types defined as well. So the same interface that is used to query the types, properties and flags about system types is the same interface that we use for our types. As we work our way through the code generation and semantic analysis, new types are entered into the Type system through the use of System.Reflection.Emit. The TypeManager will lookup types on both the user defined types and on the system defined ones. So special care has to be used. The order in which we proceeed from here is important. * Base class resolution and type definition. Once the parsing has happened, the compiler resolves the inheritance tree for interfaces. This is done recursively and we catch recursive interface definitions here. After this is done, we continue on with classes. Classes have can have an optional "parent" inherit from or the implicit System.Object class (for normal builds, builds with /nostdlib will allow you to compile class System.Object with no parent). At this point we do some error checking and verify that the inherits/implements section of a class is correct (since we have previously built the interface inheritance). By the time we are done, all classes, structs and interfaces have been created using System.Reflection.Emit and registered with the Type Manager. This allows us to define fields and resolve argument names for methods, properties, indexers and events. * Field generation Fields are generated next, we go through all the type containers (classes and structs) and enter the fields into their types. * Method, Properties, Indexers and events definitions Now all the methods, constructors, properties, indexers and events are entered. They are only `defined' using System.Reflection.Emit. No code generation will happen until everything has been entered into System.Reflection.Emit. This is important because to actually generate code we need to know everything about the environment in which the code is being generated. * Code Generation At this point all the definitions have been entered into the type manager through System.Reflection.Emit. We can now use System.Reflection to query all the information about the types. Your normal semantic analysis and code generation phase lives here. * Statements Most of the statements are handled in the codegen.cs file. * Expressions * Error reporting We should try to use the `Report.Error' and `Report.Warning' classes which are part of the RootContext (there is even a property to access it). Error reporting should try to use the same codes that the Microsoft compiler uses (if only so we can track which errors we handle and which ones we dont). If there is an error which is specific to MSC, use negative numbers, and register the number in mcs/errors/errors.txt Try to write a test case for any error that you run into the code of the compiler if there is none already. Put your test case in a file called csNNNN.cs in the mcs/errors directory, and have the first two lines be: // csNNNN.cs: This is the description. // Line: XXX Where `XXX' is the line where the error ocurrs. We will later use this as a regression test suite for catching errors in the compiler. --- NEW FILE: compiler.sln --- Microsoft Visual Studio Solution File, Format Version 8.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "compiler", "compiler.csproj", "{896D1461-B76B-41C0-ABE6-ACA2BB4F7B5A}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {896D1461-B76B-41C0-ABE6-ACA2BB4F7B5A}.Debug.ActiveCfg = Debug|.NET {896D1461-B76B-41C0-ABE6-ACA2BB4F7B5A}.Debug.Build.0 = Debug|.NET {896D1461-B76B-41C0-ABE6-ACA2BB4F7B5A}.Release.ActiveCfg = Release|.NET {896D1461-B76B-41C0-ABE6-ACA2BB4F7B5A}.Release.Build.0 = Release|.NET EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal --- NEW FILE: const.cs --- // // const.cs: Constant declarations. // // Author: // Miguel de Icaza (mi...@xi...) // // (C) 2001 Ximian, Inc. // // // // This is needed because the following situation arises: // // The FieldBuilder is declared with the real type for an enumeration // // When we attempt to set the value for the constant, the FieldBuilder.SetConstant // function aborts because it requires its argument to be of the same type // namespace Mono.CSharp { using System; using System.Reflection; using System.Reflection.Emit; using System.Collections; public class Const : FieldMember { public Expression Expr; EmitContext const_ec; bool resolved = false; object ConstantValue = null; bool in_transit = false; public const int AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; public Const (TypeContainer parent, Expression constant_type, string name, Expression expr, int mod_flags, Attributes attrs, Location loc) : base (parent, constant_type, mod_flags, AllowedModifiers, new MemberName (name), null, attrs, loc) { Expr = expr; ModFlags |= Modifiers.STATIC; } public FieldAttributes FieldAttr { get { return FieldAttributes.Literal | FieldAttributes.Static | Modifiers.FieldAttr (ModFlags) ; } } #if DEBUG void dump_tree (Type t) { Console.WriteLine ("Dumping hierarchy"); while (t != null){ Console.WriteLine (" " + t.FullName + " " + (t.GetType ().IsEnum ? "yes" : "no")); t = t.BaseType; } } #endif /// <summary> /// Defines the constant in the @parent /// </summary> public override bool Define () { if (!base.Define ()) return false; const_ec = new EmitContext (Parent, Location, null, MemberType, ModFlags); Type ttype = MemberType; while (ttype.IsArray) ttype = TypeManager.GetElementType (ttype); if (!TypeManager.IsBuiltinType (ttype) && (!ttype.IsSubclassOf (TypeManager.enum_type)) && !(Expr is NullLiteral)) { Report.Error ( -3, Location, "Constant type is not valid (only system types are allowed)"); return false; } FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, FieldAttr); TypeManager.RegisterConstant (FieldBuilder, this); return true; } // // Changes the type of the constant expression `expr' to the Type `type' // Returns null on failure. // public static Constant ChangeType (Location loc, Constant expr, Type type) { if (type == TypeManager.object_type) return expr; bool fail; // from the null type to any reference-type. if (expr is NullLiteral && !type.IsValueType && !TypeManager.IsEnumType (type)) return NullLiteral.Null; if (!Convert.ImplicitStandardConversionExists (expr, type)){ Convert.Error_CannotImplicitConversion (loc, expr.Type, type); return null; } object constant_value = TypeManager.ChangeType (expr.GetValue (), type, out fail); if (fail){ Convert.Error_CannotImplicitConversion (loc, expr.Type, type); // // We should always catch the error before this is ever // reached, by calling Convert.ImplicitStandardConversionExists // throw new Exception ( String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type)); } Constant retval; if (type == TypeManager.int32_type) retval = new IntConstant ((int) constant_value); else if (type == TypeManager.uint32_type) retval = new UIntConstant ((uint) constant_value); else if (type == TypeManager.int64_type) retval = new LongConstant ((long) constant_value); else if (type == TypeManager.uint64_type) retval = new ULongConstant ((ulong) constant_value); else if (type == TypeManager.float_type) retval = new FloatConstant ((float) constant_value); else if (type == TypeManager.double_type) retval = new DoubleConstant ((double) constant_value); else if (type == TypeManager.string_type) retval = new StringConstant ((string) constant_value); else if (type == TypeManager.short_type) retval = new ShortConstant ((short) constant_value); else if (type == TypeManager.ushort_type) retval = new UShortConstant ((ushort) constant_value); else if (type == TypeManager.sbyte_type) retval = new SByteConstant ((sbyte) constant_value); else if (type == TypeManager.byte_type) retval = new ByteConstant ((byte) constant_value); else if (type == TypeManager.char_type) retval = new CharConstant ((char) constant_value); else if (type == TypeManager.bool_type) retval = new BoolConstant ((bool) constant_value); else throw new Exception ("LookupConstantValue: Unhandled constant type: " + type); return retval; } /// <summary> /// Looks up the value of a constant field. Defines it if it hasn't /// already been. Similar to LookupEnumValue in spirit. /// </summary> public bool LookupConstantValue (out object value) { if (resolved) { value = ConstantValue; return true; } if (in_transit) { Report.Error (110, Location, "The evaluation of the constant value for `" + Name + "' involves a circular definition."); value = null; return false; } in_transit = true; int errors = Report.Errors; // // We might have cleared Expr ourselves in a recursive definition // if (Expr == null){ value = null; return false; } Expr = Expr.Resolve (const_ec); in_transit = false; if (Expr == null) { if (errors == Report.Errors) Report.Error (150, Location, "A constant value is expected"); value = null; return false; } Expression real_expr = Expr; Constant ce = Expr as Constant; if (ce == null){ UnCheckedExpr un_expr = Expr as UnCheckedExpr; CheckedExpr ch_expr = Expr as CheckedExpr; EmptyCast ec_expr = Expr as EmptyCast; if ((un_expr != null) && (un_expr.Expr is Constant)) Expr = un_expr.Expr; else if ((ch_expr != null) && (ch_expr.Expr is Constant)) Expr = ch_expr.Expr; else if ((ec_expr != null) && (ec_expr.Child is Constant)) Expr = ec_expr.Child; else if (Expr is ArrayCreation){ Report.Error (133, Location, "Arrays can not be constant"); } else { if (errors == Report.Errors) Report.Error (150, Location, "A constant value is expected"); value = null; return false; } ce = Expr as Constant; } if (MemberType != real_expr.Type) { ce = ChangeType (Location, ce, MemberType); if (ce == null){ value = null; return false; } Expr = ce; } ConstantValue = ce.GetValue (); if (MemberType.IsEnum){ // // This sadly does not work for our user-defined enumerations types ;-( // try { ConstantValue = System.Enum.ToObject ( MemberType, ConstantValue); } catch (ArgumentException){ Report.Error ( -16, Location, ".NET SDK 1.0 does not permit to create the constant "+ " field from a user-defined enumeration"); } } FieldBuilder.SetConstant (ConstantValue); if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue)) throw new Exception ("Cannot register const value"); value = ConstantValue; resolved = true; return true; } /// <summary> /// Emits the field value by evaluating the expression /// </summary> public override void Emit () { object value; LookupConstantValue (out value); if (OptAttributes != null) { OptAttributes.Emit (const_ec, this); } base.Emit (); } } } --- NEW FILE: constant.cs --- // // constant.cs: Constants. // // Author: // Miguel de Icaza (mi...@xi...) // // (C) 2001 Ximian, Inc. // // namespace Mono.CSharp { using System; using System.Reflection.Emit; /// <summary> /// Base class for constants and literals. /// </summary> public abstract class Constant : Expression { [...1074 lines suppressed...] } public override void Emit (EmitContext ec) { if (Value == null) ec.ig.Emit (OpCodes.Ldnull); else ec.ig.Emit (OpCodes.Ldstr, Value); } public override bool IsNegative { get { return false; } } } } --- NEW FILE: convert.cs --- // // conversion.cs: various routines for implementing conversions. // // Authors: // Miguel de Icaza (mi...@xi...) // Ravi Pratap (ra...@xi...) // // (C) 2001, 2002, 2003 Ximian, Inc. // namespace Mono.CSharp { using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; // // A container class for all the conversion operations [...1735 lines suppressed...] Type target_type, Location l) { Expression ne = ImplicitConversionStandard (ec, expr, target_type, l); if (ne != null) return ne; ne = ExplicitNumericConversion (ec, expr, target_type, l); if (ne != null) return ne; ne = ExplicitReferenceConversion (expr, target_type); if (ne != null) return ne; Error_CannotConvertType (l, expr.Type, target_type); return null; } } } --- NEW FILE: cs-parser.jay --- %{ // // cs-parser.jay: The Parser for the C# compiler // // Authors: Miguel de Icaza (mi...@gn...) // Ravi Pratap (ra...@xi...) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // // TODO: // (1) Figure out why error productions dont work. `type-declaration' is a // great spot to put an `error' because you can reproduce it with this input: // "public X { }" // // Possible optimization: // Run memory profiler with parsing only, and consider dropping // arraylists where not needed. Some pieces can use linked lists. [...4397 lines suppressed...] Console.WriteLine (e); } } void CheckToken (int error, int yyToken, string msg) { if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD){ Report.Error (error, lexer.Location, String.Format ("{0}: `{1}' is a keyword", msg, yyNames [yyToken].ToLower ())); return; } Report.Error (error, lexer.Location, msg); } void CheckIdentifierToken (int yyToken) { CheckToken (1041, yyToken, "Identifier expected"); } /* end end end */ } --- NEW FILE: cs-tokenizer.cs --- // // cs-tokenizer.cs: The Tokenizer for the C# compiler // This also implements the preprocessor // // Author: Miguel de Icaza (mi...@gn...) // // Licensed under the terms of the GNU GPL // // (C) 2001, 2002 Ximian, Inc (http://www.ximian.com) // /* * TODO: * Make sure we accept the proper Unicode ranges, per the spec. * Report error 1032 */ using System; using System.Text; [...2013 lines suppressed...] return Token.ERROR; } return Token.EOF; } public void cleanup () { if (ifstack != null && ifstack.Count >= 1) { int state = (int) ifstack.Pop (); if ((state & REGION) != 0) Report.Error (1038, "#endregion directive expected"); else Report.Error (1027, "#endif directive expected"); } } } } --- NEW FILE: decl.cs --- // // decl.cs: Declaration base class for structs, classes, enums and interfaces. // // Author: Miguel de Icaza (mi...@gn...) // Marek Safar (mar...@se...) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // // TODO: Move the method verification stuff from the class.cs and interface.cs here // using System; using System.Collections; using System.Globalization; using System.Reflection.Emit; using System.Reflection; [...1943 lines suppressed...] if ((entry.EntryType & tested_type) != tested_type) continue; MethodBase method_to_compare = (MethodBase)entry.Member; if (AttributeTester.AreOverloadedMethodParamsClsCompliant (method.ParameterTypes, TypeManager.GetArgumentTypes (method_to_compare))) continue; IMethodData md = TypeManager.GetMethod (method_to_compare); // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy. // However it is exactly what csc does. if (md != null && !md.IsClsCompliaceRequired (method.Parent)) continue; Report.SymbolRelatedToPreviousError (entry.Member); Report.Error (3006, method.Location, "Overloaded method '{0}' differing only in ref or out, or in array rank, is not CLS-compliant", method.GetSignatureForError ()); } } } } --- NEW FILE: delegate.cs --- // // delegate.cs: Delegate Handler // // Authors: // Ravi Pratap (ra...@xi...) // Miguel de Icaza (mi...@xi...) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // // using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Text; namespace Mono.CSharp { /// <summary> /// Holds Delegates /// </summary> public class Delegate : DeclSpace { public Expression ReturnType; public Parameters Parameters; public ConstructorBuilder ConstructorBuilder; public MethodBuilder InvokeBuilder; public MethodBuilder BeginInvokeBuilder; public MethodBuilder EndInvokeBuilder; Type [] param_types; Type ret_type; static string[] attribute_targets = new string [] { "type", "return" }; Expression instance_expr; MethodBase delegate_method; ReturnParameter return_attributes; const int AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.UNSAFE | Modifiers.PRIVATE; public Delegate (NamespaceEntry ns, TypeContainer parent, Expression type, int mod_flags, MemberName name, Parameters param_list, Attributes attrs, Location l) : base (ns, parent, name, attrs, l) { this.ReturnType = type; ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l); Parameters = param_list; } public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) { if (a.Target == AttributeTargets.ReturnValue) { if (return_attributes == null) return_attributes = new ReturnParameter (InvokeBuilder, Location); return_attributes.ApplyAttributeBuilder (a, cb); return; } base.ApplyAttributeBuilder (a, cb); } public override TypeBuilder DefineType () { if (TypeBuilder != null) return TypeBuilder; TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel) | TypeAttributes.Class | TypeAttributes.Sealed; if (IsTopLevel) { if (TypeManager.NamespaceClash (Name, Location)) return null; ModuleBuilder builder = CodeGen.Module.Builder; TypeBuilder = builder.DefineType ( Name, attr, TypeManager.multicast_delegate_type); } else { TypeBuilder builder = Parent.TypeBuilder; string name = Name.Substring (1 + Name.LastIndexOf ('.')); TypeBuilder = builder.DefineNestedType ( name, attr, TypeManager.multicast_delegate_type); } TypeManager.AddDelegateType (Name, TypeBuilder, this); return TypeBuilder; } public override bool DefineMembers (TypeContainer container) { return true; } public override bool Define () { MethodAttributes mattr; int i; EmitContext ec = new EmitContext (this, this, Location, null, null, ModFlags, false); // FIXME: POSSIBLY make this static, as it is always constant // Type [] const_arg_types = new Type [2]; const_arg_types [0] = TypeManager.object_type; const_arg_types [1] = TypeManager.intptr_type; mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; ConstructorBuilder = TypeBuilder.DefineConstructor (mattr, CallingConventions.Standard, const_arg_types); ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object"); ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method"); // // HACK because System.Reflection.Emit is lame // // // FIXME: POSSIBLY make these static, as they are always the same Parameter [] fixed_pars = new Parameter [2]; fixed_pars [0] = new Parameter (null, null, Parameter.Modifier.NONE, null); fixed_pars [1] = new Parameter (null, null, Parameter.Modifier.NONE, null); Parameters const_parameters = new Parameters (fixed_pars, null, Location); TypeManager.RegisterMethod ( ConstructorBuilder, new InternalParameters (const_arg_types, const_parameters), const_arg_types); ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); // // Here the various methods like Invoke, BeginInvoke etc are defined // // First, call the `out of band' special method for // defining recursively any types we need: if (!Parameters.ComputeAndDefineParameterTypes (this)) return false; param_types = Parameters.GetParameterInfo (this); if (param_types == null) return false; // // Invoke method // // Check accessibility foreach (Type partype in param_types){ if (!Parent.AsAccessible (partype, ModFlags)) { Report.Error (59, Location, "Inconsistent accessibility: parameter type `" + TypeManager.CSharpName (partype) + "` is less " + "accessible than delegate `" + Name + "'"); return false; } if (partype.IsPointer && !UnsafeOK (Parent)) return false; } ReturnType = ResolveTypeExpr (ReturnType, false, Location); if (ReturnType == null) return false; ret_type = ReturnType.Type; if (ret_type == null) return false; if (!Parent.AsAccessible (ret_type, ModFlags)) { Report.Error (58, Location, "Inconsistent accessibility: return type `" + TypeManager.CSharpName (ret_type) + "` is less " + "accessible than delegate `" + Name + "'"); return false; } if (ret_type.IsPointer && !UnsafeOK (Parent)) return false; // // We don't have to check any others because they are all // guaranteed to be accessible - they are standard types. // CallingConventions cc = Parameters.GetCallingConvention (); mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual; InvokeBuilder = TypeBuilder.DefineMethod ("Invoke", mattr, cc, ret_type, param_types); // // Define parameters, and count out/ref parameters // int out_params = 0; i = 0; if (Parameters.FixedParameters != null){ int top = Parameters.FixedParameters.Length; Parameter p; for (; i < top; i++) { p = Parameters.FixedParameters [i]; p.DefineParameter (ec, InvokeBuilder, null, i + 1, Location); if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0) out_params++; } } if (Parameters.ArrayParameter != null){ Parameter p = Parameters.ArrayParameter; p.DefineParameter (ec, InvokeBuilder, null, i + 1, Location); } InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); TypeManager.RegisterMethod (InvokeBuilder, new InternalParameters (Parent, Parameters), param_types); // // BeginInvoke // int params_num = param_types.Length; Type [] async_param_types = new Type [params_num + 2]; param_types.CopyTo (async_param_types, 0); async_param_types [params_num] = TypeManager.asynccallback_type; async_param_types [params_num + 1] = TypeManager.object_type; mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot; BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke", mattr, cc, TypeManager.iasyncresult_type, async_param_types); i = 0; if (Parameters.FixedParameters != null){ int top = Parameters.FixedParameters.Length; Parameter p; for (i = 0 ; i < top; i++) { p = Parameters.FixedParameters [i]; p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1, Location); } } if (Parameters.ArrayParameter != null){ Parameter p = Parameters.ArrayParameter; p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1, Location); i++; } BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback"); BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object"); BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); Parameter [] async_params = new Parameter [params_num + 2]; int n = 0; if (Parameters.FixedParameters != null){ Parameters.FixedParameters.CopyTo (async_params, 0); n = Parameters.FixedParameters.Length; } if (Parameters.ArrayParameter != null) async_params [n] = Parameters.ArrayParameter; async_params [params_num] = new Parameter ( TypeManager.system_asynccallback_expr, "callback", Parameter.Modifier.NONE, null); async_params [params_num + 1] = new Parameter ( TypeManager.system_object_expr, "object", Parameter.Modifier.NONE, null); Parameters async_parameters = new Parameters (async_params, null, Location); async_parameters.ComputeAndDefineParameterTypes (this); async_parameters.ComputeAndDefineParameterTypes (this); TypeManager.RegisterMethod (BeginInvokeBuilder, new InternalParameters (Parent, async_parameters), async_param_types); // // EndInvoke is a bit more interesting, all the parameters labeled as // out or ref have to be duplicated here. // Type [] end_param_types = new Type [out_params + 1]; Parameter [] end_params = new Parameter [out_params + 1]; int param = 0; if (out_params > 0){ int top = Parameters.FixedParameters.Length; for (i = 0; i < top; i++){ Parameter p = Parameters.FixedParameters [i]; if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0) continue; end_param_types [param] = param_types [i]; end_params [param] = p; param++; } } end_param_types [out_params] = TypeManager.iasyncresult_type; end_params [out_params] = new Parameter (TypeManager.system_iasyncresult_expr, "result", Parameter.Modifier.NONE, null); // // Create method, define parameters, register parameters with type system // EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_param_types); EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime); // // EndInvoke: Label the parameters // EndInvokeBuilder.DefineParameter (out_params + 1, ParameterAttributes.None, "result"); for (i = 0; i < end_params.Length-1; i++){ EndInvokeBuilder.DefineParameter (i + 1, end_params [i].Attributes, end_params [i].Name); } Parameters end_parameters = new Parameters (end_params, null, Location); end_parameters.ComputeAndDefineParameterTypes (this); TypeManager.RegisterMethod ( EndInvokeBuilder, new InternalParameters (Parent, end_parameters), end_param_types); return true; } public override void Emit () { if (OptAttributes != null) { EmitContext ec = new EmitContext ( Parent, this, Location, null, null, ModFlags, false); Parameters.LabelParameters (ec, InvokeBuilder, Location); OptAttributes.Emit (ec, this); } base.Emit (); } public override string[] ValidAttributeTargets { get { return attribute_targets; } } //TODO: duplicate protected override bool VerifyClsCompliance (DeclSpace ds) { if (!base.VerifyClsCompliance (ds)) { return false; } AttributeTester.AreParametersCompliant (Parameters.FixedParameters, Location); if (!AttributeTester.IsClsCompliant (ReturnType.Type)) { Report.Error (3002, Location, "Return type of '{0}' is not CLS-compliant", GetSignatureForError ()); } return true; } /// <summary> /// Verifies whether the method in question is compatible with the delegate /// Returns the method itself if okay and null if not. /// </summary> public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb, Location loc) { ParameterData pd = Invocation.GetParameterData (mb); int pd_count = pd.Count; Expression ml = Expression.MemberLookup ( ec, delegate_type, "Invoke", loc); if (!(ml is MethodGroupExpr)) { Report.Error (-100, loc, "Internal error: could not find Invoke method!"); return null; } MethodBase invoke_mb = ((MethodGroupExpr) ml).Methods [0]; ParameterData invoke_pd = Invocation.GetParameterData (invoke_mb); if (invoke_pd.Count != pd_count) return null; for (int i = pd_count; i > 0; ) { i--; if (invoke_pd.ParameterType (i) == pd.ParameterType (i) && invoke_pd.ParameterModifier (i) == pd.ParameterModifier (i)) continue; else { return null; } } if (((MethodInfo) invoke_mb).ReturnType == ((MethodInfo) mb).ReturnType) return mb; else return null; } // <summary> // Verifies whether the invocation arguments are compatible with the // delegate's target method // </summary> public static bool VerifyApplicability (EmitContext ec, Type delegate_type, ArrayList args, Location loc) { int arg_count; if (args == null) arg_count = 0; else arg_count = args.Count; Expression ml = Expression.MemberLookup ( ec, delegate_type, "Invoke", loc); if (!(ml is MethodGroupExpr)) { Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type); return false; } MethodBase mb = ((MethodGroupExpr) ml).Methods [0]; ParameterData pd = Invocation.GetParameterData (mb); int pd_count = pd.Count; bool params_method = (pd_count != 0) && (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS); if (!params_method && pd_count != arg_count) { Report.Error (1593, loc, "Delegate '" + delegate_type.ToString () + "' does not take '" + arg_count + "' arguments"); return false; } // // Consider the case: // delegate void FOO(param object[] args); // FOO f = new FOO(...); // f(new object[] {1, 2, 3}); // // This should be treated like f(1,2,3). This is done by ignoring the // 'param' modifier for that invocation. If that fails, then the // 'param' modifier is considered. // // One issue is that 'VerifyArgumentsCompat' modifies the elements of // the 'args' array. However, the modifications appear idempotent. // Normal 'Invocation's also have the same behaviour, implicitly. // bool ans = false; if (arg_count == pd_count) ans = Invocation.VerifyArgumentsCompat ( ec, args, arg_count, mb, false, delegate_type, false, loc); if (!ans && params_method) ans = Invocation.VerifyArgumentsCompat ( ec, args, arg_count, mb, true, delegate_type, false, loc); return ans; } /// <summary> /// Verifies whether the delegate in question is compatible with this one in /// order to determine if instantiation from the same is possible. /// </summary> public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Type probe_type, Location loc) { Expression ml = Expression.MemberLookup ( ec, delegate_type, "Invoke", loc); if (!(ml is MethodGroupExpr)) { Report.Error (-100, loc, "Internal error: could not find Invoke method!"); return false; } MethodBase mb = ((MethodGroupExpr) ml).Methods [0]; ParameterData pd = Invocation.GetParameterData (mb); Expression probe_ml = Expression.MemberLookup ( ec, delegate_type, "Invoke", loc); if (!(probe_ml is MethodGroupExpr)) { Report.Error (-100, loc, "Internal error: could not find Invoke method!"); return false; } MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0]; ParameterData probe_pd = Invocation.GetParameterData (probe_mb); if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType) return false; if (pd.Count != probe_pd.Count) return false; for (int i = pd.Count; i > 0; ) { i--; if (pd.ParameterType (i) != probe_pd.ParameterType (i) || pd.ParameterModifier (i) != probe_pd.ParameterModifier (i)) return false; } return true; } public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd) { StringBuilder sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType)); sb.Append (" " + del_type.ToString ()); sb.Append (" ("); int length = pd.Count; for (int i = length; i > 0; ) { i--; sb.Append (pd.ParameterDesc (length - i - 1)); if (i != 0) sb.Append (", "); } sb.Append (")"); return sb.ToString (); } // Hack around System.Reflection as found everywhere else public override MemberList FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria) { ArrayList members = new ArrayList (); if ((mt & MemberTypes.Method) != 0) { if (ConstructorBuilder != null) if (filter (ConstructorBuilder, criteria)) members.Add (ConstructorBuilder); if (InvokeBuilder != null) if (filter (InvokeBuilder, criteria)) members.Add (InvokeBuilder); if (BeginInvokeBuilder != null) if (filter (BeginInvokeBuilder, criteria)) members.Add (BeginInvokeBuilder); if (EndInvokeBuilder != null) if (filter (EndInvokeBuilder, criteria)) members.Add (EndInvokeBuilder); } return new MemberList (members); } public override MemberCache MemberCache { get { return null; } } public Expression InstanceExpression { get { return instance_expr; } set { instance_expr = value; } } public MethodBase TargetMethod { get { return delegate_method; } set { delegate_method = value; } } public Type TargetReturnType { get { return ret_type; } } public Type [] ParameterTypes { get { return param_types; } } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Delegate; } } protected override void VerifyObsoleteAttribute() { CheckUsageOfObsoleteAttribute (ret_type); foreach (Type type in param_types) { CheckUsageOfObsoleteAttribute (type); } } } // // Base class for `NewDelegate' and `ImplicitDelegateCreation' // public abstract class DelegateCreation : Expression { protected MethodBase constructor_method; protected MethodBase delegate_method; protected MethodGroupExpr method_group; protected Expression delegate_instance_expression; public DelegateCreation () {} public static void Error_NoMatchingMethodForDelegate (EmitContext ec, MethodGroupExpr mg, Type type, Location loc) { string method_desc; if (mg.Methods.Length > 1) method_desc = mg.Methods [0].Name; else method_desc = Invocation.FullMethodDesc (mg.Methods [0]); Expression invoke_method = Expression.MemberLookup ( ec, type, "Invoke", MemberTypes.Method, Expression.AllBindingFlags, loc); MethodBase method = ((MethodGroupExpr) invoke_method).Methods [0]; ParameterData param = Invocation.GetParameterData (method); string delegate_desc = Delegate.FullDelegateDesc (type, method, param); Report.Error (1... [truncated message content] |