continue;
if (obsoleteCheck) {
- ObsoleteAttribute obsolete_attr = t.GetAttributeObsolete ();
- if (obsolete_attr != null)
- AttributeTester.Report_ObsoleteMessage (obsolete_attr, t.GetSignatureForError (), c.Location, context.Module.Compiler.Report);
+ t.CheckObsoleteness (context, c.Location);
}
ConstraintChecker.Check (context, t, c.Location);
public TypeParameter (TypeParameterSpec spec, TypeSpec parentSpec, MemberName name, Attributes attrs)
: base (null, name, attrs)
{
- this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
+ this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, this, spec.SpecialConstraint, spec.Variance, null) {
BaseType = spec.BaseType,
InterfacesDefined = spec.InterfacesDefined,
TypeArguments = spec.TypeArguments
};
}
-
+
#region Properties
public override AttributeTargets AttributeTargets {
var meta_constraints = new List<MetaType> (spec.TypeArguments.Length);
foreach (var c in spec.TypeArguments) {
//
- // Inflated type parameters can collide with special constraint types, don't
+ // Inflated type parameters can collide with base type constraint, don't
// emit any such type parameter.
//
- if (c.BuiltinType == BuiltinTypeSpec.Type.Object || c.BuiltinType == BuiltinTypeSpec.Type.ValueType)
+ if (c.IsClass && spec.BaseType.BuiltinType != BuiltinTypeSpec.Type.Object)
continue;
meta_constraints.Add (c.GetMetaInfo ());
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
//
//
bool found;
if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
- if (other.targs == null)
- return false;
-
found = false;
- foreach (var otarg in other.targs) {
- if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
- found = true;
- break;
+ if (other.targs != null) {
+ foreach (var otarg in other.targs) {
+ if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
+ found = true;
+ break;
+ }
+ }
+ } else if (targs != null) {
+ foreach (var targ in targs) {
+ if (TypeSpecComparer.Override.IsEqual (targ, other.BaseType)) {
+ found = true;
+ break;
+ }
}
}
//
// Iterate over inflated interfaces
//
- foreach (var iface in Interfaces) {
+ foreach (var iface in InterfacesDefined) {
found = false;
if (other.InterfacesDefined != null) {
foreach (var oiface in other.Interfaces) {
// Check interfaces implementation <- definition
if (other.InterfacesDefined != null) {
- if (InterfacesDefined == null)
- return false;
-
//
// Iterate over inflated interfaces
//
- foreach (var oiface in other.Interfaces) {
+ foreach (var oiface in other.InterfacesDefined) {
found = false;
- foreach (var iface in Interfaces) {
- if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
- found = true;
- break;
+
+ if (InterfacesDefined != null) {
+ foreach (var iface in Interfaces) {
+ if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
+ found = true;
+ break;
+ }
+ }
+ } else if (targs != null) {
+ foreach (var targ in targs) {
+ if (TypeSpecComparer.Override.IsEqual (targ, oiface)) {
+ found = true;
+ break;
+ }
}
}
// Check type parameters implementation -> definition
if (targs != null) {
- if (other.targs == null)
- return false;
-
foreach (var targ in targs) {
found = false;
- foreach (var otarg in other.targs) {
- if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
- found = true;
- break;
+
+ if (other.targs != null) {
+ foreach (var otarg in other.targs) {
+ if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (other.InterfacesDefined != null && !found) {
+ foreach (var iface in other.Interfaces) {
+ if (TypeSpecComparer.Override.IsEqual (iface, targ)) {
+ found = true;
+ break;
+ }
}
}
+ if (!found)
+ found = TypeSpecComparer.Override.IsEqual (targ, other.BaseType);
+
if (!found)
return false;
}
{
cache = new MemberCache ();
+ if (targs != null) {
+ foreach (var ta in targs) {
+ var tps = ta as TypeParameterSpec;
+ var b_type = tps == null ? ta : tps.GetEffectiveBase ();
+
+ //
+ // Find the most specific type when base type was inflated from base constraints
+ //
+ if (b_type != null && !b_type.IsStructOrEnum && TypeSpec.IsBaseClass (b_type, BaseType, false))
+ BaseType = b_type;
+ }
+ }
+
//
// 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
//
- if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType)
+ 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);
}
}
+ //
+ // Import interfaces after base type to match behavior from ordinary classes
+ //
if (targs != null) {
foreach (var ta in targs) {
var tps = ta as TypeParameterSpec;
- IList<TypeSpec> ifaces;
- TypeSpec b_type;
- if (tps != null) {
- b_type = tps.GetEffectiveBase ();
- ifaces = tps.InterfacesDefined;
- } else {
- b_type = ta;
- ifaces = ta.Interfaces;
- }
-
- //
- // Don't add base type which was inflated from base constraints but it's not valid
- // in C# context
- //
- if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType && !b_type.IsStructOrEnum)
- cache.AddBaseType (b_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);
}
}
}
// Parent was inflated, find the same type on inflated type
// to use same cache for nested types on same generic parent
//
- type = MemberCache.FindNestedType (parent, type.Name, type.Arity);
+ type = MemberCache.FindNestedType (parent, type.Name, type.Arity, false);
//
// Handle the tricky case where parent shares local type arguments
return definition.GetMetaInfo ().MakeGenericType (all.ToArray ());
}
+ public override void CheckObsoleteness (IMemberContext mc, Location loc)
+ {
+ base.CheckObsoleteness (mc, loc);
+
+ foreach (var ta in TypeArguments)
+ ta.CheckObsoleteness (mc, loc);
+ }
+
public override ObsoleteAttribute GetAttributeObsolete ()
{
return open_type.GetAttributeObsolete ();
return this;
var mutated = (InflatedTypeSpec) MemberwiseClone ();
+#if DEBUG
+ mutated.ID += 1000000;
+#endif
+
if (decl != DeclaringType) {
// Gets back MethodInfo in case of metaInfo was inflated
//mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
return ExactInference (ac_u.Element, ac_v.Element);
}
- // If V is constructed type and U is constructed type
+ //
+ // If V is constructed type and U is constructed type or dynamic
+ //
if (TypeManager.IsGenericType (v)) {
- if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition)
- return 0;
+ if (u.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
- TypeSpec [] ga_u = TypeManager.GetTypeArguments (u);
- TypeSpec [] ga_v = TypeManager.GetTypeArguments (v);
- if (ga_u.Length != ga_v.Length)
- return 0;
+ var ga_v = v.TypeArguments;
+
+ int score = 0;
+ for (int i = 0; i < ga_v.Length; ++i)
+ score += ExactInference (u, ga_v [i]);
+
+ return System.Math.Min (1, score);
+
+ } else {
+ if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition)
+ return 0;
+
+ var ga_u = u.TypeArguments;
+ var ga_v = v.TypeArguments;
+
+ if (u.TypeArguments.Length != v.TypeArguments.Length)
+ return 0;
- int score = 0;
- for (int i = 0; i < ga_u.Length; ++i)
- score += ExactInference (ga_u [i], ga_v [i]);
+ int score = 0;
+ for (int i = 0; i < ga_v.Length; ++i)
+ score += ExactInference (ga_u [i], ga_v [i]);
- return System.Math.Min (1, score);
+ return System.Math.Min (1, score);
+ }
}
// If V is one of the unfixed type arguments