++2005-02-18 Marek Safar <marek.safar@seznam.cz>
++
++ * class.cs (EmitFieldInitializers): Don't emit field initializer
++ for default values when optimilization is on.
++
++ * constant.cs (Constant.IsDefaultValue): New property.
++
++ * driver.cs: Add /optimize handling.
++
++ * constant.cs,
++ * ecore.cs,
++ * literal.cs: Implement new IsDefaultValue property.
++
++ * rootcontext.cs (Optimize): New field, holds /optimize option.
++
++2005-02-18 Raja R Harinath <rharinath@novell.com>
++
++ Fix crasher in re-opened #72347.
++ * namespace.cs (Namespace.Lookup): Return null if
++ DeclSpace.DefineType returns null.
++
++ Fix #72678.
++ * expression.cs (Argument.Resolve): Handle a case of CS0120 here.
++
++2005-02-18 Raja R Harinath <rharinath@novell.com>
++
++ Fix remainder of #63202. Change semantics of DoResolveLValue: it
++ now returns null if it cannot resolve to an lvalue.
++ * ecore.cs (Expression.DoResolveLValue): Return 'null' by default.
++ (Expression.ResolveLValue): Emit CS0131 error if DoResolveLValue
++ returned null. Remove check for SimpleName.
++ (EventExpr.DoResolveLValue): New.
++ * iterators.cs (Iterator.FieldExpression.DoResolveLValue): New.
++ * expression.cs (Argument.Error_LValueRequired): New. Move CS1510
++ error from ...
++ (Argument.Resolve): ... here. Use it. Use DoResolveLValue to
++ avoid CS0131 error.
++ (Unary.ResolveOperator): Move CS0211 check ...
++ (Unary.DoResolve): ... here. Use DoResolveLValue to avoid
++ CS0131 error.
++ (Unary.DoResolveLValue): Simplify.
++ (AddressOf.DoResolveLValue): New.
++ (ArrayAccess.DoResolveLValue): New.
++
++2005-02-16 Marek Safar <marek.safar@seznam.cz>
++
++ * attribute.cs (Attribute.Resolve): Add arguments casting for
++ when types doesn't match ctor arguments.
++
++2005-02-16 Raja R Harinath <rharinath@novell.com>
++
++ Fix parts of #63202.
++ * expression.cs (UnaryMutator.ResolveOperator): Remove redundant
++ lookup of operator in base type. Ensure that all checks happen
++ when the operator resolves to an "op_..." method.
++
+2005-02-15 Raja R Harinath <rharinath@novell.com>
+
+ Fix #71992.
+ * namespace.cs (NamespaceEntry.LookupNamespaceOrType): Add
+ 'ignore_cs0104' parameter. Pass it to ...
+ (NamespaceEntry.Lookup): ... this.
+ * decl.cs (DeclSpace.LookupType): Add 'ignore_cs0104' parameter.
+ * ecore.cs (SimpleName.ResolveAsTypeStep): Update.
+ (TypeLookupExpression.DoResolveAsTypeStep): Update.
+ * expression.cs (MemberAccess.IdenticalNameAndTypeName):
+ Update. Request that cs0104 errors be ignored.
+ (ComposedCast.ResolveAsTypeStep): Update.
+
+2005-02-14 Raja R Harinath <rharinath@novell.com>
+
+ Fix #59209.
+ * expression.cs (Invocation.BetterFunction): Remove support for
+ comparing virtual functions and their overrides.
+ (Invocation.IsOverride): New.
+ (Invocation.OverloadResolve): Don't consider 'override' functions
+ during candidate selection. Store them in a lookaside list.
+ If the selected method is a 'virtual' function, use the list to
+ find any overrides that are closer to the LHS type.
+
+2005-02-14 Marek Safar <marek.safar@seznam.cz>
+
+ * expression.cs (New.DoResolve): Add complex core type reduction.
+ (New.Constantify): Converts complex core type syntax like 'new int ()'
+ to simple constant.
+
+2005-02-14 Raja R Harinath <rharinath@novell.com>
+
+ * decl.cs (EntryType.EntryType): New constructor to create an
+ updated copy of a cache entry.
+ (MemberCache.AddMethods): Use it.
+ (MemberCache.ClearDeclaredOnly): Remove.
+ (MemberCache.MemberCache): Update.
+
+2005-02-11 Miguel de Icaza <miguel@novell.com>
+
+ * codegen.cs (EmitContext): Introduce the `MethodIsStatic'
+ variable. This one is represents the actual low-level declaration
+ of the method, as opposed to the semantic level `IsStatic'.
+
+ An anonymous method which is hosted into a static method might be
+ actually an instance method. IsStatic would reflect the
+ container, while MethodIsStatic represents the actual code
+ generated.
+
+ * expression.cs (ParameterReference): Use the new MethodIsStatic
+ instead of IsStatic.
+
+ * anonymous.cs (AnonymousMethod.Compatible): Pass the
+ Modifiers.STATIC to the Anonymous' Method EmitContext if static is
+ set on the current EmitContext.
+
+ * expression.cs (Cast): Overload DoResolveLValue so we can pass
+ resolve our casted expression as an LValue. This triggers the
+ proper LValue processing that is later required by Assign.
+
+ This fixes 72347.
+
+ * cs-tokenizer.cs (pp_and): recurse on pp_and, fixes #61903.
+
+2005-02-11 Marek Safar <marek.safar@seznam.cz>
+
+ C# 2.0 Fixed buffer implementation
+
+ * anonymous.cs: Update after RegisterHelperClass renaming.
+
+ * attribute.cs (AttributeTester.fixed_buffer_cache):
+ Cache of external fixed buffers.
+ (AttributeTester.GetFixedBuffer): Returns IFixedBuffer
+ implementation if field is fixed buffer else null.
+
+ * class.cs
+ (TypeContainer.AddField): Accept FieldMember instead of Field.
+ (FieldBase.IsFieldClsCompliant): Extracted code from
+ VerifyClsCompliance descendant customization.
+ (FixedField): New class handles fixed buffer fields.
+ (FixedFieldExternal): Keeps information about imported fixed
+ buffer.
+ (IFixedField): Make access to internal or external fixed buffer
+ same.
+
+ * cs-parser.jay: Add fixed buffer parsing.
+
+ * ecore.cs (FieldExpr.Emit): Add special emit case for fixed
+ buffer.
+
+ * expression.cs (Indirection): Extended implementation to accept
+ fixed buffer field.
+ (PointerArithmetic.Emit): Get element from fixed buffer as well.
+ (ElementAccess.MakePointerAccess): Get type as parameter.
+ (DoResolve): Add fixed buffer field expression conversion.
+ (DoResolveLValue): Ditto.
+ (FixedBufferPtr): New class. Moved most of original ArrayPtr.
+ (ArrayPtr): Derives from FixedBufferPtr.
+ (ArrayPtr.Emit): Add extra emit for array elements.
+
+ * flowanalysis.cs.cs (StructInfo): Use FieldMember.
+
+ * rootcontext.cs (CloseTypes): Emit CompilerGenerated attribute
+ for compiler generated types.
+ (RegisterCompilerGeneratedType): Renamed from RegisterHelperClass.
+
+ * statement.cs (Fixed): Refactored to be easier add fixed buffer
+ and consume less memory.
+ (Fixed.Resolve): Add fixed buffer case.
+
+ * typemanager.cs (compiler_generated_attr_ctor,
+ fixed_buffer_attr_ctor): Add new 2.0 compiler attributes.
+ (HasElementType): Add our own implementation to work on every
+ runtime.
+
+2005-02-11 Miguel de Icaza <miguel@novell.com>
+
+ * anonymous.cs (CaptureContext): Track whether `this' has been
+ referenced.
+
+ * expression.cs (This.ResolveBase): Call CaptureThis. Before we
+ only captured `this' if it was implicitly done (instance
+ methods/variables were used).
+
+ * codegen.cs (EmitContext.CaptureThis): New method to flag that
+ `this' must be captured.
+
+2005-01-30 Miguel de Icaza <miguel@novell.com>
+
+ * anonymous.cs (CreateMethodHost): If there Scope.ScopeTypeBuilder
+ is null it means that there has been no need to capture anything,
+ so we just create a sibling.
+
+ Renamed `EmitHelperClasses' to `EmitAnonymousHelperClasses'
+
+ Just a partial fix. The other half is fairly elusive.
+
+2005-02-10 Raja R Harinath <rharinath@novell.com>
+
+ Fix #52586, cs0121-4.cs.
+ * decl.cs (MemberCache.DeepCopy): Rename from SetupCache. Take
+ and return a hashtable.
+ (MemberCache.ClearDeclaredOnly): New.
+ (MemberCache.MemberCache): Update to change. Make a deep copy of
+ the method_hash of a base type too.
+ (MemberCache.AddMethods): Adapt to having a deep copy of the base
+ type methods. Overwrite entries with the same MethodHandle so
+ that the ReflectedType is correct. The process leaves in base
+ virtual functions and their overrides as distinct entries.
+ (CacheEntry): Now a class instead of a struct. It shouldn't alter
+ matters since it was boxed in a ArrayList before.
+ (CacheEntry.Member, CacheEntry.EntryType): Remove 'readonly'
+ modifier.
+ * expression.cs (Invocation.BetterFunction): Simplify. Handle the
+ case of a virtual function and its override (choose the overload
+ as better).
+ (Invocation.OverloadResolve): Avoid 'override' members during
+ 'applicable_type' calculation.
+
+2005-02-09 Raja R Harinath <rharinath@novell.com>
+
+ Combine two near-redundant caches.
+ * typemanager.cs (method_params): Rename from method_internal_params.
+ (TypeManager.GetParameterData): New. Replace
+ Invocation.GetParameterData.
+ (TypeManager.LookupParametersByBuilder): Remove.
+ * expression.cs (Invocation.method_parameter_cache): Remove.
+ (Invocation.GetParameterData): Remove.
+ Update to changes.
+ * anonymous.cs, attribute.cs, convert.cs, delegate.cs:
+ Update to changes.
+
+2005-02-08 Raja R Harinath <rharinath@novell.com>
+
+ Fix #72015.
+ * delegate.cs (Delegate.DefineType): When bootstrapping corlib, if
+ TypeManager.multicast_delegate_type is null, resolve it by looking
+ up "System.MulticastDelegate".
+ * rootcontext.cs (RootContext.ResolveCore): Simplify.
+
+2005-02-07 Abin Thomas (NOSIP) <projectmonokochi@rediffmail.com>
+ Anoob V.E (NOSIP) <projectmonokochi@rediffmail.com>
+ Harilal P.R (NOSIP) <projectmonokochi@rediffmail.com>
+
+ Fix cs0164.cs.
+ * statement.cs (LabeledStatement.Resolve): Don't set 'referenced'.
+ (LabeledStatement.AddReference): New. Set 'referenced'.
+ (Goto.Resolve): Use it.
+
+2005-02-05 John Luke <john.luke@gmail.com>
+
+ * driver.cs: remove duplicate -doc line in Usage ()
+
+2005-02-04 Raja R Harinath <rharinath@novell.com>
+
+ * location.cs (Location.AddFile): Fix CS2002 error report.
+
+2005-02-02 Martin Baulig <martin@ximian.com>
+
+ * delegate.cs (Delegate.DefineType): Report an internal error if
+ TypeManager.multicast_delegate_type is null. See bug #72015 for
+ details.
+
+2005-02-02 Raja R Harinath <rharinath@novell.com>
+
+ Fix a crasher in a variant of #31984.
+ * const.cs (Constant.CheckBase): New override that defers the
+ new-or-override check in case the base type hasn't been populated
+ yet.
+ (Constant.Define): Ensure the new-or-override check is performed.
+
+2005-02-01 Duncan Mak <duncan@ximian.com>
+
+ * const.cs (LookupConstantValue): Check that `ce' is not null
+ before calling GetValue ().
+
+2005-02-01 Raja R Harinath <rharinath@novell.com>
+
+ Fix test-334.cs (#69519).
+ * cs-parser.jay (using_alias_directive): Pass in an expression to
+ NamespaceEntry.UsingAlias.
+ (using_namespace_directive): Pass in an expression to
+ NamespaceEntry.Using.
+ (namespace_name): Don't flatten to a string.
+ * namespace.cs (NamespaceEntry.AliasEntry): Store an expression.
+ (NamespaceEntry.AliasEntry.Resolve): Lookup using
+ ResolveAsTypeStep.
+ (NamespaceEntry.UsingEntry): Likewise.
+ (NamespaceEntry.Using,NamespaceEntry.UsingAlias): Update to
+ changes.
+ (NamespaceEntry.LookupForUsing): Remove.
+ (NamespaceEntry.LookupNamespaceOrType): Add support for dotted
+ names.
+ (NamespaceEntry.Lookup): Remove support for dotted names.
+
+2005-02-01 Raja R Harinath <rharinath@novell.com>
+
+ * namespace.cs (NamespaceEntry.NamespaceEntry): Simplify, and
+ split into two.
+ (NamespaceEntry.ImplicitParent): Compute on demand.
+ (NamespaceEntry.Doppelganger): New implicit namespace-entry that
+ parallels the current.
+ (NamespaceEntry.LookupForUsing): Use it.
+ (NamespaceEntry.Lookup): If the current namespace-entry is
+ implicit, don't search aliases and using tables.
+
+2005-02-01 Raja R Harinath <rharinath@novell.com>
+
+ Fix #31984.
+ * class.cs (TypeContainer.DoDefineMembers): Don't initialize
+ BaseCache here.
+ (TypeContainer.BaseCache): Compute on demand.
+ (TypeContainer.FindMembers): Define constants and types if they're
+ not already created.
+ (FieldMember.Define): Move resetting of ec.InUnsafe before error
+ check.
+ * const.cs (Constant.Define): Make idempotent.
+
+2005-01-29 Miguel de Icaza <miguel@novell.com>
+
+ * pending.cs: Produce better code (no nops produced by using Ldarg
+ + value).
+
+ * pending.cs (PendingImplementation.DefineProxy): It was not `arg
+ i - 1' it should be arg + 1.
+
+ Fixes bug #71819.
+
+2005-01-28 Raja R Harinath <rharinath@novell.com>
+
+ * attribute.cs (Attribute.CheckAttributeType): Make private
+ non-virtual.
+ (Attribute.ResolveType): Make virtual.
+ (GlobalAttribute.ResolveType,GlobalAttribute.Resolve): Simplify
+ handling of RootContext.Tree.Types.
+
+2005-01-27 Raja R Harinath <rharinath@novell.com>
+
+ Update attribute-handling to use the SimpleName/MemberAccess
+ mechanisms.
+ * cs-parser.jay (attribute): Pass in an expression to the
+ constructors of Attribute and GlobalAttribute.
+ * attribute.cs (Attribute): Take an expression for the name.
+ (Attribute.ResolvePossibleAttributeTypes): New. Resolves the
+ passed in attribute name expression.
+ (Attribute.CheckAttributeType): Use it.
+ * ecore.cs (FullNamedExpression.ResolveAsTypeStep): New.
+ * expression.cs (MemberAccess.ResolveAsTypeStep): Move body to ...
+ (MemberAccess.ResolveNamespaceOrType): ... here. Add 'silent'
+ argument to prevent error messages if the lookup fails.
+
+2005-01-27 Marek Safar <marek.safar@seznam.cz>
+
+ * expression.cs (Indirection): Implemented IVariable interface
+ to support indirection in AddressOf operator.
+ (PointerArithmetic.Emit): Add optimalization for case where
+ result can be precomputed.
+
+2005-01-26 Martin Baulig <martin@ximian.com>
+
+ * class.cs (TypeContainer.AttributeTargets): Return the correct
+ AttributeTargets depending on our `Kind' instead of throwing an
+ exception; fixes #71632.
+
+2005-01-26 Marek Safar <marek.safar@seznam.cz>
+
+ Fix #71257
+ * expression.cs (MemberAccess.ResolveMemberAccess): Add CS0176 test for
+ constant members.
+
+2005-03-17 Martin Baulig <martin@ximian.com>
+
+ * anonymous.cs (AnonymousMethod.method_modifiers): Change default
+ from `Modifiers.INTERNAL' to `Modifiers.PRIVATE'. Fixes #73260.
+
+2005-03-17 Martin Baulig <martin@ximian.com>
+
+ * anonymous.cs (AnonymousMethod.EmitMethod): Changed return type
+ to bool so we can return an error condition.
+ (AnonymousDelegate.Emit): Check whether AnonymousMethod.EmitMethod()
+ returned an error.
+
+2005-03-17 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (TypeMananager.IsIEnumerable): New public method.
+
+ * convert.cs (Convert.ImplicitReferenceConversion(Exists)): Allow
+ converting from an array-type of T to `IEnumerable<T>'.
+
+2005-03-16 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.Unwrap): Implement IAssignMethod.
+ (Nullable.LiftedUnaryMutator): New public class.
+
+ * expression.cs (UnaryMutator.DoResolve): Added support for
+ Nullable Types.
+
+2005-03-14 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.NullCoalescingOperator): Implemented.
+
+2005-03-14 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.LiftedBinaryOperator): Added support for
+ the comparision operators `<', `>', `<=' and `>='.
+
+2005-03-13 Martin Baulig <martin@ximian.com>
+
+ * generic.cs
+ (Nullable.NullLiteral): Renamed to `Nullable.NullableLiteral' to
+ avoid confusion with the `NullLiteral'.
+ (Nullable.LiftedBinaryOperator): Correctly implement `==' and '!='.
+
+2005-03-13 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): For `==' and `!=', allow
+ comparing arbitrary types with the null literal.
+
+2005-03-13 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.LiftedBinaryOperator): Add support for the
+ boolean operators '&&', '||', '&' and '|'.
+ (Nullable.OperatorTrueOrFalse): New public class.
+
+ * ecore.cs (Expression.GetOperatorTrue/False): Return an `Expression'
+ instead of a `StaticCallExpr'; added support for nullables.
+
+2005-03-10 Martin Baulig <martin@ximian.com>
+
+ * expression.cs
+ (ArrayAccess.EmitDynamicInitializers): Use `etype.IsValueType'
+ rather than `etype.IsSubclassOf (TypeManager.value_type)'.
+
+2005-03-07 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.Unwrap): Implement IMemoryLocation and make
+ it work if `expr' is not an IMemoryLocation.
+ (Nullable.Lifted): Implement IMemoryLocation.
+ (Nullable.LiftedConversion.ResolveUnderlying): Use the correct
+ target type.
+
+2005-03-05 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (Nullable.Unwrap, Wrap): New protected classes.
+ (Nullable.Lifted): New abstract class; rewrote the lifted conversions.
+ (Nullable): Added support for lifted unary and binary operators.
+
+ * expression.cs (Unary.DoResolve): Added support for nullable types.
+ (Binary.DoResolve): Likewise.
+ (Conditional.DoResolve): Likewise.
+
+2005-03-02 Martin Baulig <martin@ximian.com>
+
+ * decl.cs (DeclSpace.SetParameterInfo): Make this virtual.
+
+ * class.cs (ClassPart.SetParameterInfo): Override this.
+ (PartialContainer.SetParameterInfo): Override this.
+ (TypeContainer.CheckConstraints): New protected method.
+ (PartialContainer.CheckConstraints): Override this and check
+ whether the same contraints were specified in all parts of a
+ partial generic type definition.
+ (PartialContainer.UpdateConstraints): New public method.
+
+ * generic.cs (TypeParameter.UpdateConstraints): New public method.
+
+2005-03-02 Martin Baulig <martin@ximian.com>
+
+ Committing a patch from Carlos Alberto Cortez to fix #72887.
+
+ * convert.cs (Convert.ExplicitReferenceConversionExists): Allow
+ casts from `T []' to `int []'.
+
+2005-03-02 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (TypeManager.IsEqual): Make this symmetric.
+
+ * expression.cs (Binary.ResolveOperator): When resolving a
+ BinaryDelegate, use `TypeManager.IsEqual (l, r)' rather than just
+ `=='. Fixes #71866. See gen-127.cs.
+
+2005-03-02 Martin Baulig <martin@ximian.com>
+
+ * class.cs (TypeContainer.DoDefineMembers): We also need a default
+ static constructor in static classes.
+
+2005-03-02 Martin Baulig <martin@ximian.com>
+
+ * generic.cs
+ (NullableType.Name, NullableType.FullName): Add a "?" to the name.
+ (Nullable.LiftedConversion): Added support for user-defined
+ conversions.
+
+ * cs-tokenizer.cs (Tokenizer.PutbackCloseParens): New public method.
+
+ * cs-parser.jay: Use ComposedCast everywhere instead of
+ NullableType, so we don't need to check for NullableType
+ everywhere.
+ (conditional_expression): Added `INTERR CLOSE_PARENS' rule for the
+ case where we'll be resolved into a `parenthesized_expression_0'
+ afterwards.
+
+ * convert.cs
+ (Convert.UserDefinedConversion): Added nullable conversions.
+
+2005-02-28 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (TypeManager.IsNullableType): New static method.
+ (Nullable): New abstract class.
+ (Nullable.NullLiteral): New public class.
+ (Nullable.LiftedConversion): New public class.
+
+ * cs-parser.jay (non_expression_type): Changed `builtin_types' to
+ `builtin_types opt_nullable'.
+
+ * convert.cs
+ (Convert.ImplicitConversionStandard): Added nullable conversions.
+ (Convert.ExplicitConversionStandard): Likewise.
+ (Convert.ExplicitConversion): Likewise.
+
+2005-02-26 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (ComposedCast.DoResolveAsTypeStep): Allow `dim' to
+ begin with a "?", for instance "?[]". Don't do a type lookup if
+ `dim' is empty.
+
+2005-02-25 Martin Baulig <martin@ximian.com>
+
+ The first part of Nullable Types :-)
+
+ * generic.cs (NullableType): New public class.
+ (NullCoalescingOperator): New public class.
+ (TypeArguments.Resolve): Add a CS0306 check.
+
+ * cs-parser.jay (opt_error_modifier): Removed, this was unused.
+ (opt_nullable): New rule.
+ (type): Added `opt_nullable' to `namespace_or_type_name',
+ `builtin_types' and `pointer_type'.
+ (array_type): Added `opt_nullable'.
+ (opt_rank_specifier_or_nullable): New rule; this is the
+ combination of `opt_rank_specifier' and `opt_nullable'.
+ (opt_error): New rule; catch errors here.
+ (nullable_type_or_conditional): New rule; we use this to check for
+ nullable and still detect the conditional operator.
+ (local_variable_type): Use `opt_rank_specifier_or_nullable'
+ instead `opt_rank_specifier'.
+
+ * expression.cs (ComposedCast.DoResolveAsTypeStep): Added support
+ for nullables.
+
+2005-02-24 Martin Baulig <martin@ximian.com>
+
+ * README, README.Changes: Removed; they're old and obsolete.
+
+2005-02-22 Martin Baulig <martin@ximian.com>
+
+ * generic.cs (TypeParameter.Resolve): If resolving the constraints
+ returned an error, set `constraints' to null to avoid a crash
+ later on.
+ (TypeParameter.ResolveType): Likewise.
+
+2005-02-22 Martin Baulig <martin@ximian.com>
+
+ * generic.cs
+ (Constraints.ResolveTypes): Protect against being called twice.
+ (Constraints.CheckInterfaceMethod): Don't call ResolveTypes().
+ (TypeParameter.ResolveType): New public method; calls
+ constraints.ResolveTypes().
+ (TypeParameter.DefineType): Moved constraints.ResolveType() out
+ into the new ResolveType().
+ (GenericMethod.Define): Call ResolveType() on all our
+ TypeParameter's.
+
+2005-02-21 Martin Baulig <martin@ximian.com>
+
+ * generic.cs
+ (TypeManager.generic_nullable_type): New static public field.
+ (TypeManager.InitGenericCoreType): Lookup "System.Nullable`1".
+
+ * rootcontext.cs
+ (RootContext.ResolveCore): Resolve "System.Nullable`1".
+
2005-02-15 Martin Baulig <martin@ximian.com>
* generic.cs (ConstructedType.Constraints): Correctly check
--- /dev/null
--- /dev/null
++This document describes all code optimalizations performed by Mono C# compiler
++when optimalizations are enabled via /optimize+ option.
++
++Optimalizations:
++
++* Instance field initializer to default value
++---------------------------------------------
++
++Code to optimize:
++
++class C
++{
++ enum E
++ {
++ Test
++ }
++
++ int i = 0; // Field will not be redundantly assigned
++ int i2 = new int (); // This will be also completely optimized out
++
++ E e = E.Test; // Even this will go out.
++
++}
++
++
++
public AttributeTargets Target;
public readonly string Name;
+ public readonly Expression LeftExpr;
+ public readonly string Identifier;
+
public readonly ArrayList Arguments;
public readonly Location Location;
static PtrHashtable usage_attr_cache = new PtrHashtable ();
- public Attribute (string target, string name, ArrayList args, Location loc)
+ public Attribute (string target, Expression left_expr, string identifier, ArrayList args, Location loc)
{
- Name = name;
+ LeftExpr = left_expr;
+ Identifier = identifier;
+ Name = LeftExpr == null ? identifier : LeftExpr + "." + identifier;
Arguments = args;
Location = loc;
ExplicitTarget = target;
{
Report.Error (617, Location, "Invalid attribute argument: '{0}'. Argument must be fields " +
"fields which are not readonly, static or const; or read-write instance properties.",
- Name);
+ name);
}
static void Error_AttributeArgumentNotValid (string extra, Location loc)
"Could not find a constructor for this argument list.");
}
+ void ResolvePossibleAttributeTypes (EmitContext ec, out Type t1, out Type t2)
+ {
+ t1 = null;
+ t2 = null;
+
+ FullNamedExpression n1 = null;
+ FullNamedExpression n2 = null;
+ string IdentifierAttribute = Identifier + "Attribute";
+ if (LeftExpr == null) {
+ n1 = new SimpleName (Identifier, Location).ResolveAsTypeStep (ec);
+
+ // FIXME: Shouldn't do this for quoted attributes: [@A]
+ n2 = new SimpleName (IdentifierAttribute, Location).ResolveAsTypeStep (ec);
+ } else {
+ FullNamedExpression l = LeftExpr.ResolveAsTypeStep (ec);
+ if (l == null) {
+ Report.Error (246, Location, "Couldn't find namespace or type '{0}'", LeftExpr);
+ return;
+ }
+ n1 = new MemberAccess (l, Identifier, Location).ResolveNamespaceOrType (ec, true);
+
+ // FIXME: Shouldn't do this for quoted attributes: [X.@A]
+ n2 = new MemberAccess (l, IdentifierAttribute, Location).ResolveNamespaceOrType (ec, true);
+ }
+
+ TypeExpr te1 = n1 == null ? null : n1 as TypeExpr;
+ TypeExpr te2 = n2 == null ? null : n2 as TypeExpr;
+
+ if (te1 != null)
+ t1 = te1.ResolveType (ec);
+ if (te2 != null)
+ t2 = te2.ResolveType (ec);
+ }
+
/// <summary>
/// Tries to resolve the type of the attribute. Flags an error if it can't, and complain is true.
/// </summary>
- protected virtual Type CheckAttributeType (EmitContext ec)
+ Type CheckAttributeType (EmitContext ec)
{
- string NameAttribute = Name + "Attribute";
- FullNamedExpression n1 = ec.ResolvingTypeTree
- ? ec.DeclSpace.FindType (Location, Name)
- : ec.DeclSpace.LookupType (Name, true, Location);
-
- // FIXME: Shouldn't do this for quoted attributes: [@A]
- FullNamedExpression n2 = ec.ResolvingTypeTree
- ? ec.DeclSpace.FindType (Location, NameAttribute)
- : ec.DeclSpace.LookupType (NameAttribute, true, Location);
-
- TypeExpr e1 = n1 == null ? null : n1 as TypeExpr;
- TypeExpr e2 = n2 == null ? null : n2 as TypeExpr;
+ Type t1, t2;
+ ResolvePossibleAttributeTypes (ec, out t1, out t2);
- Type t1 = e1 == null ? null : e1.ResolveType (ec);
- Type t2 = e2 == null ? null : e2.ResolveType (ec);
+ string NameAttribute = Name + "Attribute";
String err0616 = null;
if (t1 != null && ! t1.IsSubclassOf (TypeManager.attribute_type)) {
return null;
}
- public Type ResolveType (EmitContext ec)
+ public virtual Type ResolveType (EmitContext ec)
{
if (Type == null)
Type = CheckAttributeType (ec);
// of type object
//
- ParameterData pd = Invocation.GetParameterData (constructor);
+ ParameterData pd = TypeManager.GetParameterData (constructor);
int last_real_param = pd.Count;
if (pd.HasParams) {
return null;
}
++ object value = pos_values [j];
++ if (value != null && a.Type != value.GetType () && a.Type.IsPrimitive) {
++ bool fail;
++ pos_values [j] = TypeManager.ChangeType (value, a.Type, out fail);
++ if (fail) {
++ // TODO: Can failed ?
++ throw new NotImplementedException ();
++ }
++ }
++
if (j < last_real_param)
continue;
{
public readonly NamespaceEntry ns;
- public GlobalAttribute (TypeContainer container, string target, string name, ArrayList args, Location loc):
- base (target, name, args, loc)
+ public GlobalAttribute (TypeContainer container, string target,
+ Expression left_expr, string identifier, ArrayList args, Location loc):
+ base (target, left_expr, identifier, args, loc)
{
ns = container.NamespaceEntry;
}
- protected override Type CheckAttributeType (EmitContext ec)
+ void Enter ()
{
// RootContext.Tree.Types has a single NamespaceEntry which gets overwritten
// each time a new file is parsed. However, we need to use the NamespaceEntry
// in effect where the attribute was used. Since code elsewhere cannot assume
// that the NamespaceEntry is right, just overwrite it.
//
- // Precondition: RootContext.Tree.Types == null || RootContext.Tree.Types == ns.
- // The second case happens when we are recursively invoked from inside Emit.
-
- NamespaceEntry old = null;
- if (ec.DeclSpace == RootContext.Tree.Types) {
- old = ec.DeclSpace.NamespaceEntry;
- ec.DeclSpace.NamespaceEntry = ns;
- if (old != null && old != ns)
- throw new InternalErrorException (Location + " non-null NamespaceEntry " + old);
- }
+ // Precondition: RootContext.Tree.Types == null
+
+ if (RootContext.Tree.Types.NamespaceEntry != null)
+ throw new InternalErrorException (Location + " non-null NamespaceEntry");
- Type retval = base.CheckAttributeType (ec);
+ RootContext.Tree.Types.NamespaceEntry = ns;
+ }
- if (ec.DeclSpace == RootContext.Tree.Types)
- ec.DeclSpace.NamespaceEntry = old;
+ void Leave ()
+ {
+ RootContext.Tree.Types.NamespaceEntry = null;
+ }
+ public override Type ResolveType (EmitContext ec)
+ {
+ Enter ();
+ Type retval = base.ResolveType (ec);
+ Leave ();
return retval;
}
public override CustomAttributeBuilder Resolve (EmitContext ec)
{
- if (ec.DeclSpace == RootContext.Tree.Types) {
- NamespaceEntry old = ec.DeclSpace.NamespaceEntry;
- ec.DeclSpace.NamespaceEntry = ns;
- if (old != null)
- throw new InternalErrorException (Location + " non-null NamespaceEntry " + old);
- }
-
+ Enter ();
CustomAttributeBuilder retval = base.Resolve (ec);
-
- if (ec.DeclSpace == RootContext.Tree.Types)
- ec.DeclSpace.NamespaceEntry = null;
-
+ Leave ();
return retval;
}
}
static PtrHashtable analyzed_types_obsolete = new PtrHashtable ();
static PtrHashtable analyzed_member_obsolete = new PtrHashtable ();
static PtrHashtable analyzed_method_excluded = new PtrHashtable ();
+ static PtrHashtable fixed_buffer_cache = new PtrHashtable ();
+
+ static object TRUE = new object ();
+ static object FALSE = new object ();
private AttributeTester ()
{
}
analyzed_types.Add (type, result ? TRUE : FALSE);
return result;
- }
+ }
+
+ /// <summary>
+ /// Returns IFixedBuffer implementation if field is fixed buffer else null.
+ /// </summary>
+ public static IFixedBuffer GetFixedBuffer (FieldInfo fi)
+ {
+ FieldBase fb = TypeManager.GetField (fi);
+ if (fb != null) {
+ return fb as IFixedBuffer;
+ }
- static object TRUE = new object ();
- static object FALSE = new object ();
+#if NET_2_0
+ object o = fixed_buffer_cache [fi];
+ if (o == null) {
+ if (System.Attribute.GetCustomAttribute (fi, TypeManager.fixed_buffer_attr_type) == null) {
+ fixed_buffer_cache.Add (fi, FALSE);
+ return null;
+ }
+
+ IFixedBuffer iff = new FixedFieldExternal (fi);
+ fixed_buffer_cache.Add (fi, iff);
+ return iff;
+ }
+
+ if (o == FALSE)
+ return null;
+
+ return (IFixedBuffer)o;
+#else
+ return null;
+#endif
+ }
public static void VerifyModulesClsCompliance ()
{
interfaces.Add (iface);
}
- public void AddField (Field field)
+ public void AddField (FieldMember field)
{
if (!AddToMemberContainer (field))
return;
if (a == null)
return false;
++ if (RootContext.Optimize) {
++ Constant c = e as Constant;
++ if (c != null) {
++ if (c.IsDefaultValue)
++ continue;
++ }
++ }
++
a.EmitStatement (ec);
}
CurrentTypeParameters [i - offset].DefineConstraints ();
current_type = new ConstructedType (Name, TypeParameters, Location);
- }
- if (IsGeneric) {
- foreach (TypeParameter type_param in TypeParameters)
+ foreach (TypeParameter type_param in TypeParameters) {
if (!type_param.DefineType (ec)) {
error = true;
return null;
}
+ }
+
+ if (!CheckConstraints (ec)) {
+ error = true;
+ return null;
+ }
}
if ((Kind == Kind.Struct) && TypeManager.value_type == null)
return TypeBuilder;
}
+ protected virtual bool CheckConstraints (EmitContext ec)
+ {
+ return true;
+ }
+
protected virtual bool DefineNestedTypes ()
{
if (Interfaces != null) {
protected virtual bool DoDefineMembers ()
{
- //
- // We need to be able to use the member cache while we are checking/defining
- //
- if (TypeBuilder.BaseType != null)
- base_cache = TypeManager.LookupMemberCache (TypeBuilder.BaseType);
-
- if (TypeBuilder.IsInterface)
- base_cache = TypeManager.LookupBaseInterfacesCache (TypeBuilder);
-
if (IsTopLevel) {
if ((ModFlags & Modifiers.NEW) != 0)
Error_KeywordNotAllowed (Location);
DefineContainerMembers (constants);
DefineContainerMembers (fields);
- if ((Kind == Kind.Class) && !(this is ClassPart) && !(this is StaticClass)){
+ if ((Kind == Kind.Class) && !(this is ClassPart)){
if ((instance_constructors == null) &&
!(this is StaticClass)) {
if (default_constructor == null)
if (fields != null) {
int len = fields.Count;
for (int i = 0; i < len; i++) {
- Field f = (Field) fields [i];
+ FieldMember f = (FieldMember) fields [i];
if ((f.ModFlags & modflags) == 0)
continue;
continue;
FieldBuilder fb = con.FieldBuilder;
+ if (fb == null) {
+ if (con.Define ())
+ fb = con.FieldBuilder;
+ }
if (fb != null && filter (fb, criteria) == true) {
if (members == null)
members = new ArrayList ();
continue;
TypeBuilder tb = t.TypeBuilder;
+ if (tb == null)
+ tb = t.DefineType ();
+
if (tb != null && (filter (tb, criteria) == true)) {
if (members == null)
members = new ArrayList ();
}
if (fields != null)
- foreach (Field f in fields)
+ foreach (FieldMember f in fields)
f.Emit ();
if (events != null){
public virtual MemberCache BaseCache {
get {
+ if (base_cache != null)
+ return base_cache;
+ if (TypeBuilder.BaseType != null)
+ base_cache = TypeManager.LookupMemberCache (TypeBuilder.BaseType);
+ if (TypeBuilder.IsInterface)
+ base_cache = TypeManager.LookupBaseInterfacesCache (TypeBuilder);
return base_cache;
}
}
return null;
}
+ if (pc.IsGeneric) {
+ if (pc.CountTypeParameters != member_name.CountTypeArguments) {
+ Report.Error (
+ 264, loc, "Partial declarations of `{0}' " +
+ "must have the same type parameter names in " +
+ "the same order", member_name.GetTypeName ());
+ return null;
+ }
+
+ string[] pc_names = pc.MemberName.TypeArguments.GetDeclarations ();
+ string[] names = member_name.TypeArguments.GetDeclarations ();
+
+ for (int i = 0; i < pc.CountTypeParameters; i++) {
+ if (pc_names [i] == names [i])
+ continue;
+
+ Report.Error (
+ 264, loc, "Partial declarations of `{0}' " +
+ "must have the same type parameter names in " +
+ "the same order", member_name.GetTypeName ());
+ return null;
+ }
+ }
+
return pc;
}
RootContext.Tree.RecordDecl (full_name, pc);
parent.AddType (pc);
pc.Register ();
+ // This is needed to define our type parameters; we define the constraints later.
+ pc.SetParameterInfo (null);
return pc;
}
return PendingImplementation.GetPendingImplementations (this);
}
+ ArrayList constraints_lists;
+
+ public void UpdateConstraints (ArrayList constraints_list)
+ {
+ //
+ // This is called for each ClassPart in a partial generic type declaration.
+ //
+ // If no constraints were specified for the part, just return.
+ // Otherwise, if we're called with constraints for the first time, they become
+ // the type's constraint. If we're called with constraints again, we just
+ // store them somewhere so we can later check whether there are no conflicts.
+ //
+ if (constraints_list == null)
+ return;
+
+ if (constraints_lists != null) {
+ constraints_lists.Add (constraints_list);
+ return;
+ }
+
+ DoUpdateConstraints (null, constraints_list, false);
+
+ constraints_lists = new ArrayList ();
+ }
+
+ protected bool DoUpdateConstraints (EmitContext ec, ArrayList constraints_list, bool check)
+ {
+ for (int i = 0; i < TypeParameters.Length; i++) {
+ string name = TypeParameters [i].Name;
+
+ Constraints constraints = null;
+ if (constraints_list != null) {
+ foreach (Constraints constraint in constraints_list) {
+ if (constraint.TypeParameter == name) {
+ constraints = constraint;
+ break;
+ }
+ }
+ }
+
+ if (!TypeParameters [i].UpdateConstraints (ec, constraints, check)) {
+ Report.Error (265, Location, "Partial declarations of `{0}' have " +
+ "inconsistent constraints for type parameter `{1}'.",
+ MemberName.GetTypeName (), name);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected override bool CheckConstraints (EmitContext ec)
+ {
+ if (constraints_lists == null)
+ return true;
+
+ //
+ // If constraints were specified in more than one part of a
+ // partial generic type definition, they must be identical.
+ //
+ // Note that we must resolve them and then compute the fully
+ // resolved types since different parts may have different
+ // `using' aliases. See gen-129.cs for an example.
+
+ foreach (ArrayList constraints_list in constraints_lists) {
+ if (!DoUpdateConstraints (ec, constraints_list, true))
+ return false;
+ }
+
+ return true;
+ }
+
public ClassPart AddPart (NamespaceEntry ns, int mod, Attributes attrs,
Location l)
{
interface_type, full, name, loc);
}
+ public override void SetParameterInfo (ArrayList constraints_list)
+ {
+ PartialContainer.UpdateConstraints (constraints_list);
+ }
+
public override MemberCache BaseCache {
get {
return PartialContainer.BaseCache;
protected override bool CheckGenericOverride (MethodInfo method, string name)
{
- ParameterData pd = Invocation.GetParameterData (method);
+ ParameterData pd = TypeManager.GetParameterData (method);
for (int i = 0; i < ParameterTypes.Length; i++) {
GenericConstraints ogc = pd.GenericConstraints (i);
}
if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0) {
- Report.SymbolRelatedToPreviousError (conflict_symbol);
- Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError (Parent));
- }
+ Report.SymbolRelatedToPreviousError (conflict_symbol);
+ Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError (Parent));
+ }
return true;
}
return TypeManager.GetFullNameSignature (FieldBuilder);
}
+ protected virtual bool IsFieldClsCompliant {
+ get {
+ if (FieldBuilder == null)
+ return true;
+
+ return AttributeTester.IsClsCompliant (FieldBuilder.FieldType);
+ }
+ }
+
public override string[] ValidAttributeTargets {
get {
return attribute_targets;
if (!base.VerifyClsCompliance (ds))
return false;
- if (FieldBuilder == null) {
- return true;
- }
-
- if (!AttributeTester.IsClsCompliant (FieldBuilder.FieldType)) {
+ if (!IsFieldClsCompliant) {
Report.Error (3003, Location, "Type of '{0}' is not CLS-compliant", GetSignatureForError ());
}
return true;
MemberType = texpr.Type;
+ ec.InUnsafe = old_unsafe;
+
if (MemberType == TypeManager.void_type) {
Report.Error (1547, Location, "Keyword 'void' cannot be used in this context");
return false;
}
- ec.InUnsafe = old_unsafe;
-
if (!CheckBase ())
return false;
public override void Emit ()
{
+ if (OptAttributes != null) {
+ EmitContext ec = new EmitContext (Parent, Location, null, FieldBuilder.FieldType, ModFlags);
+ OptAttributes.Emit (ec, this);
+ }
+
if (Parent.HasExplicitLayout && ((status & Status.HAS_OFFSET) == 0) && (ModFlags & Modifiers.STATIC) == 0) {
Report.Error (625, Location, "'{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute.", GetSignatureForError ());
}
}
}
+ interface IFixedBuffer
+ {
+ FieldInfo Element { get; }
+ Type ElementType { get; }
+ }
+
+ public class FixedFieldExternal: IFixedBuffer
+ {
+ FieldInfo element_field;
+
+ public FixedFieldExternal (FieldInfo fi)
+ {
+ element_field = fi.FieldType.GetField (FixedField.FixedElementName);
+ }
+
+ #region IFixedField Members
+
+ public FieldInfo Element {
+ get {
+ return element_field;
+ }
+ }
+
+ public Type ElementType {
+ get {
+ return element_field.FieldType;
+ }
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Fixed buffer implementation
+ /// </summary>
+ public class FixedField: FieldMember, IFixedBuffer
+ {
+ public const string FixedElementName = "FixedElementField";
+ static int GlobalCounter = 0;
+ static object[] ctor_args = new object[] { (short)LayoutKind.Sequential };
+ static FieldInfo[] fi;
+
+ TypeBuilder fixed_buffer_type;
+ FieldBuilder element;
+ Expression size_expr;
+ int buffer_size;
+
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE;
+
+ public FixedField (TypeContainer parent, Expression type, int mod, string name,
+ Expression size_expr, Attributes attrs, Location loc):
+ base (parent, type, mod, AllowedModifiers, new MemberName (name), null, attrs, loc)
+ {
+ if (RootContext.Version == LanguageVersion.ISO_1)
+ Report.FeatureIsNotStandardized (loc, "fixed sized buffers");
+
+ this.size_expr = size_expr;
+ }
+
+ public override bool Define()
+ {
+#if !NET_2_0
+ if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) != 0)
+ Report.Warning (-23, Location, "Only not private or internal fixed sized buffers are supported by .NET 1.x");
+#endif
+
+ if (Parent.Kind != Kind.Struct) {
+ Report.Error (1642, Location, "Fixed buffer fields may only be members of structs");
+ return false;
+ }
+
+ if (!base.Define ())
+ return false;
+
+ if (!MemberType.IsPrimitive) {
+ Report.Error (1663, Location, "Fixed sized buffer type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double");
+ return false;
+ }
+
+ Expression e = size_expr.Resolve (Parent.EmitContext);
+ if (e == null)
+ return false;
+
+ Constant c = e as Constant;
+ if (c == null) {
+ Report.Error (133, Location, "The expression being assigned to '{0}' must be constant", GetSignatureForError ());
+ return false;
+ }
+
+ buffer_size = (int)c.GetValue ();
+ if (buffer_size <= 0) {
+ Report.Error (1665, Location, "Fixed sized buffer '{0}' must have a length greater than zero", GetSignatureForError ());
+ return false;
+ }
+ buffer_size *= Expression.GetTypeSize (MemberType);
+
+ // Define nested
+ string name = String.Format ("<{0}>__FixedBuffer{1}", Name, GlobalCounter++);
+
+ fixed_buffer_type = Parent.TypeBuilder.DefineNestedType (name,
+ TypeAttributes.NestedPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, TypeManager.value_type);
+ element = fixed_buffer_type.DefineField (FixedElementName, MemberType, FieldAttributes.Public);
+ RootContext.RegisterCompilerGeneratedType (fixed_buffer_type);
+
+ FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, Modifiers.FieldAttr (ModFlags));
+ TypeManager.RegisterFieldBase (FieldBuilder, this);
+
+ return true;
+ }
+
+ public override void Emit()
+ {
+ if (fi == null)
+ fi = new FieldInfo [] { TypeManager.struct_layout_attribute_type.GetField ("Size") };
+
+ object[] fi_val = new object[1];
+ fi_val [0] = buffer_size;
+
+ CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.struct_layout_attribute_ctor,
+ ctor_args, fi, fi_val);
+ fixed_buffer_type.SetCustomAttribute (cab);
+
+#if NET_2_0
+ cab = new CustomAttributeBuilder (TypeManager.fixed_buffer_attr_ctor, new object[] { MemberType, buffer_size } );
+ FieldBuilder.SetCustomAttribute (cab);
+#endif
+ base.Emit ();
+ }
+
+ protected override bool IsFieldClsCompliant {
+ get {
+ return false;
+ }
+ }
+
+ #region IFixedField Members
+
+ public FieldInfo Element {
+ get {
+ return element;
+ }
+ }
+
+ public Type ElementType {
+ get {
+ return MemberType;
+ }
+ }
+
+ #endregion
+ }
+
//
// The Field class is used to represents class/struct fields during parsing.
//
return true;
}
-
- public override void Emit ()
- {
- if (OptAttributes != null) {
- EmitContext ec = new EmitContext (
- Parent, Location, null, FieldBuilder.FieldType,
- ModFlags);
- OptAttributes.Emit (ec, this);
- }
-
- base.Emit ();
- }
}
//
return null;
}
++ public abstract bool IsDefaultValue {
++ get;
++ }
++
public abstract bool IsNegative {
get;
}
ec.ig.Emit (OpCodes.Ldc_I4_0);
}
++ public override bool IsDefaultValue {
++ get {
++ return !Value;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
return new IntConstant (Value);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
return new IntConstant (Value);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
return new IntConstant (Value);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return Value < 0;
{
return new IntConstant (Value);
}
++
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
public override bool IsZeroInteger {
get { return Value == 0; }
return new IntConstant (Value);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
{
return this;
}
++
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
public override bool IsNegative {
get {
return null;
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
return null;
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return Value < 0;
return null;
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
return null;
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return Value < 0;
return null;
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return Value < 0;
ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == 0;
++ }
++ }
++
public override bool IsNegative {
get {
return Value < 0;
ec.ig.Emit (OpCodes.Ldstr, Value);
}
++ public override bool IsDefaultValue {
++ get {
++ return Value == null;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
" -noconfig[+|-] Disables implicit references to assemblies\n" +
" -nostdlib[+|-] Does not load core libraries\n" +
" -nowarn:W1[,W2] Disables one or more warnings\n" +
++ " -optimize[+|-] Enables code optimalizations" + Environment.NewLine +
" -out:FNAME Specifies output file\n" +
- " -doc:XMLFILE Generates xml documentation into specified file\n" +
" -pkg:P1[,Pn] References packages P1..Pn\n" +
" --expect-error X Expect that error X will be encountered\n" +
" -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
"For more information on Mono, visit the project Web site\n" +
" http://www.go-mono.com\n\n" +
- "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig and Marek Safar");
+ "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
Environment.Exit (0);
}
case "/optimize":
case "/optimize+":
++ RootContext.Optimize = true;
++ return true;
++
case "/optimize-":
++ RootContext.Optimize = false;
++ return true;
++
case "/incremental":
case "/incremental+":
case "/incremental-":
public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
-- return DoResolve (ec);
++ return null;
}
//
/// </remarks>
public Expression ResolveLValue (EmitContext ec, Expression right_side)
{
++ int errors = Report.Errors;
Expression e = DoResolveLValue (ec, right_side);
-- if (e != null){
-- if (e is SimpleName){
-- SimpleName s = (SimpleName) e;
-- MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
-- ec.DeclSpace.Name, loc);
-- return null;
-- }
++ if (e == null) {
++ if (errors == Report.Errors)
++ Report.Error (131, Location, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
++ return null;
++ }
++ if (e != null){
if (e.eclass == ExprClass.Invalid)
throw new Exception ("Expression " + e +
" ExprClass is Invalid after resolve");
/// Returns an expression that can be used to invoke operator true
/// on the expression if it exists.
/// </summary>
- static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
+ static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
{
return GetOperatorTrueOrFalse (ec, e, true, loc);
}
/// Returns an expression that can be used to invoke operator false
/// on the expression if it exists.
/// </summary>
- static public StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
+ static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
{
return GetOperatorTrueOrFalse (ec, e, false, loc);
}
- static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
+ static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
{
MethodBase method;
Expression operator_group;
+ if (TypeManager.IsNullableType (e.Type))
+ return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
+
operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
if (operator_group == null)
return null;
sb.Append (valid [i]);
}
- Error (119, "Expression denotes a `" + ExprClassName () + "' where " +
+ Report.Error (119, loc, "Expression denotes a `" + ExprClassName () + "' where " +
"a `" + sb.ToString () + "' was expected");
}
public EmptyCast (Expression child, Type return_type)
{
eclass = child.eclass;
++ loc = child.Location;
type = return_type;
this.child = child;
}
child.Emit (ec);
}
++ public override bool IsDefaultValue {
++ get {
++ throw new NotImplementedException ();
++ }
++ }
++
public override bool IsNegative {
get {
return false;
{
return Child.ConvertToInt ();
}
--
++
++ public override bool IsDefaultValue {
++ get {
++ return Child.IsDefaultValue;
++ }
++ }
++
public override bool IsZeroInteger {
get { return Child.IsZeroInteger; }
}
int errors = Report.Errors;
dt = ec.ResolvingTypeTree
? ds.FindType (loc, Name)
- : ds.LookupType (Name, true, loc);
+ : ds.LookupType (Name, loc, /*silent=*/ true, /*ignore_cs0104=*/ false);
if (Report.Errors != errors)
return null;
/// section 10.8.1 (Fully Qualified Names).
/// </summary>
public abstract class FullNamedExpression : Expression {
+ public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
+ {
+ return this;
+ }
+
public abstract string FullName {
get;
}
protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
{
if (type == null) {
- FullNamedExpression t = ec.DeclSpace.LookupType (name, false, Location.Null);
+ FullNamedExpression t = ec.DeclSpace.LookupType (
+ name, Location.Null, /*silent=*/ false, /*ignore_cs0104=*/ false);
if (t == null)
return null;
if (!(t is TypeExpr))
if (is_volatile)
ig.Emit (OpCodes.Volatile);
- ig.Emit (OpCodes.Ldfld, FieldInfo);
+ IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
+ if (ff != null)
+ {
+ ig.Emit (OpCodes.Ldflda, FieldInfo);
+ ig.Emit (OpCodes.Ldflda, ff.Element);
+ }
+ else {
+ ig.Emit (OpCodes.Ldfld, FieldInfo);
+ }
}
if (leave_copy) {
return true;
}
++ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
++ {
++ return DoResolve (ec);
++ }
++
public override Expression DoResolve (EmitContext ec)
{
if (instance_expr != null) {
return this;
case Operator.AddressOf:
-- if (Expr.eclass != ExprClass.Variable){
-- Error (211, "Cannot take the address of non-variables");
-- return null;
-- }
--
if (!ec.InUnsafe) {
UnsafeError (loc);
return null;
}
IVariable variable = Expr as IVariable;
- if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
+ bool is_fixed = variable != null && variable.VerifyFixed (false);
+
+ if (!ec.InFixedInitializer && !is_fixed) {
Error (212, "You can only take the address of an unfixed expression inside " +
"of a fixed statement initializer");
return null;
}
- if (ec.InFixedInitializer && ((variable != null) && variable.VerifyFixed (false))) {
+ if (ec.InFixedInitializer && is_fixed) {
Error (213, "You can not fix an already fixed expression");
return null;
}
public override Expression DoResolve (EmitContext ec)
{
-- if (Oper == Operator.AddressOf)
-- Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
++ if (Oper == Operator.AddressOf) {
++ Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
++
++ if (Expr == null || Expr.eclass != ExprClass.Variable){
++ Error (211, "Cannot take the address of non-variables");
++ return null;
++ }
++ }
else
Expr = Expr.Resolve (ec);
if (Expr == null)
return null;
+ if (TypeManager.IsNullableType (Expr.Type))
+ return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
+
eclass = ExprClass.Value;
return ResolveOperator (ec);
}
public override Expression DoResolveLValue (EmitContext ec, Expression right)
{
if (Oper == Operator.Indirection)
-- return base.DoResolveLValue (ec, right);
++ return DoResolve (ec);
-- Error (131, "The left-hand side of an assignment must be a " +
-- "variable, property or indexer");
return null;
}
// after semantic analysis (this is so we can take the address
// of an indirection).
//
- public class Indirection : Expression, IMemoryLocation, IAssignMethod {
+ public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
Expression expr;
LocalTemporary temporary;
bool prepared;
public Indirection (Expression expr, Location l)
{
this.expr = expr;
- this.type = TypeManager.GetElementType (expr.Type);
+ type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
eclass = ExprClass.Variable;
loc = l;
}
expr.Emit (ec);
}
++ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
++ {
++ return DoResolve (ec);
++ }
++
public override Expression DoResolve (EmitContext ec)
{
//
{
return "*(" + expr + ")";
}
+
+ #region IVariable Members
+
+ public VariableInfo VariableInfo {
+ get {
+ return null;
+ }
+ }
+
+ public bool VerifyFixed (bool is_expression)
+ {
+ return true;
+ }
+
+ #endregion
}
/// <summary>
mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
-- if (mg == null && expr_type.BaseType != null)
-- mg = MemberLookup (ec, expr_type.BaseType, op_name,
-- MemberTypes.Method, AllBindingFlags, loc);
--
if (mg != null) {
method = StaticCallExpr.MakeSimpleCall (
ec, (MethodGroupExpr) mg, expr, loc);
type = method.Type;
-- return this;
++ } else if (!IsIncrementableNumber (expr_type)) {
++ Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
++ TypeManager.CSharpName (expr_type) + "'");
++ return null;
}
//
type = expr_type;
if (expr.eclass == ExprClass.Variable){
LocalVariableReference var = expr as LocalVariableReference;
-- if ((var != null) && var.IsReadOnly)
++ if ((var != null) && var.IsReadOnly) {
Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
-- if (IsIncrementableNumber (expr_type) ||
-- expr_type == TypeManager.decimal_type){
-- return this;
++ return null;
}
-- } else if (expr.eclass == ExprClass.IndexerAccess){
-- IndexerAccess ia = (IndexerAccess) expr;
--
-- expr = ia.ResolveLValue (ec, this);
++ } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
++ expr = expr.ResolveLValue (ec, this);
if (expr == null)
return null;
--
-- return this;
-- } else if (expr.eclass == ExprClass.PropertyAccess){
-- PropertyExpr pe = (PropertyExpr) expr;
--
-- if (pe.VerifyAssignable ())
-- return this;
--
-- return null;
} else {
expr.Error_UnexpectedKind ("variable, indexer or property access", loc);
return null;
}
-- Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
-- TypeManager.CSharpName (expr_type) + "'");
-- return null;
++ return this;
}
public override Expression DoResolve (EmitContext ec)
return null;
eclass = ExprClass.Value;
+
+ if (TypeManager.IsNullableType (expr.Type))
+ return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
+
return ResolveOperator (ec);
}
this.is_expr = is_expr;
((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
}
-
public override void Emit (EmitContext ec)
{
return null;
}
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ expr = expr.DoResolveLValue (ec, right_side);
+ if (expr == null)
+ return null;
+
+ return ResolveRest (ec);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
expr = expr.Resolve (ec);
if (expr == null)
return null;
+ return ResolveRest (ec);
+ }
+
+ Expression ResolveRest (EmitContext ec)
+ {
TypeExpr target = target_type.ResolveAsTypeTerminal (ec);
if (target == null)
return null;
expr = Convert.ExplicitConversion (ec, expr, type, loc);
return expr;
}
-
+
public override void Emit (EmitContext ec)
{
//
return this;
}
+ bool left_is_null = left is NullLiteral;
+ bool right_is_null = right is NullLiteral;
+ if (left_is_null || right_is_null) {
+ if (oper == Operator.Equality)
+ return new BoolLiteral (left_is_null == right_is_null);
+ else
+ return new BoolLiteral (left_is_null != right_is_null);
+ }
+
//
// operator != (object a, object b)
// operator == (object a, object b)
if (((right.eclass == ExprClass.MethodGroup) ||
(r == TypeManager.anonymous_method_type))){
if ((RootContext.Version != LanguageVersion.ISO_1)){
- Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
- if (tmp == null)
- return null;
- right = tmp;
- r = right.Type;
- }
+ Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+ if (tmp == null)
+ return null;
+ right = tmp;
+ r = right.Type;
+ }
}
if (TypeManager.IsDelegateType (r)){
- MethodInfo method;
- ArrayList args = new ArrayList (2);
+ MethodInfo method;
+ ArrayList args = new ArrayList (2);
- args = new ArrayList (2);
- args.Add (new Argument (left, Argument.AType.Expression));
- args.Add (new Argument (right, Argument.AType.Expression));
+ args = new ArrayList (2);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
- if (oper == Operator.Addition)
- method = TypeManager.delegate_combine_delegate_delegate;
- else
- method = TypeManager.delegate_remove_delegate_delegate;
+ if (oper == Operator.Addition)
+ method = TypeManager.delegate_combine_delegate_delegate;
+ else
+ method = TypeManager.delegate_remove_delegate_delegate;
- if (l != r) {
- Error_OperatorCannotBeApplied ();
- return null;
- }
+ if (!TypeManager.IsEqual (l, r)) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
- return new BinaryDelegate (l, method, args);
- }
+ return new BinaryDelegate (l, method, args);
+ }
}
//
return e;
}
+ if (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type))
+ return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+
return ResolveOperator (ec);
}
{
Type op_type = left.Type;
ILGenerator ig = ec.ig;
- Type element = TypeManager.GetElementType (op_type);
+
+ // It must be either array or fixed buffer
+ Type element = TypeManager.HasElementType (op_type) ?
+ element = TypeManager.GetElementType (op_type) :
+ element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
+
int size = GetTypeSize (element);
Type rtype = right.Type;
//
left.Emit (ec);
ig.Emit (OpCodes.Conv_I);
- right.Emit (ec);
- if (size != 1){
- if (size == 0)
- ig.Emit (OpCodes.Sizeof, element);
- else
- IntLiteral.EmitInt (ig, size);
- if (rtype == TypeManager.int64_type)
- ig.Emit (OpCodes.Conv_I8);
- else if (rtype == TypeManager.uint64_type)
- ig.Emit (OpCodes.Conv_U8);
- ig.Emit (OpCodes.Mul);
+
+ Constant right_const = right as Constant;
+ if (right_const != null && size != 0) {
+ Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size), right_const, loc);
+ if (ex == null)
+ return;
+ ex.Emit (ec);
+ } else {
+ right.Emit (ec);
+ if (size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, element);
+ else
+ IntLiteral.EmitInt (ig, size);
+ if (rtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_I8);
+ else if (rtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_U8);
+ ig.Emit (OpCodes.Mul);
+ }
}
if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
if (expr == null)
return null;
+
+ if (TypeManager.IsNullableType (expr.Type))
+ return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
if (expr.Type != TypeManager.bool_type){
expr = Expression.ResolveBoolean (
ILGenerator ig = ec.ig;
int arg_idx = idx;
- if (!ec.IsStatic)
+ if (!ec.MethodIsStatic)
arg_idx++;
+
EmitLdArg (ig, arg_idx);
ILGenerator ig = ec.ig;
int arg_idx = idx;
- if (!ec.IsStatic)
+ if (!ec.MethodIsStatic)
arg_idx++;
EmitLdArg (ig, arg_idx);
prepared = prepare_for_load;
- if (!ec.IsStatic)
+ if (!ec.MethodIsStatic)
arg_idx++;
if (is_ref && !prepared)
int arg_idx = idx;
- if (!ec.IsStatic)
+ if (!ec.MethodIsStatic)
arg_idx++;
if (is_ref){
return true;
}
++ void Error_LValueRequired (Location loc)
++ {
++ Report.Error (1510, loc, "An lvalue is required as an argument to out or ref");
++ }
++
public bool Resolve (EmitContext ec, Location loc)
{
if (ArgType == AType.Ref) {
return false;
}
}
-- Expr = Expr.ResolveLValue (ec, Expr);
-- } else if (ArgType == AType.Out)
-- Expr = Expr.ResolveLValue (ec, EmptyExpression.Null);
++ Expr = Expr.DoResolveLValue (ec, Expr);
++ if (Expr == null)
++ Error_LValueRequired (loc);
++ } else if (ArgType == AType.Out) {
++ Expr = Expr.DoResolveLValue (ec, EmptyExpression.Null);
++ if (Expr == null)
++ Error_LValueRequired (loc);
++ }
else
Expr = Expr.Resolve (ec);
if (Expr == null)
return false;
++ if (Expr is IMemberExpr) {
++ IMemberExpr me = Expr as IMemberExpr;
++
++ //
++ // This can happen with the following code:
++ //
++ // class X {}
++ // class Y {
++ // public Y (X x) {}
++ // }
++ // class Z : Y {
++ // X X;
++ // public Z () : base (X) {}
++ // }
++ //
++ // SimpleNameResolve is conservative about flagging the X as
++ // an error since it has identical name and type. However,
++ // because there's no MemberAccess, that is not really justified.
++ // It is still simpler to fix it here, rather than in SimpleNameResolve.
++ //
++ if (me.IsInstance && me.InstanceExpression == null) {
++ SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
++ return false;
++ }
++ }
++
if (ArgType == AType.Expression)
return true;
else {
"A property or indexer can not be passed as an out or ref " +
"parameter");
} else {
-- Report.Error (
-- 1510, loc,
-- "An lvalue is required as an argument to out or ref");
++ Error_LValueRequired (loc);
}
return false;
}
Expression expr;
MethodBase method = null;
- static Hashtable method_parameter_cache;
-
- static Invocation ()
- {
- method_parameter_cache = new PtrHashtable ();
- }
-
//
// arguments is an ArrayList, but we do not want to typecast,
// as it might be null.
}
}
- /// <summary>
- /// Returns the Parameters (a ParameterData interface) for the
- /// Method `mb'
- /// </summary>
- public static ParameterData GetParameterData (MethodBase mb)
- {
- object pd = method_parameter_cache [mb];
- object ip;
-
- if (pd != null)
- return (ParameterData) pd;
-
- ip = TypeManager.LookupParametersByBuilder (mb);
- if (ip != null){
- method_parameter_cache [mb] = ip;
-
- return (ParameterData) ip;
- } else {
- ReflectionParameters rp = new ReflectionParameters (mb);
- method_parameter_cache [mb] = rp;
-
- return (ParameterData) rp;
- }
- }
-
/// <summary>
/// Determines "better conversion" as specified in 7.4.2.3
///
MethodBase candidate, bool candidate_params,
MethodBase best, bool best_params, Location loc)
{
- ParameterData candidate_pd = GetParameterData (candidate);
- ParameterData best_pd = GetParameterData (best);
+ ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
+ ParameterData best_pd = TypeManager.GetParameterData (best);
- int cand_count = candidate_pd.Count;
-
- //
- // If there is no best method, than this one
- // is better, however, if we already found a
- // best method, we cant tell. This happens
- // if we have:
- //
- // interface IFoo {
- // void DoIt ();
- // }
- //
- // interface IBar {
- // void DoIt ();
- // }
- //
- // interface IFooBar : IFoo, IBar {}
- //
- // We cant tell if IFoo.DoIt is better than IBar.DoIt
- //
- // However, we have to consider that
- // Trim (); is better than Trim (params char[] chars);
- //
- if (cand_count == 0 && argument_count == 0)
- return !candidate_params && best_params;
-
- if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
- (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
- if (cand_count != argument_count)
- return false;
-
bool better_at_least_one = false;
- bool is_equal = true;
-
+ bool same = true;
for (int j = 0; j < argument_count; ++j) {
Argument a = (Argument) args [j];
if (best_params)
bt = TypeManager.GetElementType (bt);
- if (!ct.Equals (bt))
- is_equal = false;
+ if (ct.Equals (bt))
+ continue;
+ same = false;
Type better = BetterConversion (ec, a, ct, bt, loc);
// for each argument, the conversion to 'ct' should be no worse than
// the conversion to 'bt'.
better_at_least_one = true;
}
- //
- // If a method (in the normal form) with the
- // same signature as the expanded form of the
- // current best params method already exists,
- // the expanded form is not applicable so we
- // force it to select the candidate
- //
- if (!candidate_params && best_params && cand_count == argument_count)
- return true;
+ if (better_at_least_one)
+ return true;
+
+ if (!same)
+ return false;
//
// If two methods have equal parameter types, but
// only one of them is generic, the non-generic one wins.
//
- if (is_equal) {
- if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
- return true;
- else if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
+ if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
+ return true;
+ else if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
+ return false;
+
+ //
+ // This handles the case
+ //
+ // Add (float f1, float f2, float f3);
+ // Add (params decimal [] foo);
+ //
+ // The call Add (3, 4, 5) should be ambiguous. Without this check, the
+ // first candidate would've chosen as better.
+ //
+ //
+ // This handles the following cases:
+ //
+ // Trim () is better than Trim (params char[] chars)
+ // Concat (string s1, string s2, string s3) is better than
+ // Concat (string s1, params string [] srest)
+ //
+ return !candidate_params && best_params;
+ }
+
+ static bool IsOverride (MethodBase cand_method, MethodBase base_method)
+ {
+ if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
+ return false;
+
+ ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
+ ParameterData base_pd = TypeManager.GetParameterData (base_method);
+
+ if (cand_pd.Count != base_pd.Count)
+ return false;
+
+ for (int j = 0; j < cand_pd.Count; ++j) {
+ Parameter.Modifier cm = cand_pd.ParameterModifier (j);
+ Parameter.Modifier bm = base_pd.ParameterModifier (j);
+ Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
+ Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
+
+ if (cm != bm || ct != bt)
return false;
}
- return better_at_least_one;
+ return true;
}
public static string FullMethodDesc (MethodBase mb)
sb.Append (".");
sb.Append (mb.Name);
- ParameterData pd = GetParameterData (mb);
+ ParameterData pd = TypeManager.GetParameterData (mb);
int count = pd.Count;
sb.Append (" (");
int arg_count, MethodBase candidate,
bool do_varargs)
{
- ParameterData pd = GetParameterData (candidate);
+ ParameterData pd = TypeManager.GetParameterData (candidate);
int pd_count = pd.Count;
static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
MethodBase candidate)
{
- ParameterData pd = GetParameterData (candidate);
+ ParameterData pd = TypeManager.GetParameterData (candidate);
if (arg_count != pd.Count)
return false;
Type applicable_type = null;
int arg_count = 0;
ArrayList candidates = new ArrayList ();
+ ArrayList candidate_overrides = new ArrayList ();
//
// Used to keep a map between the candidate
IsAncestralType (decl_type, applicable_type))
continue;
+ //
+ // Methods marked 'override' don't take part in 'applicable_type'
+ // computation, nor in the actual overload resolution.
+ // However, they still need to be emitted instead of a base virtual method.
+ // We avoid doing the 'applicable' test here, since it'll anyway be applied
+ // to the base virtual function, and IsOverride is much faster than IsApplicable.
+ //
+ if (!me.IsBase &&
+ methods [i].IsVirtual &&
+ (methods [i].Attributes & MethodAttributes.NewSlot) == 0) {
+ candidate_overrides.Add (methods [i]);
+ continue;
+ }
+
//
// Check if candidate is applicable (section 14.4.2.1)
// Is candidate applicable in normal form?
int candidate_top = candidates.Count;
- if (candidate_top == 0) {
+ if (applicable_type == null) {
//
// Okay so we have failed to find anything so we
// return by providing info about the closest match
//
for (int i = 0; i < methods.Length; ++i) {
MethodBase c = (MethodBase) methods [i];
- ParameterData pd = GetParameterData (c);
+ ParameterData pd = TypeManager.GetParameterData (c);
if (pd.Count != arg_count)
continue;
for (int i = 0; i < methods.Length; ++i) {
MethodBase c = methods [i];
- ParameterData pd = GetParameterData (c);
+ ParameterData pd = TypeManager.GetParameterData (c);
if (pd.Count != arg_count)
continue;
int j = finalized; // where to put the next finalized candidate
int k = finalized; // where to put the next undiscarded candidate
for (int i = finalized; i < candidate_top; ++i) {
- Type decl_type = ((MethodBase) candidates[i]).DeclaringType;
+ MethodBase candidate = (MethodBase) candidates [i];
+ Type decl_type = candidate.DeclaringType;
if (decl_type == applicable_type) {
- candidates[k++] = candidates[j];
- candidates[j++] = candidates[i];
+ candidates [k++] = candidates [j];
+ candidates [j++] = candidates [i];
continue;
}
IsAncestralType (decl_type, next_applicable_type))
continue;
- candidates[k++] = candidates[i];
+ candidates [k++] = candidates [i];
- #if false
- //
- // Methods marked 'override' don't take part in 'applicable_type'
- // computation.
- //
- if (!me.IsBase &&
- candidate.IsVirtual &&
- (candidate.Attributes & MethodAttributes.NewSlot) == 0)
- continue;
- #endif
-
if (next_applicable_type == null ||
IsAncestralType (next_applicable_type, decl_type))
next_applicable_type = decl_type;
// Now we actually find the best method
//
- method = (MethodBase) candidates[0];
+ method = (MethodBase) candidates [0];
method_params = candidate_to_form != null && candidate_to_form.Contains (method);
for (int ix = 1; ix < candidate_top; ix++){
MethodBase candidate = (MethodBase) candidates [ix];
+
+ if (candidate == method)
+ continue;
+
bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
if (BetterFunction (ec, Arguments, arg_count,
return null;
}
+ //
+ // If the method is a virtual function, pick an override closer to the LHS type.
+ //
+ if (!me.IsBase && method.IsVirtual) {
+ if ((method.Attributes & MethodAttributes.NewSlot) != MethodAttributes.NewSlot)
+ throw new InternalErrorException (
+ "Should not happen. An 'override' method took part in overload resolution: " + method);
+
+ foreach (MethodBase candidate in candidate_overrides) {
+ if (IsOverride (candidate, method))
+ method = candidate;
+ }
+ }
+
//
// And now check if the arguments are all
// compatible, perform conversions if
Type delegate_type, bool may_fail,
Location loc)
{
- ParameterData pd = GetParameterData (method);
+ ParameterData pd = TypeManager.GetParameterData (method);
int pd_count = pd.Count;
for (int j = 0; j < arg_count; j++) {
{
ParameterData pd;
if (mb != null)
- pd = GetParameterData (mb);
+ pd = TypeManager.GetParameterData (mb);
else
pd = null;
static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
ArrayList arguments)
{
- ParameterData pd = GetParameterData (mb);
+ ParameterData pd = TypeManager.GetParameterData (mb);
if (arguments == null)
return new Type [0];
// value_target = MyEmptyExpression;
}
+
+ /// <summary>
+ /// Converts complex core type syntax like 'new int ()' to simple constant
+ /// </summary>
+ Expression Constantify (Type t)
+ {
+ if (t == TypeManager.int32_type)
+ return new IntConstant (0);
+ if (t == TypeManager.uint32_type)
+ return new UIntConstant (0);
+ if (t == TypeManager.int64_type)
+ return new LongConstant (0);
+ if (t == TypeManager.uint64_type)
+ return new ULongConstant (0);
+ if (t == TypeManager.float_type)
+ return new FloatConstant (0);
+ if (t == TypeManager.double_type)
+ return new DoubleConstant (0);
+ if (t == TypeManager.short_type)
+ return new ShortConstant (0);
+ if (t == TypeManager.ushort_type)
+ return new UShortConstant (0);
+ if (t == TypeManager.sbyte_type)
+ return new SByteConstant (0);
+ if (t == TypeManager.byte_type)
+ return new ByteConstant (0);
+ if (t == TypeManager.char_type)
+ return new CharConstant ('\0');
+ if (t == TypeManager.bool_type)
+ return new BoolConstant (false);
+ if (t == TypeManager.decimal_type)
+ return new DecimalConstant (0);
+
+ return null;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
//
TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec);
if (texpr == null)
return null;
+
+ if (Arguments == null) {
+ Expression c = Constantify (type);
+ if (c != null)
+ return c;
+ }
type = texpr.Type;
if (type == null)
// If we are dealing with a struct, get the
// address of it, so we can store it.
//
- if ((dims == 1) &&
- etype.IsSubclassOf (TypeManager.value_type) &&
+ if ((dims == 1) && etype.IsValueType &&
(!TypeManager.IsBuiltinOrEnum (etype) ||
etype == TypeManager.decimal_type)) {
if (e is New){
if ((block != null) && (block.ThisVariable != null))
variable_info = block.ThisVariable.VariableInfo;
+ if (ec.CurrentAnonymousMethod != null)
+ ec.CaptureThis ();
+
return true;
}
if (sn == null || left == null || left.Type.Name != sn.Name)
return false;
- return ec.DeclSpace.LookupType (sn.Name, true, loc) != null;
+ return ec.DeclSpace.LookupType (sn.Name, loc, /*silent=*/ true, /*ignore_cs0104*/ true) != null;
}
// TODO: possible optimalization
object real_value = ((Constant) c.Expr).GetValue ();
- return Constantify (real_value, t);
+ Expression exp = Constantify (real_value, t);
+
+ if (left_is_explicit && !left_is_type && !IdenticalNameAndTypeName (ec, left_original, left, loc)) {
+ Report.SymbolRelatedToPreviousError (c);
+ error176 (loc, c.GetSignatureForError ());
+ return null;
+ }
+
+ return exp;
}
}
}
public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
+ {
+ return ResolveNamespaceOrType (ec, false);
+ }
+
+ public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent)
{
FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec);
FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc);
if ((retval != null) && (args != null))
retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec);
- if (retval == null)
+ if (!silent && retval == null)
Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName);
return retval;
}
Expression member_lookup;
member_lookup = MemberLookupFinal (ec, expr_type, expr_type, lookup_id, loc);
- if (member_lookup == null) {
+ if (!silent && member_lookup == null) {
Report.Error (234, loc, "The type name `{0}' could not be found in type `{1}'",
Identifier, new_expr.FullName);
return null;
return true;
}
- Expression MakePointerAccess (EmitContext ec)
+ Expression MakePointerAccess (EmitContext ec, Type t)
{
- Type t = Expr.Type;
-
if (t == TypeManager.void_ptr_type){
Error (242, "The array index operation is not valid for void pointers");
return null;
if (t.IsArray)
return (new ArrayAccess (this, loc)).Resolve (ec);
- else if (t.IsPointer)
- return MakePointerAccess (ec);
- else
- return (new IndexerAccess (this, loc)).Resolve (ec);
+ if (t.IsPointer)
+ return MakePointerAccess (ec, Expr.Type);
+
+ FieldExpr fe = Expr as FieldExpr;
+ if (fe != null) {
+ IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
+ if (ff != null) {
+ return MakePointerAccess (ec, ff.ElementType);
+ }
+ }
+ return (new IndexerAccess (this, loc)).Resolve (ec);
}
public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
Type t = Expr.Type;
if (t.IsArray)
return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
- else if (t.IsPointer)
- return MakePointerAccess (ec);
- else
- return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
+
+ if (t.IsPointer)
+ return MakePointerAccess (ec, Expr.Type);
+
+ FieldExpr fe = Expr as FieldExpr;
+ if (fe != null) {
+ IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
+ if (ff != null) {
+// TODO: not sure whether it is correct
+// if (!ec.InFixedInitializer) {
+// if (!ec.InFixedInitializer) {
+// Error (1666, "You cannot use fixed sized buffers contained in unfixed expressions. Try using the fixed statement.");
+// return null;
+// }
+ return MakePointerAccess (ec, ff.ElementType);
+ }
+ }
+ return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
}
public override void Emit (EmitContext ec)
loc = l;
}
++ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
++ {
++ return DoResolve (ec);
++ }
++
public override Expression DoResolve (EmitContext ec)
{
#if false
return null;
}
+ if ((dim.Length > 0) && (dim [0] == '?')) {
+ TypeExpr nullable = new NullableType (left, loc);
+ if (dim.Length > 1)
+ nullable = new ComposedCast (nullable, dim.Substring (1), loc);
+ return nullable.ResolveAsTypeTerminal (ec);
+ }
+
int pos = 0;
while ((pos < dim.Length) && (dim [pos] == '[')) {
pos++;
return this;
}
- //
- // ltype.Fullname is already fully qualified, so we can skip
- // a lot of probes, and go directly to TypeManager.LookupType
- //
- string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
- string cname = fname + dim;
- type = TypeManager.LookupTypeDirect (cname);
- if (type == null){
+ if (dim != "") {
//
- // For arrays of enumerations we are having a problem
- // with the direct lookup. Need to investigate.
+ // ltype.Fullname is already fully qualified, so we can skip
+ // a lot of probes, and go directly to TypeManager.LookupType
//
// For now, fall back to the full lookup in that case.
- //
- FullNamedExpression e = ec.DeclSpace.LookupType (cname, false, loc);
+ //
+ string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
+ string cname = fname + dim;
+ FullNamedExpression e = ec.DeclSpace.LookupType (
+ cname, loc, /*silent=*/ false, /*ignore_cs0104=*/ false);
if (e is TypeExpr)
type = ((TypeExpr) e).ResolveType (ec);
if (type == null)
}
}
- //
- // This class is used to represent the address of an array, used
- // only by the Fixed statement, this is like the C "&a [0]" construct.
- //
- public class ArrayPtr : Expression {
+ public class FixedBufferPtr: Expression {
Expression array;
-
- public ArrayPtr (Expression array, Location l)
- {
- Type array_type = TypeManager.GetElementType (array.Type);
+ public FixedBufferPtr (Expression array, Type array_type, Location l)
+ {
this.array = array;
+ this.loc = l;
type = TypeManager.GetPointerType (array_type);
eclass = ExprClass.Value;
- loc = l;
}
- public override void Emit (EmitContext ec)
+ public override void Emit(EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
array.Emit (ec);
- IntLiteral.EmitInt (ig, 0);
- ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
}
public override Expression DoResolve (EmitContext ec)
}
}
+
+ //
+ // This class is used to represent the address of an array, used
+ // only by the Fixed statement, this generates "&a [0]" construct
+ // for fixed (char *pa = a)
+ //
+ public class ArrayPtr : FixedBufferPtr {
+ Type array_type;
+
+ public ArrayPtr (Expression array, Type array_type, Location l):
+ base (array, array_type, l)
+ {
+ this.array_type = array_type;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+
+ ILGenerator ig = ec.ig;
+ IntLiteral.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Ldelema, array_type);
+ }
+ }
+
//
// Used by the fixed statement
//
this.field = field;
}
++ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
++ {
++ return DoResolve (ec);
++ }
++
public override Expression DoResolve (EmitContext ec)
{
FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
{
ec.ig.Emit (OpCodes.Ldnull);
}
--
++
++ public override bool IsDefaultValue {
++ get {
++ return true;
++ }
++ }
++
public override bool IsNegative {
get {
return false;
public static bool VerifyClsCompliance = true;
++ /// <summary>
++ /// Holds /optimize option
++ /// </summary>
++ public static bool Optimize = true;
++
public static LanguageVersion Version = LanguageVersion.Default;
//
// Generic types
//
"System.Collections.Generic.IEnumerator`1",
- "System.Collections.Generic.IEnumerable`1"
+ "System.Collections.Generic.IEnumerable`1",
};
foreach (string iname in interfaces_first_stage)
// These are classes that depends on the core interfaces
//
string [] classes_second_stage = {
+ "System.Enum",
+ "System.String",
+ "System.Array",
"System.Reflection.MemberInfo",
"System.Type",
"System.Exception",
"System.Security.CodeAccessPermission"
};
- // We must store them here before calling BootstrapCorlib_ResolveDelegate.
- TypeManager.string_type = BootstrapCorlib_ResolveClass (root, "System.String");
- TypeManager.enum_type = BootstrapCorlib_ResolveClass (root, "System.Enum");
- TypeManager.array_type = BootstrapCorlib_ResolveClass (root, "System.Array");
- TypeManager.multicast_delegate_type = BootstrapCorlib_ResolveClass (root, "System.MulticastDelegate");
- TypeManager.delegate_type = BootstrapCorlib_ResolveClass (root, "System.Delegate");
-
foreach (string cname in classes_second_stage)
BootstrapCorlib_ResolveClass (root, cname);
+ BootstrapCorlib_ResolveStruct (root, "System.Nullable`1");
+
BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
+
+ // These will be defined indirectly during the previous ResolveDelegate.
+ // However make sure the rest of the checks happen.
+ string [] delegate_types = { "System.Delegate", "System.MulticastDelegate" };
+ foreach (string cname in delegate_types)
+ BootstrapCorlib_ResolveClass (root, cname);
}
// <summary>
// If we have a <PrivateImplementationDetails> class, close it
//
if (helper_classes != null){
- foreach (TypeBuilder type_builder in helper_classes)
+ foreach (TypeBuilder type_builder in helper_classes) {
+#if NET_2_0
+ type_builder.SetCustomAttribute (TypeManager.compiler_generated_attr);
+#endif
type_builder.CreateType ();
+ }
}
attribute_types = null;
/// Used to register classes that need to be closed after all the
/// user defined classes
/// </summary>
- public static void RegisterHelperClass (TypeBuilder helper_class)
+ public static void RegisterCompilerGeneratedType (TypeBuilder helper_class)
{
if (helper_classes == null)
helper_classes = new ArrayList ();
+
helper_classes.Add (helper_class);
}
TypeAttributes.NotPublic,
TypeManager.object_type);
- RegisterHelperClass (impl_details_class);
+ RegisterCompilerGeneratedType (impl_details_class);
}
fb = impl_details_class.DefineInitializedData (