Modified:
trunk/mcs/gmcs/cs-parser.jay
trunk/mcs/mcs/ChangeLog
trunk/mcs/mcs/attribute.cs
trunk/mcs/mcs/class.cs
trunk/mcs/mcs/codegen.cs
trunk/mcs/mcs/cs-parser.jay
trunk/mcs/mcs/decl.cs
trunk/mcs/mcs/doc.cs
trunk/mcs/mcs/driver.cs
trunk/mcs/mcs/ecore.cs
trunk/mcs/mcs/expression.cs
trunk/mcs/mcs/modifiers.cs
trunk/mcs/mcs/namespace.cs
trunk/mcs/mcs/parameter.cs
trunk/mcs/mcs/pending.cs
trunk/mcs/mcs/support.cs
trunk/mcs/mcs/typemanager.cs
Log:
2007-02-15 Marek Safar <marek...@gmail.com>
C# 3.0 extension methods.
* attribute.cs (Error_MisusedExtensionAttribute): Extension attribute
cannot be used directly.
* class.cs (Class.Emit): Emit extension attribute if any class method
is extension method.
(Method.Define): Add basic extension method validation conditions.
(Method.Emit): Emit extension attribute for method.
* codegen.cs (AssemblyClass): Emit extension attribute if at least one
extension method exists. Currently we follow same approach as Microsoft
does, emit even if a method or a class are private but this can change
later.
* cs-parser.jay: Add handling of `this' keyword in method parameters
context.
* decl.cs (DeclSpace.IsStaticClass): New property.
(MemberCache.FindExtensionMethods): Looks for extension methods with
defined name and extension type.
* doc.cs: Updated after OverloadResolve changes.
* driver.cs: Add new soft reference to System.Core.dll.
* ecore.cs (MethodLookup): Can return only MethodGroupExpr.
(ExtensionMethodGroupExpr): Represents group of extension methods.
* expression.cs (Invocation): Moved methods BetterConversion, MoreSpecific,
BetterFunction, IsOverride, IsAncestralType, OverloadResolve
to MethodGroupExpr and made non-static for easier customization.
(Invocation.DoResolve): Add extension method lookup when no standard
method was found.
(MemberAccess.DoResolve): Try extension methods if no member exists.
* modifiers.cs: Add METHOD_EXTENSION modifier.
* namespace.cs (RegisterExtensionMethodClass): Register class namespace
as well as candidate extension type.
(ComputeNamespaces): When assembly constains extension methods registers
them.
(Namespace.RegisterExternalExtensionMethodClass): Register type for later
extension method lookup.
(Namespace.LookupExtensionMethod): Looks for extension method in this
namespace.
(NamespaceEntry.LookupExtensionMethod): Does extension methods lookup to
find a method which matches name and extensionType.
* parameter.cs (Parameter): Add This modifer.
(HasExtensionMethodModifier): New property.
(Resolve): Add extension parameter check.
(ModFlags): turned to property to exclude this modifier as it is not real
parameter modifier.
(Parameters): Implemented ExtensionMethodType and HasExtensionMethodType.
* support.cs (ParameterData): Add ExtensionMethodType.
(ReflectionParameters): Implemented ExtensionMethodType interface property.
* typemanager.cs: Add type and ctor extension attribute type.
Modified: trunk/mcs/gmcs/cs-parser.jay
===================================================================
--- trunk/mcs/gmcs/cs-parser.jay 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/gmcs/cs-parser.jay 2007-02-15 23:22:03 UTC (rev 72971)
@@ -1325,8 +1325,12 @@
| fixed_parameters COMMA fixed_parameter
{
ArrayList pars = (ArrayList) $1;
-
- pars.Add ($3);
+ Parameter p = (Parameter)$3;
+ if (p != null) {
+ if ((p.modFlags & Parameter.Modifier.This) != 0)
+ Report.Error (1100, p.Location, "The parameter modifier `this' can only be used on the first parameter");
+ pars.Add (p);
+ }
$$ = $1;
}
;
@@ -1388,14 +1392,31 @@
}
| parameter_modifiers parameter_modifier
{
- Report.Error (1108, lexer.Location, "A parameter cannot have specified more than one modifier");
- $$ = $1;
+ Parameter.Modifier p2 = (Parameter.Modifier)$2;
+ Parameter.Modifier mod = (Parameter.Modifier)$1 | p2;
+ if (((Parameter.Modifier)$1 & p2) == p2) {
+ Error_DuplicateParameterModifier (lexer.Location, p2);
+ } else {
+ switch (mod & ~Parameter.Modifier.This) {
+ case Parameter.Modifier.REF:
+ Report.Error (1101, lexer.Location, "The parameter modifiers `this' and `ref' cannot be used altogether");
+ break;
+ case Parameter.Modifier.OUT:
+ Report.Error (1102, lexer.Location, "The parameter modifiers `this' and `out' cannot be used altogether");
+ break;
+ default:
+ Report.Error (1108, lexer.Location, "A parameter cannot have specified more than one modifier");
+ break;
+ }
+ }
+ $$ = mod;
}
;
parameter_modifier
: REF { $$ = Parameter.Modifier.REF; }
| OUT { $$ = Parameter.Modifier.OUT; }
+ | THIS { $$ = Parameter.Modifier.This; }
;
parameter_array
@@ -1404,10 +1425,20 @@
LocatedToken lt = (LocatedToken) $4;
$$ = new ParamsParameter ((Expression) $3, lt.Value, (Attributes) $1, lt.Location);
}
+ | opt_attributes PARAMS PARAMS type IDENTIFIER
+ {
+ Error_DuplicateParameterModifier (lexer.Location, Parameter.Modifier.PARAMS);
+ $$ = null;
+ }
| opt_attributes PARAMS parameter_modifier type IDENTIFIER
{
- Report.Error (1611, (Location) $2, "The params parameter cannot be declared as ref or out");
- $$ = null;
+ Parameter.Modifier mod = (Parameter.Modifier)$3;
+ if ((mod & Parameter.Modifier.This) != 0) {
+ Report.Error (1104, lexer.Location, "The parameter modifiers `this' and `params' cannot be used altogether");
+ } else {
+ Report.Error (1611, (Location) $2, "The params parameter cannot be declared as ref or out");
+ }
+ $$ = null;
}
| opt_attributes PARAMS type error {
CheckIdentifierToken (yyToken, GetLocation ($4));
@@ -5211,6 +5242,12 @@
Report.Error (631, loc, "The modifiers `ref' and `out' are not valid in this context");
}
+static void Error_DuplicateParameterModifier (Location loc, Parameter.Modifier mod)
+{
+ Report.Error (1107, loc, "Duplicate parameter modifier `{0}'",
+ Parameter.GetModifierSignature (mod));
+}
+
void push_current_class (TypeContainer tc, bool is_interface, object partial_token)
{
if (partial_token != null)
Modified: trunk/mcs/mcs/ChangeLog
===================================================================
--- trunk/mcs/mcs/ChangeLog 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/ChangeLog 2007-02-15 23:22:03 UTC (rev 72971)
@@ -1,3 +1,66 @@
+2007-02-15 Marek Safar <marek...@gmail.com>
+
+ C# 3.0 extension methods.
+
+ * attribute.cs (Error_MisusedExtensionAttribute): Extension attribute
+ cannot be used directly.
+
+ * class.cs (Class.Emit): Emit extension attribute if any class method
+ is extension method.
+ (Method.Define): Add basic extension method validation conditions.
+ (Method.Emit): Emit extension attribute for method.
+
+ * codegen.cs (AssemblyClass): Emit extension attribute if at least one
+ extension method exists. Currently we follow same approach as Microsoft
+ does, emit even if a method or a class are private but this can change
+ later.
+
+ * cs-parser.jay: Add handling of `this' keyword in method parameters
+ context.
+
+ * decl.cs (DeclSpace.IsStaticClass): New property.
+ (MemberCache.FindExtensionMethods): Looks for extension methods with
+ defined name and extension type.
+
+ * doc.cs: Updated after OverloadResolve changes.
+
+ * driver.cs: Add new soft reference to System.Core.dll.
+
+ * ecore.cs (MethodLookup): Can return only MethodGroupExpr.
+ (ExtensionMethodGroupExpr): Represents group of extension methods.
+
+ * expression.cs (Invocation): Moved methods BetterConversion, MoreSpecific,
+ BetterFunction, IsOverride, IsAncestralType, OverloadResolve
+ to MethodGroupExpr and made non-static for easier customization.
+ (Invocation.DoResolve): Add extension method lookup when no standard
+ method was found.
+ (MemberAccess.DoResolve): Try extension methods if no member exists.
+
+ * modifiers.cs: Add METHOD_EXTENSION modifier.
+
+ * namespace.cs (RegisterExtensionMethodClass): Register class namespace
+ as well as candidate extension type.
+ (ComputeNamespaces): When assembly constains extension methods registers
+ them.
+ (Namespace.RegisterExternalExtensionMethodClass): Register type for later
+ extension method lookup.
+ (Namespace.LookupExtensionMethod): Looks for extension method in this
+ namespace.
+ (NamespaceEntry.LookupExtensionMethod): Does extension methods lookup to
+ find a method which matches name and extensionType.
+
+ * parameter.cs (Parameter): Add This modifer.
+ (HasExtensionMethodModifier): New property.
+ (Resolve): Add extension parameter check.
+ (ModFlags): turned to property to exclude this modifier as it is not real
+ parameter modifier.
+ (Parameters): Implemented ExtensionMethodType and HasExtensionMethodType.
+
+ * support.cs (ParameterData): Add ExtensionMethodType.
+ (ReflectionParameters): Implemented ExtensionMethodType interface property.
+
+ * typemanager.cs: Add type and ctor extension attribute type.
+
2007-02-15 Miguel de Icaza <mig...@novell.com>
* report.cs (DisableErrors, EnableErrors): used to prevent error
Modified: trunk/mcs/mcs/attribute.cs
===================================================================
--- trunk/mcs/mcs/attribute.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/attribute.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -187,6 +187,11 @@
Report.Error (596, Location, "The Guid attribute must be specified with the ComImport attribute");
}
+ public void Error_MisusedExtensionAttribute ()
+ {
+ //Report.Error (1112, Location, "Do not use `{0}' directly. Use parameter modifier `this' instead", GetSignatureForError ());
+ }
+
/// <summary>
/// This is rather hack. We report many emit attribute error with same error to be compatible with
/// csc. But because csc has to report them this way because error came from ilasm we needn't.
@@ -398,8 +403,8 @@
if (mg == null)
return null;
- MethodBase constructor = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) mg, PosArguments, false, Location);
+ MethodBase constructor = ((MethodGroupExpr)mg).OverloadResolve (
+ ec, PosArguments, false, Location);
if (constructor == null)
return null;
Modified: trunk/mcs/mcs/class.cs
===================================================================
--- trunk/mcs/mcs/class.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/class.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -2859,6 +2859,11 @@
}
}
+ public override ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name)
+ {
+ return NamespaceEntry.LookupExtensionMethod (extensionType, true, name);
+ }
+
protected override TypeAttributes TypeAttr {
get {
if (default_static_constructor == null)
@@ -2918,6 +2923,11 @@
return;
}
+ if (a.Type == TypeManager.extension_attribute_type) {
+ a.Error_MisusedExtensionAttribute ();
+ return;
+ }
+
if (AttributeTester.IsAttributeExcluded (a.Type))
return;
@@ -2969,6 +2979,12 @@
continue;
}
+ Method method = m as Method;
+ if (method != null && method.Parameters.HasExtensionMethodType) {
+ Report.Error (1105, m.Location, "`{0}': Extension methods must be declared static", m.GetSignatureForError ());
+ continue;
+ }
+
Report.Error (708, m.Location, "`{0}': cannot declare instance members in a static class", m.GetSignatureForError ());
}
@@ -2998,6 +3014,14 @@
return base.DoDefineMembers ();
}
+ public override void Emit ()
+ {
+ base.Emit ();
+
+ if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
+ TypeBuilder.SetCustomAttribute (TypeManager.extension_attribute_attr);
+ }
+
public override TypeExpr[] GetClassBases (out TypeExpr base_class)
{
TypeExpr[] ifaces = base.GetClassBases (out base_class);
@@ -4386,6 +4410,11 @@
}
}
+ if (a.Type == TypeManager.extension_attribute_type) {
+ a.Error_MisusedExtensionAttribute ();
+ return;
+ }
+
base.ApplyAttributeBuilder (a, cb);
}
@@ -4457,10 +4486,33 @@
Parent.PartialContainer.Mark_HasGetHashCode ();
}
+ if ((ModFlags & Modifiers.STATIC) == 0)
+ return true;
+
+ if (Parameters.HasExtensionMethodType) {
+ if (Parent.IsStaticClass && !Parent.IsGeneric) {
+ if (!Parent.IsTopLevel)
+ Report.Error (1109, Location, "`{0}': Extension methods cannot be defined in a nested class",
+ GetSignatureForError ());
+
+ if (TypeManager.extension_attribute_type == null)
+ Report.Error (1110, Location,
+ "`{0}': Extension methods cannot be declared without a reference to System.Core.dll assembly. Add the assembly reference or remove `this' modifer from the first parameter",
+ GetSignatureForError ());
+
+ ModFlags |= Modifiers.METHOD_EXTENSION;
+ Parent.ModFlags |= Modifiers.METHOD_EXTENSION;
+ CodeGen.Assembly.HasExtensionMethods = true;
+ } else {
+ Report.Error (1106, Location, "`{0}': Extension methods must be defined in a non-generic static class",
+ GetSignatureForError ());
+ }
+ }
+
//
// This is used to track the Entry Point,
//
- if (RootContext.NeedsEntryPoint && ((ModFlags & Modifiers.STATIC) != 0) &&
+ if (RootContext.NeedsEntryPoint &&
Name == "Main" &&
(RootContext.MainClass == null ||
RootContext.MainClass == Parent.TypeBuilder.FullName)){
@@ -4499,6 +4551,9 @@
MethodData.Emit (Parent);
base.Emit ();
+ if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
+ MethodBuilder.SetCustomAttribute (TypeManager.extension_attribute_attr);
+
Block = null;
MethodData = null;
}
@@ -4609,8 +4664,9 @@
int errors = Report.Errors;
if (base_constructor_group != null)
- base_constructor = (ConstructorInfo) Invocation.OverloadResolve (
- ec, (MethodGroupExpr) base_constructor_group, argument_list,
+ base_constructor = (ConstructorInfo)
+ ((MethodGroupExpr) base_constructor_group).OverloadResolve (
+ ec, argument_list,
false, loc);
if (base_constructor == null) {
@@ -5240,10 +5296,13 @@
// check for public accessibility
//
if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public)
+ {
implementing = null;
+ }
} else if ((flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Private){
// We may never be private.
implementing = null;
+
} else if ((modifiers & Modifiers.OVERRIDE) == 0){
//
// We may be protected if we're overriding something.
@@ -5296,6 +5355,7 @@
if ((modifiers & Modifiers.UNSAFE) != 0)
builder.InitLocals = false;
+
if (implementing != null){
//
// clear the pending implemntation flag
@@ -5312,7 +5372,6 @@
if (member.IsExplicitImpl)
container.TypeBuilder.DefineMethodOverride (
builder, implementing);
-
}
TypeManager.AddMethod (builder, method);
Modified: trunk/mcs/mcs/codegen.cs
===================================================================
--- trunk/mcs/mcs/codegen.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/codegen.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -997,6 +997,7 @@
public AssemblyBuilder Builder;
bool is_cls_compliant;
bool wrap_non_exception_throws;
+ bool has_extension_method;
public Attribute ClsCompliantAttribute;
@@ -1017,6 +1018,10 @@
#endif
}
+ public bool HasExtensionMethods {
+ set { has_extension_method = value; }
+ }
+
public bool IsClsCompliant {
get {
return is_cls_compliant;
@@ -1320,6 +1325,10 @@
return;
}
+ if (a.Type == TypeManager.extension_attribute_type) {
+ a.Error_MisusedExtensionAttribute ();
+ return;
+ }
#endif
Builder.SetCustomAttribute (customBuilder);
}
@@ -1329,6 +1338,9 @@
base.Emit (tc);
#if GMCS_SOURCE
+ if (has_extension_method)
+ Builder.SetCustomAttribute (TypeManager.extension_attribute_attr);
+
// FIXME: Does this belong inside SRE.AssemblyBuilder instead?
if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
ConstructorInfo ci = TypeManager.GetConstructor (
Modified: trunk/mcs/mcs/cs-parser.jay
===================================================================
--- trunk/mcs/mcs/cs-parser.jay 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/cs-parser.jay 2007-02-15 23:22:03 UTC (rev 72971)
@@ -1322,6 +1322,7 @@
parameter_modifier
: REF { $$ = Parameter.Modifier.REF; }
| OUT { $$ = Parameter.Modifier.OUT; }
+ | THIS { $$ = Parameter.Modifier.This; }
;
parameter_array
@@ -1337,7 +1338,12 @@
}
| opt_attributes PARAMS parameter_modifier type IDENTIFIER
{
+ Parameter.Modifier mod = (Parameter.Modifier)$3;
+ if ((mod & Parameter.Modifier.This) != 0) {
+ Report.Error (1104, lexer.Location, "The parameter modifiers `this' and `params' cannot be used altogether");
+ } else {
Report.Error (1611, (Location) $2, "The params parameter cannot be declared as ref or out");
+ }
$$ = null;
}
| opt_attributes PARAMS type error {
Modified: trunk/mcs/mcs/decl.cs
===================================================================
--- trunk/mcs/mcs/decl.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/decl.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -766,6 +766,10 @@
{
return (MemberCore)defined_names [name];
}
+
+ public bool IsStaticClass {
+ get { return (ModFlags & Modifiers.STATIC) != 0; }
+ }
//
// root_types contains all the types. All TopLevel types
@@ -805,7 +809,7 @@
/// Should be overriten by the appropriate declaration space
/// </remarks>
public abstract TypeBuilder DefineType ();
-
+
/// <summary>
/// Define all members, but don't apply any attributes or do anything which may
/// access not-yet-defined classes. This method also creates the MemberCache.
@@ -1059,6 +1063,11 @@
return null;
}
+ public virtual ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name)
+ {
+ return NamespaceEntry.LookupExtensionMethod (extensionType, true, name);
+ }
+
//
// Public function used to locate types.
//
@@ -1857,12 +1866,14 @@
Property = 0x200,
NestedType = 0x400,
+ NotExtensionMethod = 0x800,
+
MaskType = Constructor|Event|Field|Method|Property|NestedType
}
protected class CacheEntry {
public readonly IMemberContainer Container;
- public readonly EntryType EntryType;
+ public EntryType EntryType;
public readonly MemberInfo Member;
public CacheEntry (IMemberContainer container, MemberInfo member,
@@ -2101,6 +2112,46 @@
return null;
}
+
+ //
+ // Looks for extension methods with defined name and extension type
+ //
+ public ArrayList FindExtensionMethods (Type extensionType, string name)
+ {
+ ArrayList entries;
+ if (method_hash != null)
+ entries = (ArrayList)method_hash [name];
+ else
+ entries = (ArrayList)member_hash [name];
+
+ if (entries == null)
+ return null;
+
+ ArrayList candidates = null;
+ foreach (CacheEntry entry in entries) {
+ if ((entry.EntryType & (EntryType.Static | EntryType.Method | EntryType.NotExtensionMethod)) == (EntryType.Static | EntryType.Method)) {
+ MethodBase mb = (MethodBase)entry.Member;
+
+ IMethodData md = TypeManager.GetMethod (mb);
+ ParameterData pd = md == null ?
+ TypeManager.GetParameterData (mb) : md.ParameterInfo;
+
+ Type ex_type = pd.ExtensionMethodType;
+ if (ex_type == null) {
+ entry.EntryType |= EntryType.NotExtensionMethod;
+ continue;
+ }
+
+ if (ex_type == extensionType || TypeManager.IsGenericParameter (ex_type)) {
+ if (candidates == null)
+ candidates = new ArrayList (2);
+ candidates.Add (mb);
+ }
+ }
+ }
+
+ return candidates;
+ }
//
// This finds the method or property for us to override. invocationType is the type where
Modified: trunk/mcs/mcs/doc.cs
===================================================================
--- trunk/mcs/mcs/doc.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/doc.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -366,7 +366,7 @@
static bool IsOverride (PropertyInfo deriv_prop, PropertyInfo base_prop)
{
- if (!Invocation.IsAncestralType (base_prop.DeclaringType, deriv_prop.DeclaringType))
+ if (!MethodGroupExpr.IsAncestralType (base_prop.DeclaringType, deriv_prop.DeclaringType))
return false;
Type [] deriv_pd = TypeManager.GetArgumentTypes (deriv_prop);
@@ -405,7 +405,7 @@
continue;
MethodBase my = ml [j] as MethodBase;
if (mx != null && my != null &&
- Invocation.IsOverride (my, mx)) {
+ MethodGroupExpr.IsOverride (my, mx)) {
overriden = true;
break;
}
Modified: trunk/mcs/mcs/driver.cs
===================================================================
--- trunk/mcs/mcs/driver.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/driver.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -458,12 +458,18 @@
/// </summary>
static public void LoadReferences ()
{
- foreach (string r in references)
- LoadAssembly (r, false);
+ //
+ // Load Core Library for default compilation
+ //
+ if (RootContext.StdLib)
+ LoadAssembly ("mscorlib", false);
foreach (string r in soft_references)
LoadAssembly (r, true);
+ foreach (string r in references)
+ LoadAssembly (r, false);
+
foreach (DictionaryEntry entry in external_aliases)
LoadAssembly ((string) entry.Value, (string) entry.Key, false);
@@ -636,7 +642,7 @@
//
string [] default_config = {
"System",
- "System.Xml",
+ "System.Xml"
#if false
//
// Is it worth pre-loading all this stuff?
@@ -662,6 +668,9 @@
#endif
};
+ if (RootContext.Version == LanguageVersion.LINQ)
+ soft_references.Add ("System.Core");
+
soft_references.AddRange (default_config);
}
@@ -1649,12 +1658,6 @@
if (parse_only)
return true;
- //
- // Load Core Library for default compilation
- //
- if (RootContext.StdLib)
- references.Insert (0, "mscorlib");
-
if (load_default_config)
DefineDefaultConfig ();
Modified: trunk/mcs/mcs/ecore.cs
===================================================================
--- trunk/mcs/mcs/ecore.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/ecore.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -709,10 +709,10 @@
name, AllMemberTypes, AllBindingFlags, loc);
}
- public static Expression MethodLookup (Type container_type, Type queried_type,
+ public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
string name, Location loc)
{
- return MemberLookup (container_type, null, queried_type, name,
+ return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
MemberTypes.Method, AllBindingFlags, loc);
}
@@ -870,8 +870,8 @@
ArrayList arguments = new ArrayList ();
arguments.Add (new Argument (e, Argument.AType.Expression));
- method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) operator_group, arguments, false, loc);
+ method = ((MethodGroupExpr) operator_group).OverloadResolve (
+ ec, arguments, false, loc);
if (method == null)
return null;
@@ -2843,6 +2843,61 @@
}
}
+ ///
+ /// Represents group of extension methods
+ ///
+ public class ExtensionMethodGroupExpr : MethodGroupExpr
+ {
+ NamespaceEntry namespaceEntry;
+ readonly bool usingCandidates;
+
+ public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, bool usingCandidates,
+ Type extensionType, Location l)
+ : base (list, l)
+ {
+ this.namespaceEntry = n;
+ this.usingCandidates = usingCandidates;
+ this.type = extensionType;
+ }
+
+ public override bool IsBase {
+ get { return true; }
+ }
+
+ public override bool IsStatic {
+ get { return true; }
+ }
+
+ public bool IsTopLevel {
+ get { return namespaceEntry == null; }
+ }
+
+ public override MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
+ Expression expr, Location loc)
+ {
+ if (arguments == null)
+ arguments = new ArrayList (1);
+
+ Argument a = new Argument (((MemberAccess)expr).Expr);
+ a.Resolve (ec, loc);
+ arguments.Insert (0, a);
+
+ mg = this;
+ do {
+ MethodBase method = mg.OverloadResolve (ec, arguments, true, loc);
+ if (method != null)
+ return method;
+
+ ExtensionMethodGroupExpr e = namespaceEntry.LookupExtensionMethod (type, usingCandidates, Name);
+ if (e == null)
+ return mg.OverloadResolve (ec, arguments, false, loc);
+
+ mg = e;
+ namespaceEntry = e.namespaceEntry;
+ } while (true);
+ }
+ }
+
/// <summary>
/// MethodGroup Expression.
///
@@ -2917,7 +2972,7 @@
}
}
- public bool IsBase {
+ public virtual bool IsBase {
get {
return is_base;
}
@@ -2957,6 +3012,235 @@
}
}
+ /// <summary>
+ /// Determines "better conversion" as specified in 14.4.2.3
+ ///
+ /// Returns : p if a->p is better,
+ /// q if a->q is better,
+ /// null if neither is better
+ /// </summary>
+ static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
+ {
+ Type argument_type = TypeManager.TypeToCoreType (a.Type);
+ Expression argument_expr = a.Expr;
+
+ if (argument_type == null)
+ throw new Exception ("Expression of type " + a.Expr +
+ " does not resolve its type");
+
+ if (p == null || q == null)
+ throw new InternalErrorException ("BetterConversion Got a null conversion");
+
+ if (p == q)
+ return null;
+
+ if (argument_expr is NullLiteral)
+ {
+ //
+ // If the argument is null and one of the types to compare is 'object' and
+ // the other is a reference type, we prefer the other.
+ //
+ // This follows from the usual rules:
+ // * There is an implicit conversion from 'null' to type 'object'
+ // * There is an implicit conversion from 'null' to any reference type
+ // * There is an implicit conversion from any reference type to type 'object'
+ // * There is no implicit conversion from type 'object' to other reference types
+ // => Conversion of 'null' to a reference type is better than conversion to 'object'
+ //
+ // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
+ // null type. I think it used to be 'object' and thus needed a special
+ // case to avoid the immediately following two checks.
+ //
+ if (!p.IsValueType && q == TypeManager.object_type)
+ return p;
+ if (!q.IsValueType && p == TypeManager.object_type)
+ return q;
+ }
+
+ if (argument_type == p)
+ return p;
+
+ if (argument_type == q)
+ return q;
+
+ Expression p_tmp = new EmptyExpression (p);
+ Expression q_tmp = new EmptyExpression (q);
+
+ bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
+ bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
+
+ if (p_to_q && !q_to_p)
+ return p;
+
+ if (q_to_p && !p_to_q)
+ return q;
+
+ if (p == TypeManager.sbyte_type)
+ if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
+ q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return p;
+ if (q == TypeManager.sbyte_type)
+ if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
+ p == TypeManager.uint32_type || p == TypeManager.uint64_type)
+ return q;
+
+ if (p == TypeManager.short_type)
+ if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
+ q == TypeManager.uint64_type)
+ return p;
+ if (q == TypeManager.short_type)
+ if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
+ p == TypeManager.uint64_type)
+ return q;
+
+ if (p == TypeManager.int32_type)
+ if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return p;
+ if (q == TypeManager.int32_type)
+ if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
+ return q;
+
+ if (p == TypeManager.int64_type)
+ if (q == TypeManager.uint64_type)
+ return p;
+ if (q == TypeManager.int64_type)
+ if (p == TypeManager.uint64_type)
+ return q;
+
+ return null;
+ }
+
+ /// <summary>
+ /// Determines "Better function" between candidate
+ /// and the current best match
+ /// </summary>
+ /// <remarks>
+ /// Returns a boolean indicating :
+ /// false if candidate ain't better
+ /// true if candidate is better than the current best match
+ /// </remarks>
+ static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
+ MethodBase candidate, bool candidate_params,
+ MethodBase best, bool best_params)
+ {
+ ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
+ ParameterData best_pd = TypeManager.GetParameterData (best);
+
+ bool better_at_least_one = false;
+ bool same = true;
+ for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
+ {
+ Argument a = (Argument) args [j];
+
+ Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
+ Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
+
+ if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS)
+ {
+ ct = TypeManager.GetElementType (ct);
+ --c_idx;
+ }
+
+ if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS)
+ {
+ bt = TypeManager.GetElementType (bt);
+ --b_idx;
+ }
+
+ if (ct.Equals (bt))
+ continue;
+
+ same = false;
+ Type better = BetterConversion (ec, a, ct, bt);
+
+ // for each argument, the conversion to 'ct' should be no worse than
+ // the conversion to 'bt'.
+ if (better == bt)
+ return false;
+
+ // for at least one argument, the conversion to 'ct' should be better than
+ // the conversion to 'bt'.
+ if (better == ct)
+ better_at_least_one = true;
+ }
+
+ if (better_at_least_one)
+ return true;
+
+ //
+ // 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.
+ //
+ if (!same)
+ return false;
+
+ //
+ // The two methods have equal parameter types. Now apply tie-breaking rules
+ //
+ if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
+ return true;
+ if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
+ return false;
+
+ //
+ // 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)
+ // Foo (int, params int [] rest) is better than Foo (params int [] rest)
+ //
+ if (!candidate_params && best_params)
+ return true;
+ if (candidate_params && !best_params)
+ return false;
+
+ int candidate_param_count = candidate_pd.Count;
+ int best_param_count = best_pd.Count;
+
+ if (candidate_param_count != best_param_count)
+ // can only happen if (candidate_params && best_params)
+ return candidate_param_count > best_param_count;
+
+ //
+ // now, both methods have the same number of parameters, and the parameters have the same types
+ // Pick the "more specific" signature
+ //
+
+ MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
+ MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
+
+ ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
+ ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
+
+ bool specific_at_least_once = false;
+ for (int j = 0; j < candidate_param_count; ++j)
+ {
+ Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
+ Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
+ if (ct.Equals (bt))
+ continue;
+ Type specific = MoreSpecific (ct, bt);
+ if (specific == bt)
+ return false;
+ if (specific == ct)
+ specific_at_least_once = true;
+ }
+
+ if (specific_at_least_once)
+ return true;
+
+ // FIXME: handle lifted operators
+ // ...
+
+ return false;
+ }
+
public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
SimpleName original)
{
@@ -2992,6 +3276,444 @@
ReportUsageError ();
}
+ public static bool IsAncestralType (Type first_type, Type second_type)
+ {
+ return first_type != second_type &&
+ (TypeManager.IsSubclassOf (second_type, first_type) ||
+ TypeManager.ImplementsInterface (second_type, first_type));
+ }
+
+ public 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 true;
+ }
+
+ static Type MoreSpecific (Type p, Type q)
+ {
+ if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
+ return q;
+ if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
+ return p;
+
+ if (TypeManager.HasElementType (p))
+ {
+ Type pe = TypeManager.GetElementType (p);
+ Type qe = TypeManager.GetElementType (q);
+ Type specific = MoreSpecific (pe, qe);
+ if (specific == pe)
+ return p;
+ if (specific == qe)
+ return q;
+ }
+ else if (TypeManager.IsGenericType (p))
+ {
+ Type[] pargs = TypeManager.GetTypeArguments (p);
+ Type[] qargs = TypeManager.GetTypeArguments (q);
+
+ bool p_specific_at_least_once = false;
+ bool q_specific_at_least_once = false;
+
+ for (int i = 0; i < pargs.Length; i++)
+ {
+ Type specific = MoreSpecific (pargs [i], qargs [i]);
+ if (specific == pargs [i])
+ p_specific_at_least_once = true;
+ if (specific == qargs [i])
+ q_specific_at_least_once = true;
+ }
+
+ if (p_specific_at_least_once && !q_specific_at_least_once)
+ return p;
+ if (!p_specific_at_least_once && q_specific_at_least_once)
+ return q;
+ }
+
+ return null;
+ }
+
+ public virtual MethodBase OverloadExtensionResolve (EmitContext ec, ref ArrayList arguments, ref MethodGroupExpr mg,
+ Expression expr, Location loc)
+ {
+ MethodBase method = OverloadResolve (ec, arguments, true, loc);
+ if (method != null) {
+ mg = this;
+ return method;
+ }
+
+ MemberAccess mexpr = expr as MemberAccess;
+ if (mexpr != null) {
+ ExtensionMethodGroupExpr emg = ec.DeclContainer.LookupExtensionMethod (mexpr.Expr.Type, Name);
+ if (emg != null) {
+ return OverloadExtensionResolve (ec, ref arguments, ref mg, expr, loc);
+ }
+ }
+
+ return OverloadResolve (ec, arguments, false, loc);
+ }
+
+ /// <summary>
+ /// Find the Applicable Function Members (7.4.2.1)
+ ///
+ /// me: Method Group expression with the members to select.
+ /// it might contain constructors or methods (or anything
+ /// that maps to a method).
+ ///
+ /// Arguments: ArrayList containing resolved Argument objects.
+ ///
+ /// loc: The location if we want an error to be reported, or a Null
+ /// location for "probing" purposes.
+ ///
+ /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+ /// that is the best match of me on Arguments.
+ ///
+ /// </summary>
+ public virtual MethodBase OverloadResolve (EmitContext ec, ArrayList Arguments,
+ bool may_fail, Location loc)
+ {
+ MethodBase method = null;
+ bool method_params = false;
+ Type applicable_type = null;
+ int arg_count = 0;
+ ArrayList candidates = new ArrayList (2);
+ ArrayList candidate_overrides = null;
+
+ //
+ // Used to keep a map between the candidate
+ // and whether it is being considered in its
+ // normal or expanded form
+ //
+ // false is normal form, true is expanded form
+ //
+ Hashtable candidate_to_form = null;
+
+ if (Arguments != null)
+ arg_count = Arguments.Count;
+
+ if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
+ if (!may_fail)
+ Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
+ return null;
+ }
+
+ int nmethods = Methods.Length;
+
+ if (!IsBase) {
+ //
+ // 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.
+ // So, we salt them away into the 'candidate_overrides' array.
+ //
+ // In case of reflected methods, we replace each overriding method with
+ // its corresponding base virtual method. This is to improve compatibility
+ // with non-C# libraries which change the visibility of overrides (#75636)
+ //
+ int j = 0;
+ for (int i = 0; i < Methods.Length; ++i) {
+ MethodBase m = Methods [i];
+#if GMCS_SOURCE
+ Type [] gen_args = null;
+ if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
+ gen_args = m.GetGenericArguments ();
+#endif
+ if (TypeManager.IsOverride (m)) {
+ if (candidate_overrides == null)
+ candidate_overrides = new ArrayList ();
+ candidate_overrides.Add (m);
+ m = TypeManager.TryGetBaseDefinition (m);
+#if GMCS_SOURCE
+ if (m != null && gen_args != null) {
+ if (!m.IsGenericMethodDefinition)
+ throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
+ m = ((MethodInfo) m).MakeGenericMethod (gen_args);
+ }
+#endif
+ }
+ if (m != null)
+ Methods [j++] = m;
+ }
+ nmethods = j;
+ }
+
+ int applicable_errors = Report.Errors;
+
+ //
+ // First we construct the set of applicable methods
+ //
+ bool is_sorted = true;
+ for (int i = 0; i < nmethods; i++) {
+ Type decl_type = Methods [i].DeclaringType;
+
+ //
+ // If we have already found an applicable method
+ // we eliminate all base types (Section 14.5.5.1)
+ //
+ if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
+ continue;
+
+ //
+ // Check if candidate is applicable (section 14.4.2.1)
+ // Is candidate applicable in normal form?
+ //
+ bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]);
+
+ if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) {
+ MethodBase candidate = Methods [i];
+ if (candidate_to_form == null)
+ candidate_to_form = new PtrHashtable ();
+ candidate_to_form [candidate] = candidate;
+ // Candidate is applicable in expanded form
+ is_applicable = true;
+ }
+
+ if (!is_applicable)
+ continue;
+
+ candidates.Add (Methods [i]);
+
+ if (applicable_type == null)
+ applicable_type = decl_type;
+ else if (applicable_type != decl_type) {
+ is_sorted = false;
+ if (IsAncestralType (applicable_type, decl_type))
+ applicable_type = decl_type;
+ }
+ }
+
+ if (applicable_errors != Report.Errors)
+ return null;
+
+ int candidate_top = candidates.Count;
+
+ if (applicable_type == null) {
+ //
+ // Okay so we have failed to find anything so we
+ // return by providing info about the closest match
+ //
+ int errors = Report.Errors;
+ for (int i = 0; i < nmethods; ++i) {
+ MethodBase c = Methods [i];
+ ParameterData pd = TypeManager.GetParameterData (c);
+
+ if (pd.Count != arg_count)
+ continue;
+
+#if GMCS_SOURCE
+ if (!TypeManager.InferTypeArguments (Arguments, ref c))
+ continue;
+ if (TypeManager.IsGenericMethodDefinition (c))
+ continue;
+#endif
+
+ Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count,
+ c, false, null, may_fail, loc);
+
+ if (!may_fail && errors == Report.Errors)
+ throw new InternalErrorException (
+ "VerifyArgumentsCompat and IsApplicable do not agree; " +
+ "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
+
+ break;
+ }
+
+ if (!may_fail && errors == Report.Errors) {
+ string report_name = Name;
+ if (report_name == ".ctor")
+ report_name = TypeManager.CSharpName (DeclaringType);
+
+#if GMCS_SOURCE
+ //
+ // Type inference
+ //
+ for (int i = 0; i < Methods.Length; ++i) {
+ MethodBase c = Methods [i];
+ ParameterData pd = TypeManager.GetParameterData (c);
+
+ if (pd.Count != arg_count)
+ continue;
+
+ if (TypeManager.InferTypeArguments (Arguments, ref c))
+ continue;
+
+ Report.Error (
+ 411, loc, "The type arguments for " +
+ "method `{0}' cannot be inferred from " +
+ "the usage. Try specifying the type " +
+ "arguments explicitly.", report_name);
+ return null;
+ }
+#endif
+
+ Invocation.Error_WrongNumArguments (loc, report_name, arg_count);
+ }
+
+ return null;
+ }
+
+ if (!is_sorted) {
+ //
+ // At this point, applicable_type is _one_ of the most derived types
+ // in the set of types containing the methods in this MethodGroup.
+ // Filter the candidates so that they only contain methods from the
+ // most derived types.
+ //
+
+ int finalized = 0; // Number of finalized candidates
+
+ do {
+ // Invariant: applicable_type is a most derived type
+
+ // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
+ // eliminating all it's base types. At the same time, we'll also move
+ // every unrelated type to the end of the array, and pick the next
+ // 'applicable_type'.
+
+ Type next_applicable_type = null;
+ 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) {
+ MethodBase candidate = (MethodBase) candidates [i];
+ Type decl_type = candidate.DeclaringType;
+
+ if (decl_type == applicable_type) {
+ candidates [k++] = candidates [j];
+ candidates [j++] = candidates [i];
+ continue;
+ }
+
+ if (IsAncestralType (decl_type, applicable_type))
+ continue;
+
+ if (next_applicable_type != null &&
+ IsAncestralType (decl_type, next_applicable_type))
+ continue;
+
+ candidates [k++] = candidates [i];
+
+ if (next_applicable_type == null ||
+ IsAncestralType (next_applicable_type, decl_type))
+ next_applicable_type = decl_type;
+ }
+
+ applicable_type = next_applicable_type;
+ finalized = j;
+ candidate_top = k;
+ } while (applicable_type != null);
+ }
+
+ //
+ // Now we actually find the best method
+ //
+
+ 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,
+ candidate, cand_params,
+ method, method_params)) {
+ method = candidate;
+ method_params = cand_params;
+ }
+ }
+ //
+ // Now check that there are no ambiguities i.e the selected method
+ // should be better than all the others
+ //
+ MethodBase ambiguous = null;
+ for (int ix = 0; 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,
+ method, method_params,
+ candidate, cand_params))
+ {
+ if (!may_fail)
+ Report.SymbolRelatedToPreviousError (candidate);
+ ambiguous = candidate;
+ }
+ }
+
+ if (ambiguous != null) {
+ Report.SymbolRelatedToPreviousError (method);
+ Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
+ TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
+ return method;
+ }
+
+ //
+ // If the method is a virtual function, pick an override closer to the LHS type.
+ //
+ if (!IsBase && method.IsVirtual) {
+ if (TypeManager.IsOverride (method))
+ throw new InternalErrorException (
+ "Should not happen. An 'override' method took part in overload resolution: " + method);
+
+ if (candidate_overrides != null)
+ foreach (MethodBase candidate in candidate_overrides) {
+ if (IsOverride (candidate, method))
+ method = candidate;
+ }
+ }
+
+ //
+ // And now check if the arguments are all
+ // compatible, perform conversions if
+ // necessary etc. and return if everything is
+ // all right
+ //
+ if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, method,
+ method_params, null, may_fail, loc))
+ return null;
+
+ if (method == null)
+ return null;
+
+ MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
+#if GMCS_SOURCE
+ if (the_method.IsGenericMethodDefinition &&
+ !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
+ return null;
+#endif
+
+ IMethodData data = TypeManager.GetMethod (the_method);
+ if (data != null)
+ data.SetMemberIsUsed ();
+
+ return method;
+ }
+
+
bool RemoveMethods (bool keep_static)
{
ArrayList smethods = new ArrayList ();
Modified: trunk/mcs/mcs/expression.cs
===================================================================
--- trunk/mcs/mcs/expression.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/expression.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -67,8 +67,8 @@
return null;
args.Add (a);
- method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) mg, args, false, loc);
+ method = mg.OverloadResolve (
+ ec, args, false, loc);
if (method == null)
return null;
@@ -1782,7 +1782,7 @@
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
- MethodBase method = Invocation.OverloadResolve (ec, union, args, true, Location.Null);
+ MethodBase method = union.OverloadResolve (ec, args, true, Location.Null);
if (method != null) {
MethodInfo mi = (MethodInfo) method;
@@ -1922,8 +1922,8 @@
ArrayList args = new ArrayList (2);
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (left, Argument.AType.Expression));
- MethodBase method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) left_operators, args, true, Location.Null);
+ MethodBase method = ((MethodGroupExpr)left_operators).OverloadResolve (
+ ec, args, true, Location.Null);
if (method != null)
Warning_UnintendedReferenceComparison (loc, "right", l);
}
@@ -1933,8 +1933,8 @@
ArrayList args = new ArrayList (2);
args.Add (new Argument (right, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
- MethodBase method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) right_operators, args, true, Location.Null);
+ MethodBase method = ((MethodGroupExpr)right_operators).OverloadResolve (
+ ec, args, true, Location.Null);
if (method != null)
Warning_UnintendedReferenceComparison (loc, "left", r);
}
@@ -2229,7 +2229,7 @@
ArrayList args = new ArrayList (2);
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
- MethodBase method = Invocation.OverloadResolve (ec, ops, args, true, Location.Null);
+ MethodBase method = ops.OverloadResolve (ec, args, true, Location.Null);
return new BinaryMethod (type, method, args);
}
@@ -3100,8 +3100,8 @@
ArrayList arguments = new ArrayList (2);
arguments.Add (new Argument (left_temp, Argument.AType.Expression));
arguments.Add (new Argument (right, Argument.AType.Expression));
- method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) operator_group, arguments, false, loc)
+ method = ((MethodGroupExpr) operator_group).OverloadResolve (
+ ec, arguments, false, loc)
as MethodInfo;
if (method == null) {
Error19 ();
@@ -4007,293 +4007,6 @@
}
}
- /// <summary>
- /// Determines "better conversion" as specified in 14.4.2.3
- ///
- /// Returns : p if a->p is better,
- /// q if a->q is better,
- /// null if neither is better
- /// </summary>
- static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
- {
- Type argument_type = TypeManager.TypeToCoreType (a.Type);
- Expression argument_expr = a.Expr;
-
- if (argument_type == null)
- throw new Exception ("Expression of type " + a.Expr +
- " does not resolve its type");
-
- if (p == null || q == null)
- throw new InternalErrorException ("BetterConversion Got a null conversion");
-
- if (p == q)
- return null;
-
- if (argument_expr is NullLiteral) {
- //
- // If the argument is null and one of the types to compare is 'object' and
- // the other is a reference type, we prefer the other.
- //
- // This follows from the usual rules:
- // * There is an implicit conversion from 'null' to type 'object'
- // * There is an implicit conversion from 'null' to any reference type
- // * There is an implicit conversion from any reference type to type 'object'
- // * There is no implicit conversion from type 'object' to other reference types
- // => Conversion of 'null' to a reference type is better than conversion to 'object'
- //
- // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
- // null type. I think it used to be 'object' and thus needed a special
- // case to avoid the immediately following two checks.
- //
- if (!p.IsValueType && q == TypeManager.object_type)
- return p;
- if (!q.IsValueType && p == TypeManager.object_type)
- return q;
- }
-
- if (argument_type == p)
- return p;
-
- if (argument_type == q)
- return q;
-
- Expression p_tmp = new EmptyExpression (p);
- Expression q_tmp = new EmptyExpression (q);
-
- bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
- bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
-
- if (p_to_q && !q_to_p)
- return p;
-
- if (q_to_p && !p_to_q)
- return q;
-
- if (p == TypeManager.sbyte_type)
- if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
- q == TypeManager.uint32_type || q == TypeManager.uint64_type)
- return p;
- if (q == TypeManager.sbyte_type)
- if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
- p == TypeManager.uint32_type || p == TypeManager.uint64_type)
- return q;
-
- if (p == TypeManager.short_type)
- if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
- q == TypeManager.uint64_type)
- return p;
- if (q == TypeManager.short_type)
- if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
- p == TypeManager.uint64_type)
- return q;
-
- if (p == TypeManager.int32_type)
- if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
- return p;
- if (q == TypeManager.int32_type)
- if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
- return q;
-
- if (p == TypeManager.int64_type)
- if (q == TypeManager.uint64_type)
- return p;
- if (q == TypeManager.int64_type)
- if (p == TypeManager.uint64_type)
- return q;
-
- return null;
- }
-
- static Type MoreSpecific (Type p, Type q)
- {
- if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
- return q;
- if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
- return p;
-
- if (TypeManager.HasElementType (p)) {
- Type pe = TypeManager.GetElementType (p);
- Type qe = TypeManager.GetElementType (q);
- Type specific = MoreSpecific (pe, qe);
- if (specific == pe)
- return p;
- if (specific == qe)
- return q;
- } else if (TypeManager.IsGenericType (p)) {
- Type[] pargs = TypeManager.GetTypeArguments (p);
- Type[] qargs = TypeManager.GetTypeArguments (q);
-
- bool p_specific_at_least_once = false;
- bool q_specific_at_least_once = false;
-
- for (int i = 0; i < pargs.Length; i++) {
- Type specific = MoreSpecific (pargs [i], qargs [i]);
- if (specific == pargs [i])
- p_specific_at_least_once = true;
- if (specific == qargs [i])
- q_specific_at_least_once = true;
- }
-
- if (p_specific_at_least_once && !q_specific_at_least_once)
- return p;
- if (!p_specific_at_least_once && q_specific_at_least_once)
- return q;
- }
-
- return null;
- }
-
- /// <summary>
- /// Determines "Better function" between candidate
- /// and the current best match
- /// </summary>
- /// <remarks>
- /// Returns a boolean indicating :
- /// false if candidate ain't better
- /// true if candidate is better than the current best match
- /// </remarks>
- static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
- MethodBase candidate, bool candidate_params,
- MethodBase best, bool best_params)
- {
- ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
- ParameterData best_pd = TypeManager.GetParameterData (best);
-
- bool better_at_least_one = false;
- bool same = true;
- for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx) {
- Argument a = (Argument) args [j];
-
- Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
- Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
-
- if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS) {
- ct = TypeManager.GetElementType (ct);
- --c_idx;
- }
-
- if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS) {
- bt = TypeManager.GetElementType (bt);
- --b_idx;
- }
-
- if (ct.Equals (bt))
- continue;
-
- same = false;
- Type better = BetterConversion (ec, a, ct, bt);
-
- // for each argument, the conversion to 'ct' should be no worse than
- // the conversion to 'bt'.
- if (better == bt)
- return false;
-
- // for at least one argument, the conversion to 'ct' should be better than
- // the conversion to 'bt'.
- if (better == ct)
- better_at_least_one = true;
- }
-
- if (better_at_least_one)
- return true;
-
- //
- // 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.
- //
- if (!same)
- return false;
-
- //
- // The two methods have equal parameter types. Now apply tie-breaking rules
- //
- if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
- return true;
- if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
- return false;
-
- //
- // 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)
- // Foo (int, params int [] rest) is better than Foo (params int [] rest)
- //
- if (!candidate_params && best_params)
- return true;
- if (candidate_params && !best_params)
- return false;
-
- int candidate_param_count = candidate_pd.Count;
- int best_param_count = best_pd.Count;
-
- if (candidate_param_count != best_param_count)
- // can only happen if (candidate_params && best_params)
- return candidate_param_count > best_param_count;
-
- //
- // now, both methods have the same number of parameters, and the parameters have the same types
- // Pick the "more specific" signature
- //
-
- MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
- MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
-
- ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
- ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
-
- bool specific_at_least_once = false;
- for (int j = 0; j < candidate_param_count; ++j) {
- Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
- Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
- if (ct.Equals (bt))
- continue;
- Type specific = MoreSpecific (ct, bt);
- if (specific == bt)
- return false;
- if (specific == ct)
- specific_at_least_once = true;
- }
-
- if (specific_at_least_once)
- return true;
-
- // FIXME: handle lifted operators
- // ...
-
- return false;
- }
-
- internal 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 true;
- }
-
public static string FullMethodDesc (MethodBase mb)
{
if (mb == null)
@@ -4540,355 +4253,6 @@
return true;
}
- static internal bool IsAncestralType (Type first_type, Type second_type)
- {
- return first_type != second_type &&
- (TypeManager.IsSubclassOf (second_type, first_type) ||
- TypeManager.ImplementsInterface (second_type, first_type));
- }
-
- /// <summary>
- /// Find the Applicable Function Members (7.4.2.1)
- ///
- /// me: Method Group expression with the members to select.
- /// it might contain constructors or methods (or anything
- /// that maps to a method).
- ///
- /// Arguments: ArrayList containing resolved Argument objects.
- ///
- /// loc: The location if we want an error to be reported, or a Null
- /// location for "probing" purposes.
- ///
- /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
- /// that is the best match of me on Arguments.
- ///
- /// </summary>
- public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
- ArrayList Arguments, bool may_fail,
- Location loc)
- {
- MethodBase method = null;
- bool method_params = false;
- Type applicable_type = null;
- int arg_count = 0;
- ArrayList candidates = new ArrayList (2);
- ArrayList candidate_overrides = null;
-
- //
- // Used to keep a map between the candidate
- // and whether it is being considered in its
- // normal or expanded form
- //
- // false is normal form, true is expanded form
- //
- Hashtable candidate_to_form = null;
-
- if (Arguments != null)
- arg_count = Arguments.Count;
-
- // This error was reported by csc 1.x only
- // if (me.Name == "Invoke" && TypeManager.IsDelegateType (me.DeclaringType)) {
- // Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
- // }
-
- MethodBase[] methods = me.Methods;
-
- int nmethods = methods.Length;
-
- if (!me.IsBase) {
- //
- // 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.
- // So, we salt them away into the 'candidate_overrides' array.
- //
- // In case of reflected methods, we replace each overriding method with
- // its corresponding base virtual method. This is to improve compatibility
- // with non-C# libraries which change the visibility of overrides (#75636)
- //
- int j = 0;
- for (int i = 0; i < methods.Length; ++i) {
- MethodBase m = methods [i];
-#if GMCS_SOURCE
- Type [] gen_args = null;
- if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
- gen_args = m.GetGenericArguments ();
-#endif
- if (TypeManager.IsOverride (m)) {
- if (candidate_overrides == null)
- candidate_overrides = new ArrayList ();
- candidate_overrides.Add (m);
- m = TypeManager.TryGetBaseDefinition (m);
-#if GMCS_SOURCE
- if (m != null && gen_args != null) {
- if (!m.IsGenericMethodDefinition)
- throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
- m = ((MethodInfo) m).MakeGenericMethod (gen_args);
- }
-#endif
- }
- if (m != null)
- methods [j++] = m;
- }
- nmethods = j;
- }
-
- int applicable_errors = Report.Errors;
-
- //
- // First we construct the set of applicable methods
- //
- bool is_sorted = true;
- for (int i = 0; i < nmethods; i++){
- Type decl_type = methods [i].DeclaringType;
-
- //
- // If we have already found an applicable method
- // we eliminate all base types (Section 14.5.5.1)
- //
- if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
- continue;
-
- //
- // Check if candidate is applicable (section 14.4.2.1)
- // Is candidate applicable in normal form?
- //
- bool is_applicable = IsApplicable (ec, me, Arguments, arg_count, ref methods [i]);
-
- if (!is_applicable && IsParamsMethodApplicable (ec, me, Arguments, arg_count, ref methods [i])) {
- MethodBase candidate = methods [i];
- if (candidate_to_form == null)
- candidate_to_form = new PtrHashtable ();
- candidate_to_form [candidate] = candidate;
- // Candidate is applicable in expanded form
- is_applicable = true;
- }
-
- if (!is_applicable)
- continue;
-
- candidates.Add (methods [i]);
-
- if (applicable_type == null)
- applicable_type = decl_type;
- else if (applicable_type != decl_type) {
- is_sorted = false;
- if (IsAncestralType (applicable_type, decl_type))
- applicable_type = decl_type;
- }
- }
-
- if (applicable_errors != Report.Errors)
- return null;
-
- int candidate_top = candidates.Count;
-
- if (applicable_type == null) {
- //
- // Okay so we have failed to find anything so we
- // return by providing info about the closest match
- //
- int errors = Report.Errors;
- for (int i = 0; i < nmethods; ++i) {
- MethodBase c = (MethodBase) methods [i];
- ParameterData pd = TypeManager.GetParameterData (c);
-
- if (pd.Count != arg_count)
- continue;
-
-#if GMCS_SOURCE
- if (!TypeManager.InferTypeArguments (Arguments, ref c))
- continue;
- if (TypeManager.IsGenericMethodDefinition (c))
- continue;
-#endif
-
- VerifyArgumentsCompat (ec, Arguments, arg_count,
- c, false, null, may_fail, loc);
-
- if (!may_fail && errors == Report.Errors)
- throw new InternalErrorException (
- "VerifyArgumentsCompat and IsApplicable do not agree; " +
- "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
-
- break;
- }
-
- if (!may_fail && errors == Report.Errors) {
- string report_name = me.Name;
- if (report_name == ".ctor")
- report_name = TypeManager.CSharpName (me.DeclaringType);
-
-#if GMCS_SOURCE
- //
- // Type inference
- //
- for (int i = 0; i < methods.Length; ++i) {
- MethodBase c = methods [i];
- ParameterData pd = TypeManager.GetParameterData (c);
-
- if (pd.Count != arg_count)
- continue;
-
- if (TypeManager.InferTypeArguments (Arguments, ref c))
- continue;
-
- Report.Error (
- 411, loc, "The type arguments for " +
- "method `{0}' cannot be inferred from " +
- "the usage. Try specifying the type " +
- "arguments explicitly.", report_name);
- return null;
- }
-#endif
-
- Error_WrongNumArguments (loc, report_name, arg_count);
- }
-
- return null;
- }
-
- if (!is_sorted) {
- //
- // At this point, applicable_type is _one_ of the most derived types
- // in the set of types containing the methods in this MethodGroup.
- // Filter the candidates so that they only contain methods from the
- // most derived types.
- //
-
- int finalized = 0; // Number of finalized candidates
-
- do {
- // Invariant: applicable_type is a most derived type
-
- // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
- // eliminating all it's base types. At the same time, we'll also move
- // every unrelated type to the end of the array, and pick the next
- // 'applicable_type'.
-
- Type next_applicable_type = null;
- 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) {
- MethodBase candidate = (MethodBase) candidates [i];
- Type decl_type = candidate.DeclaringType;
-
- if (decl_type == applicable_type) {
- candidates [k++] = candidates [j];
- candidates [j++] = candidates [i];
- continue;
- }
-
- if (IsAncestralType (decl_type, applicable_type))
- continue;
-
- if (next_applicable_type != null &&
- IsAncestralType (decl_type, next_applicable_type))
- continue;
-
- candidates [k++] = candidates [i];
-
- if (next_applicable_type == null ||
- IsAncestralType (next_applicable_type, decl_type))
- next_applicable_type = decl_type;
- }
-
- applicable_type = next_applicable_type;
- finalized = j;
- candidate_top = k;
- } while (applicable_type != null);
- }
-
- //
- // Now we actually find the best method
- //
-
- 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,
- candidate, cand_params,
- method, method_params)) {
- method = candidate;
- method_params = cand_params;
- }
- }
- //
- // Now check that there are no ambiguities i.e the selected method
- // should be better than all the others
- //
- MethodBase ambiguous = null;
- for (int ix = 0; 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,
- method, method_params,
- candidate, cand_params)) {
- Report.SymbolRelatedToPreviousError (candidate);
- ambiguous = candidate;
- }
- }
-
- if (ambiguous != null) {
- Report.SymbolRelatedToPreviousError (method);
- Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
- TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
- return null;
- }
-
- //
- // If the method is a virtual function, pick an override closer to the LHS type.
- //
- if (!me.IsBase && method.IsVirtual) {
- if (TypeManager.IsOverride (method))
- throw new InternalErrorException (
- "Should not happen. An 'override' method took part in overload resolution: " + method);
-
- if (candidate_overrides != null)
- foreach (MethodBase candidate in candidate_overrides) {
- if (IsOverride (candidate, method))
- method = candidate;
- }
- }
-
- //
- // And now check if the arguments are all
- // compatible, perform conversions if
- // necessary etc. and return if everything is
- // all right
- //
- if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
- method_params, null, may_fail, loc))
- return null;
-
- if (method == null)
- return null;
-
- MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
-#if GMCS_SOURCE
- if (the_method.IsGenericMethodDefinition &&
- !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
- return null;
-#endif
-
- IMethodData data = TypeManager.GetMethod (the_method);
- if (data != null)
- data.SetMemberIsUsed ();
-
- return method;
- }
-
public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
{
Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
@@ -4983,7 +4347,8 @@
break;
if (parameter_type.IsPointer && !ec.InUnsafe) {
- UnsafeError (loc);
+ if (!may_fail)
+ UnsafeError (loc);
return false;
}
}
@@ -5011,22 +4376,18 @@
if (sn != null)
expr = sn.GetMethodGroup ();
- expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
- if (expr == null)
+ Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ if (expr_resolved == null)
return null;
- if (!(expr is MethodGroupExpr)) {
- Type expr_type = expr.Type;
+ MethodGroupExpr mg = expr_resolved as MethodGroupExpr;
+ if (mg == null) {
+ Type expr_type = expr_resolved.Type;
- if (expr_type != null){
- bool IsDelegate = TypeManager.IsDelegateType (expr_type);
- if (IsDelegate)
- return (new DelegateInvocation (
- this.expr, Arguments, loc)).Resolve (ec);
+ if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
+ return (new DelegateInvocation (
+ expr_resolved, Arguments, loc)).Resolve (ec);
}
- }
-
- if (!(expr is MethodGroupExpr)){
expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
return null;
}
@@ -5041,12 +4402,12 @@
}
}
- MethodGroupExpr mg = (MethodGroupExpr) expr;
- MethodBase method = OverloadResolve (ec, mg, Arguments, false, loc);
-
+ MethodBase method = mg.OverloadExtensionResolve (ec, ref Arguments, ref mg, expr, loc);
if (method == null)
return null;
+ expr = mg;
+
MethodInfo mi = method as MethodInfo;
if (mi != null) {
type = TypeManager.TypeToCoreType (mi.ReturnType);
@@ -5842,7 +5203,7 @@
}
}
- method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
+ method = mg.OverloadResolve (ec, Arguments, false, loc);
if (method == null) {
if (almostMatchedMembers.Count != 0)
MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
@@ -6322,8 +5683,8 @@
return null;
}
- new_method = Invocation.OverloadResolve (
- ec, (MethodGroupExpr) ml, arguments, false, loc);
+ new_method = ((MethodGroupExpr) ml).OverloadResolve (
+ ec, arguments, false, loc);
if (new_method == null) {
Error (-6, "New invocation: Can not find a constructor for " +
@@ -7392,6 +6753,10 @@
}
#endif
if (member_lookup == null) {
+ member_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
+ if (member_lookup != null)
+ return member_lookup.DoResolve (ec);
+
MemberLookupFailed (
ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
return null;
@@ -8387,7 +7752,7 @@
return null;
}
- get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
+ get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
arguments, false, loc);
if (get == null) {
@@ -8448,8 +7813,8 @@
found_any_setters = true;
set_arguments = (ArrayList) arguments.Clone ();
set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
- set = (MethodInfo) Invocation.OverloadResolve (
- ec, new MethodGroupExpr (AllSetters, loc),
+ set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
+ ec,
set_arguments, false, loc);
}
Modified: trunk/mcs/mcs/modifiers.cs
===================================================================
--- trunk/mcs/mcs/modifiers.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/modifiers.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -28,14 +28,15 @@
public const int TOP = 0x2000;
public const int PROPERTY_CUSTOM = 0x4000; // Custom property modifier
- public const int PARTIAL = 0x20000;
- public const int DEFAULT_ACCESS_MODIFER = 0x40000;
//
// We use this internally to flag that the method contains an iterator
//
- public const int METHOD_YIELDS = 0x8000;
- public const int METHOD_GENERIC = 0x10000;
+ public const int METHOD_YIELDS = 0x8000;
+ public const int METHOD_GENERIC = 0x10000;
+ public const int PARTIAL = 0x20000;
+ public const int DEFAULT_ACCESS_MODIFER = 0x40000;
+ public const int METHOD_EXTENSION = 0x80000;
public const int Accessibility =
PUBLIC | PROTECTED | INTERNAL | PRIVATE;
Modified: trunk/mcs/mcs/namespace.cs
===================================================================
--- trunk/mcs/mcs/namespace.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/namespace.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -90,19 +90,44 @@
GetNamespace (dotted_name, true);
}
- protected void ComputeNamespaces (Assembly assembly)
- {
- if (get_namespaces_method != null) {
- string [] namespaces = (string []) get_namespaces_method.Invoke (assembly, null);
- foreach (string ns in namespaces)
- RegisterNamespace (ns);
- return;
- }
+ void RegisterExtensionMethodClass (Type t)
+ {
+ string n = t.Namespace;
+ Namespace ns = n == null ? Global : (Namespace)all_namespaces [n];
+ if (ns == null)
+ ns = GetNamespace (n, true);
+
+ ns.RegisterExternalExtensionMethodClass (t);
+ }
- foreach (Type t in assembly.GetExportedTypes ())
- RegisterNamespace (t.Namespace);
- }
-
+ protected void ComputeNamespaces (Assembly assembly)
+ {
+ // How to test whether attribute exists without loading the assembly :-(
+ const string SystemCore = "System.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
+ if (TypeManager.extension_attribute_type == null &&
+ assembly.FullName == SystemCore) {
+ TypeManager.extension_attribute_type = assembly.GetType("System.Runtime.CompilerServices.ExtensionAttribute");
+ }
+
+ bool contains_extension_methods = TypeManager.extension_attribute_type != null &&
+ assembly.IsDefined(TypeManager.extension_attribute_type, false);
+
+ if (get_namespaces_method != null && !contains_extension_methods) {
+ string [] namespaces = (string []) get_namespaces_method.Invoke (assembly, null);
+ foreach (string ns in namespaces)
+ RegisterNamespace (ns);
+ return;
+ }
+
+ foreach (Type t in assembly.GetExportedTypes ()) {
+ if ((t.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
+ contains_extension_methods && t.IsDefined (TypeManager.extension_attribute_type, false))
+ RegisterExtensionMethodClass (t);
+ else
+ RegisterNamespace (t.Namespace);
+ }
+ }
+
protected static Type GetTypeInAssembly (Assembly assembly, string name)
{
Type t = assembly.GetType (name);
@@ -256,6 +281,7 @@
IDictionary declspaces;
Hashtable cached_types;
RootNamespace root;
+ ArrayList external_exmethod_classes;
public readonly MemberName MemberName;
@@ -444,6 +470,58 @@
return te;
}
+ public void RegisterExternalExtensionMethodClass (Type type)
+ {
+ if (external_exmethod_classes == null)
+ external_exmethod_classes = new ArrayList ();
+
+ external_exmethod_classes.Add (type);
+ }
+
+ ///
+ /// Looks for extension method in this namespace
+ ///
+ public ArrayList LookupExtensionMethod (Type extensionType, string name, NamespaceEntry ns)
+ {
+ if (declspaces == null)
+ return null;
+
+ ArrayList found = null;
+ IEnumerator e = declspaces.Values.GetEnumerator ();
+ e.Reset ();
+ while (e.MoveNext ()) {
+ Class c = e.Current as Class;
+ if (c == null)
+ continue;
+
+ if (!c.IsStaticClass)
+ continue;
+
+ ArrayList res = c.MemberCache.FindExtensionMethods (extensionType, name);
+ if (res == null)
+ continue;
+
+ if (found == null)
+ found = res;
+ else
+ found.AddRange (res);
+ }
+
+ if (external_exmethod_classes == null)
+ return found;
+
+ foreach (Type t in external_exmethod_classes) {
+ MemberCache m = TypeHandle.GetMemberCache (t);
+ ArrayList res = m.FindExtensionMethods (extensionType, name);
+ if (found == null)
+ found = res;
+ else
+ found.AddRange (res);
+ }
+
+ return found;
+ }
+
public void AddDeclSpace (string name, DeclSpace ds)
{
if (declspaces == null)
@@ -808,6 +886,39 @@
extern_aliases [name] = alias;
}
+ ///
+ /// Does extension methods look up to find a method which matches name and extensionType.
+ /// Search starts from this namespace and continues hierarchically up to top level.
+ ///
+ public ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, bool fullLookup, string name)
+ {
+ ArrayList candidates = null;
+ if (fullLookup) {
+ candidates = ns.LookupExtensionMethod (extensionType, name, this);
+ if (candidates != null)
+ return new ExtensionMethodGroupExpr (candidates, this, false, extensionType, Location.Null);
+ }
+
+ foreach (Namespace n in GetUsingTable ()) {
+ ArrayList a = n.LookupExtensionMethod (extensionType, name, this);
+ if (a == null)
+ continue;
+
+ if (candidates == null)
+ candidates = a;
+ else
+ candidates.AddRange (a);
+ }
+
+ if (candidates != null)
+ return new ExtensionMethodGroupExpr (candidates, parent, true, extensionType, Location.Null);
+
+ if (parent == null)
+ return null;
+
+ return parent.LookupExtensionMethod (extensionType, true, name);
+ }
+
public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
{
// Precondition: Only simple names (no dots) will be looked up with this function.
Modified: trunk/mcs/mcs/parameter.cs
===================================================================
--- trunk/mcs/mcs/parameter.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/parameter.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -200,13 +200,14 @@
ISBYREF = 8,
ARGLIST = 16,
REFMASK = 32,
- OUTMASK = 64
+ OUTMASK = 64,
+ This = 128
}
static string[] attribute_targets = new string [] { "param" };
public Expression TypeName;
- public readonly Modifier ModFlags;
+ public Modifier modFlags;
public string Name;
public bool IsCaptured;
protected Type parameter_type;
@@ -227,7 +228,7 @@
: base (attrs)
{
Name = name;
- ModFlags = mod;
+ modFlags = mod;
TypeName = type;
Location = loc;
}
@@ -236,7 +237,7 @@
: base (attrs)
{
Name = name;
- ModFlags = mod;
+ modFlags = mod;
parameter_type = type;
Location = loc;
}
@@ -327,7 +328,8 @@
#endif
if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
- Report.Error (721, Location, "`{0}': static types cannot be used as parameters", GetSignatureForError ());
+ Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
+ texpr.GetSignatureForError ());
return false;
}
@@ -336,7 +338,7 @@
return false;
}
- if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
+ if ((modFlags & Parameter.Modifier.ISBYREF) != 0){
if (parameter_type == TypeManager.typed_reference_type ||
parameter_type == TypeManager.arg_iterator_type){
Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
@@ -344,6 +346,12 @@
return false;
}
}
+
+ if ((modFlags & Modifier.This) != 0 && parameter_type.IsPointer) {
+ Report.Error (1103, Location, "The type of extension method cannot be `{0}'",
+ TypeManager.CSharpName (parameter_type));
+ return false;
+ }
return true;
}
@@ -358,12 +366,20 @@
public Type ExternalType ()
{
- if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
+ if ((modFlags & Parameter.Modifier.ISBYREF) != 0)
return TypeManager.GetReferenceType (parameter_type);
return parameter_type;
}
+ public bool HasExtensionMethodModifier {
+ get { return (modFlags & Modifier.This) != 0; }
+ }
+
+ public Modifier ModFlags {
+ get { return modFlags & ~Modifier.This; }
+ }
+
public Type ParameterType {
get {
return parameter_type;
@@ -378,23 +394,14 @@
}
#endif
- public ParameterAttributes Attributes {
+ ParameterAttributes Attributes {
get {
- switch (ModFlags) {
- case Modifier.NONE:
- return ParameterAttributes.None;
- case Modifier.REF:
- return ParameterAttributes.None;
- case Modifier.OUT:
- return ParameterAttributes.Out;
- case Modifier.PARAMS:
- return 0;
- }
-
- return ParameterAttributes.None;
+ return (modFlags & Modifier.OUT) == Modifier.OUT ?
+ ParameterAttributes.Out : ParameterAttributes.None;
}
}
+ // TODO: should be removed !!!!!!!
public static ParameterAttributes GetParameterAttributes (Modifier mod)
{
int flags = ((int) mod) & ~((int) Parameter.Modifier.ISBYREF);
@@ -426,7 +433,7 @@
else
type_name = TypeName.GetSignatureForError ();
- string mod = GetModifierSignature (ModFlags);
+ string mod = GetModifierSignature (modFlags);
if (mod.Length > 0)
return String.Concat (mod, ' ', type_name);
@@ -444,6 +451,8 @@
return "ref";
case Modifier.ARGLIST:
return "__arglist";
+ case Modifier.This:
+ return "this";
default:
return "";
}
@@ -639,6 +648,29 @@
}
}
+ //
+ // The property can be used after parameter types were resolved.
+ //
+ public Type ExtensionMethodType {
+ get {
+ if (count == 0)
+ return null;
+
+ return FixedParameters [0].HasExtensionMethodModifier ?
+ types [0] : null;
+ }
+ }
+
+ public bool HasExtensionMethodType {
+ get {
+ if (count == 0)
+ return false;
+
+ return FixedParameters [0].HasExtensionMethodModifier;
+ }
+ }
+
+
bool VerifyArgs ()
{
if (count < 2)
Modified: trunk/mcs/mcs/pending.cs
===================================================================
--- trunk/mcs/mcs/pending.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/pending.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -457,7 +457,7 @@
bool name_matches = false;
if (name == mname || mname == tm.get_indexer_name || mname == tm.set_indexer_name)
name_matches = true;
-
+
if ((t == null) && (need_proxy != null) && !name_matches)
tm.need_proxy [i] = need_proxy;
else
Modified: trunk/mcs/mcs/support.cs
===================================================================
--- trunk/mcs/mcs/support.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/support.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -22,9 +22,11 @@
Type ParameterType (int pos);
Type [] Types { get; }
int Count { get; }
+ Type ExtensionMethodType { get; }
bool HasParams { get; }
string ParameterName (int pos);
string ParameterDesc (int pos);
+
Parameter.Modifier ParameterModifier (int pos);
string GetSignatureForError ();
}
@@ -34,6 +36,7 @@
Type [] types;
int params_idx = -1;
bool is_varargs;
+ bool is_extension;
ParameterData gpd;
public ReflectionParameters (MethodBase mb)
@@ -85,6 +88,11 @@
return;
}
}
+
+ if (TypeManager.extension_attribute_type != null && mb.IsStatic &&
+ (mb.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
+ mb.IsDefined (TypeManager.extension_attribute_type, false))
+ is_extension = true;
}
public override bool Equals (object obj)
@@ -166,6 +174,9 @@
if (params_idx == pos)
sb.Append ("params ");
+ if (ExtensionMethodType != null)
+ sb.Append ("this ");
+
sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
return sb.ToString ();
@@ -196,6 +207,15 @@
get { return is_varargs ? pi.Length + 1 : pi.Length; }
}
+ public Type ExtensionMethodType {
+ get {
+ if (!is_extension)
+ return null;
+
+ return types [0];
+ }
+ }
+
public bool HasParams {
get { return params_idx != -1; }
}
Modified: trunk/mcs/mcs/typemanager.cs
===================================================================
--- trunk/mcs/mcs/typemanager.cs 2007-02-15 20:34:56 UTC (rev 72970)
+++ trunk/mcs/mcs/typemanager.cs 2007-02-15 23:22:03 UTC (rev 72971)
@@ -94,6 +94,7 @@
static public Type conditional_attribute_type;
static public Type in_attribute_type;
static public Type out_attribute_type;
+ static public Type extension_attribute_type;
static public Type default_parameter_value_attribute_type;
static public Type anonymous_method_type;
@@ -206,14 +207,15 @@
static internal ConstructorInfo struct_layout_attribute_ctor;
static public ConstructorInfo field_offset_attribute_ctor;
- ///
- /// A new in C# 2.0
- ///
#if NET_2_0
+ /// C# 2.0
static internal CustomAttributeBuilder compiler_generated_attr;
static internal ConstructorInfo fixed_buffer_attr_ctor;
#endif
+ /// C# 3.0
+ static internal CustomAttributeBuilder extension_attribute_attr;
+
static PtrHashtable builder_to_declspace;
static PtrHashtable builder_to_member_cache;
@@ -858,13 +860,19 @@
/// Looks up a type, and aborts if it is not found. This is used
/// by types required by the compiler
/// </summary>
- static Type CoreLookupType (string ns_name, string name)
+ static Type CoreLookupType (string namespaceName, string name)
{
+ return CoreLookupType (namespaceName, name, false);
+ }
+
+ static Type CoreLookupType (string ns_name, string name, bool mayFail)
+ {
Namespace ns = RootNamespace.Global.GetNamespace (ns_name, true);
FullNamedExpression fne = ns.Lookup (RootContext.ToplevelTypes, name, Location.Null);
Type t = fne == null ? null : fne.Type;
if (t == null) {
- Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
+ if (!mayFail)
+ Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
return null;
}
@@ -1084,7 +1092,13 @@
internals_visible_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute");
runtime_compatibility_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
type_forwarder_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "TypeForwardedToAttribute");
+
+ //
+ // C# 3.0
+ //
+ extension_attribute_type = CoreLookupType("System.Runtime.CompilerServices", "ExtensionAttribute", true);
#endif
+
//
// When compiling corlib, store the "real" types here.
//
@@ -1322,6 +1336,11 @@
Type[] type_int_arg = { type_type, int32_type };
fixed_buffer_attr_ctor = GetConstructor (fixed_buffer_attr_type, type_int_arg);
+
+ // C# 3.0
+ if (extension_attribute_type != null)
+ extension_attribute_attr = new CustomAttributeBuilder (
+ GetConstructor (extension_attribute_type, Type.EmptyTypes), new object [0]);
#endif
// Object