--- /dev/null
+// CS0029: Cannot implicitly convert type `string' to `int'
+// Line: 8
+
+class A<T> where T : CB, IA
+{
+ void Foo (T t)
+ {
+ t.Prop = "3";
+ }
+}
+
+class CB : CA
+{
+}
+
+class CA
+{
+ public int Prop { get; set; }
+}
+
+interface IA
+{
+ string Prop { get; set; }
+}
\ No newline at end of file
--- /dev/null
+// CS1070: The type `C' has been forwarded to an assembly that is not referenced. Consider adding a reference to assembly `CS1070-lib-missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
+// Line: 5
+// Compiler options: -r:CS1070-lib.dll
+
+public class D
+{
+ static void Main ()
+ {
+ new C ();
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1501: No overload for method `Call' takes `0' arguments
+// Line: 8
+
+class A<T> where T : CB, IA
+{
+ void Foo (T t)
+ {
+ t.Call ();
+ }
+}
+
+class CB : CA
+{
+}
+
+class CA
+{
+ public void Call (int arg)
+ {
+ }
+}
+
+interface IA
+{
+ void Call (bool arg, int arg2);
+}
public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
{
var members = MemberCache.FindMembers (queried_type, name, false);
- if (members == null)
- return null;
- Expression expr;
- do {
- expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
- if (expr != null)
- return expr;
+ if (members != null) {
+ Expression expr;
+ do {
+ expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
+ if (expr != null)
+ return expr;
- if (members [0].DeclaringType.BaseType == null)
- members = null;
- else
- members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
- } while (members != null);
+ if (members [0].DeclaringType.BaseType == null)
+ members = null;
+ else
+ members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
+ } while (members != null);
+ }
- return expr;
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null) {
+ members = MemberCache.FindInterfaceMembers (tps, name);
+ if (members != null)
+ return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
+ }
+
+ return null;
}
public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
if (member is MethodSpec) {
- //
- // Interface members that are hidden by class members are removed from the set. This
- // step only has an effect if T is a type parameter and T has both an effective base
- // class other than object and a non-empty effective interface set
- //
- var tps = queried_type as TypeParameterSpec;
- if (tps != null && tps.HasTypeConstraint)
- members = RemoveHiddenTypeParameterMethods (members);
-
return new MethodGroupExpr (members, queried_type, loc);
}
return null;
}
- static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
- {
- if (members.Count < 2)
- return members;
-
- //
- // If M is a method, then all non-method members declared in an interface declaration
- // are removed from the set, and all methods with the same signature as M declared in
- // an interface declaration are removed from the set
- //
-
- bool copied = false;
- for (int i = 0; i < members.Count; ++i) {
- var method = members[i] as MethodSpec;
- if (method == null) {
- if (!copied) {
- copied = true;
- members = new List<MemberSpec> (members);
- }
-
- members.RemoveAt (i--);
- continue;
- }
-
- if (!method.DeclaringType.IsInterface)
- continue;
-
- for (int ii = 0; ii < members.Count; ++ii) {
- var candidate = members[ii] as MethodSpec;
- if (candidate == null || !candidate.DeclaringType.IsClass)
- continue;
-
- if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
- continue;
-
- if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
- continue;
-
- if (!copied) {
- copied = true;
- members = new List<MemberSpec> (members);
- }
-
- members.RemoveAt (i--);
- break;
- }
- }
-
- return members;
- }
-
protected static void Error_NamedArgument (NamedArgument na, Report Report)
{
Report.Error (1742, na.Location, "An element access expression cannot use named argument");
// For extension methodgroup we are not looking for base members but parent
// namespace extension methods
//
- public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
+ public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
{
// TODO: candidates are null only when doing error reporting, that's
// incorrect. We have to discover same extension methods in error mode
#region IBaseMembersProvider Members
- public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
+ public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
{
- return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
+ var baseType = type.BaseType;
+
+ IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
+
+ if (members == null && !type.IsInterface) {
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null)
+ members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
+ }
+
+ return members;
}
public IParametersMember GetOverrideMemberParameters (MemberSpec member)
// Restore expanded arguments
candidate_args = args;
}
- } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
+ } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
//
// We've found exact match
#region IBaseMembersProvider Members
- IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
+ IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
{
- return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
+ var baseType = type.BaseType;
+ var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
+
+ if (members == null && !type.IsInterface) {
+ var tps = queried_type as TypeParameterSpec;
+ if (tps != null)
+ members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
+ }
+
+ return members;
}
IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
TypeSpec[] targs;
TypeSpec[] ifaces_defined;
TypeSpec effective_base;
+ MemberCache interface_cache;
//
// Creates type owned type parameter
}
}
+ public MemberCache InterfaceCache {
+ get {
+ return interface_cache;
+ }
+ }
+
//
// Unexpanded interfaces list
//
// For a type parameter the membercache is the union of the sets of members of the types
// specified as a primary constraint or secondary constraint
//
+ bool has_user_base_type = false;
if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType) {
cache.AddBaseType (BaseType);
+ has_user_base_type = true;
}
if (InterfacesDefined != null) {
+ var icache = cache;
+ if (has_user_base_type) {
+ //
+ // type-parameter lookup rules are more complicated that other types lookup rules.
+ // Effective base class and its base types member have priority over interface
+ // constraints which means we cannot lookup interface members before class members
+ // hence we setup secondary cache for such cases.
+ //
+ interface_cache = new MemberCache ();
+ icache = interface_cache;
+ }
+
foreach (var iface_type in InterfacesDefined) {
- cache.AddInterface (iface_type);
+ icache.AddInterface (iface_type);
}
}
var ifaces = tps == null ? ta.Interfaces : tps.InterfacesDefined;
if (ifaces != null) {
+ var icache = cache;
+ if (has_user_base_type) {
+ interface_cache = new MemberCache ();
+ icache = interface_cache;
+ }
+
foreach (var iface_type in ifaces) {
- cache.AddInterface (iface_type);
+ icache.AddInterface (iface_type);
}
}
}
public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
{
+ if (filter.Kind == MemberKind.Method && container.Kind == MemberKind.TypeParameter && filter.Parameters == null)
+ throw new NotSupportedException ("type parameters methods cannot be lookup up due to two stage setup");
+
+ IList<MemberSpec> applicable;
+ var top_container = container;
+
do {
- IList<MemberSpec> applicable;
if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) {
// Start from the end because interface members are in reverse order
for (int i = applicable.Count - 1; i >= 0; i--) {
container = container.BaseType;
} while (container != null);
+ var tps = top_container as TypeParameterSpec;
+ if (tps != null && tps.InterfaceCache != null) {
+ if (tps.InterfaceCache.member_hash.TryGetValue (filter.Name, out applicable)) {
+ for (int i = applicable.Count - 1; i >= 0; i--) {
+ var entry = applicable [i];
+
+ if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
+ continue;
+
+ if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
+ continue;
+
+ if (!filter.Equals (entry))
+ continue;
+
+ return entry;
+ }
+ }
+ }
+
return null;
}
//
public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnlyClass)
{
- IList<MemberSpec> applicable;
-
do {
+ IList<MemberSpec> applicable;
+
if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass)
return applicable;
return null;
}
+ public static IList<MemberSpec> FindInterfaceMembers (TypeParameterSpec typeParameter, string name)
+ {
+ if (typeParameter.InterfaceCache != null) {
+ IList<MemberSpec> applicable;
+ typeParameter.InterfaceCache.member_hash.TryGetValue (name, out applicable);
+ return applicable;
+ }
+
+ return null;
+ }
+
//
// Finds the nested type in container
//
--- /dev/null
+class A<T> where T : CB, IA
+{
+ void Foo (T t)
+ {
+ t.Prop = 3;
+ long l = t.Prop2;
+ t["1"] = "2";
+ }
+}
+
+class A2<T, U>
+ where T : CB, U
+ where U : IA
+{
+ void Foo (T t)
+ {
+ t.Prop = 3;
+ long l = t.Prop2;
+ t["1"] = "2";
+ }
+}
+
+class CB : CA
+{
+}
+
+class CA
+{
+ public int Prop { get; set; }
+
+ public string this [byte b] { get { return ""; } }
+}
+
+interface IA
+{
+ string Prop { get; set; }
+ long Prop2 { get; }
+
+ string this [string b] { get; set; }
+}
+
+class X
+{
+ public static void Main ()
+ {
+ }
+}
\ No newline at end of file
</method>
</type>
</test>
+ <test name="gtest-639.cs">
+ <type name="A`1[T]">
+ <method name="Void Foo(T)" attrs="129">
+ <size>53</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="CB">
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="CA">
+ <method name="Int32 get_Prop()" attrs="2182">
+ <size>14</size>
+ </method>
+ <method name="Void set_Prop(Int32)" attrs="2182">
+ <size>8</size>
+ </method>
+ <method name="System.String get_Item(Byte)" attrs="2182">
+ <size>14</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="X">
+ <method name="Void Main()" attrs="150">
+ <size>2</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="A2`2[T,U]">
+ <method name="Void Foo(T)" attrs="129">
+ <size>53</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="gtest-anontype-01.cs">
<type name="Test">
<method name="Int32 Main()" attrs="150">