public bool ImplementsInterface(TypeSpec iface, bool variantly) { var t = this; do { if (t.Interfaces != null) // TODO: Try t.iface { foreach (TypeSpec i in t.Interfaces) { if (i == iface || TypeSpecComparer.IsEqual(i, iface)) { return(true); } if (variantly && TypeSpecComparer.Variant.IsEqual(i, iface)) { return(true); } } } t = t.BaseType; } while (t != null); return(false); }
// // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower // comparison is used to hide differences between `object' and `dynamic' for generic // types. Should not be used for comparisons where G<object> != G<dynamic> // public static bool IsBaseClass(TypeSpec type, TypeSpec baseClass, bool dynamicIsObject) { if (dynamicIsObject && baseClass.IsGeneric) { // // Returns true for a hierarchies like this when passing baseClass of A<dynamic> // // class B : A<object> {} // while (type != null) { type = type.BaseType; if (TypeSpecComparer.IsEqual(type, baseClass)) { return(true); } } return(false); } while (type != null) { type = type.BaseType; if (type == baseClass) { return(true); } } return(false); }
public void ResolveDefaultValue(ResolveContext rc) { // // Default value was specified using an expression // if (default_expr != null) { ((DefaultParameterValueExpression)default_expr).Resolve(rc, this); if (attributes != null) { ResolveCallerAttributes(rc); } return; } if (attributes == null) { return; } var pa = rc.Module.PredefinedAttributes; var def_attr = attributes.Search(pa.DefaultParameterValue); if (def_attr != null) { if (def_attr.Resolve() == null) { return; } var default_expr_attr = def_attr.GetParameterDefaultValue(); if (default_expr_attr == null) { return; } var dpa_rc = def_attr.CreateResolveContext(); default_expr = default_expr_attr.Resolve(dpa_rc); if (default_expr is BoxedCast) { default_expr = ((BoxedCast)default_expr).Child; } Constant c = default_expr as Constant; if (c == null) { if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) { rc.Report.Error(1910, default_expr.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute", default_expr.Type.GetSignatureForError()); } else { rc.Report.Error(1909, default_expr.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'", default_expr.Type.GetSignatureForError());; } default_expr = null; return; } if (TypeSpecComparer.IsEqual(default_expr.Type, parameter_type) || (default_expr is NullConstant && TypeSpec.IsReferenceType(parameter_type) && !parameter_type.IsGenericParameter) || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) { return; } // // LAMESPEC: Some really weird csc behaviour which we have to mimic // User operators returning same type as parameter type are considered // valid for this attribute only // // struct S { public static implicit operator S (int i) {} } // // void M ([DefaultParameterValue (3)]S s) // var expr = Convert.ImplicitUserConversion(dpa_rc, default_expr, parameter_type, loc); if (expr != null && TypeSpecComparer.IsEqual(expr.Type, parameter_type)) { return; } rc.Report.Error(1908, default_expr.Location, "The type of the default value should match the type of the parameter"); return; } var opt_attr = attributes.Search(pa.OptionalParameter); if (opt_attr != null) { default_expr = EmptyExpression.MissingValue; } }
/// <summary> /// This function tells whether one of our base classes implements /// the given method (which turns out, it is valid to have an interface /// implementation in a base /// </summary> bool BaseImplements(TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method) { base_method = null; bool base_can_implement = true; TypeSpec lookup_type; // // Special handling for properties/indexers which cannot have accessors // implementing an interface found in different types (e.g. current and base) // if (mi.IsAccessor && container.Interfaces != null) { bool new_implementation = false; foreach (var iface in container.Interfaces) { if (TypeSpecComparer.IsEqual(iface, iface_type)) { new_implementation = true; break; } } if (new_implementation) { MemberFilter filter; if (mi.Parameters.Count > 1) { var indexer_params = mi.Name [0] == 'g' ? mi.Parameters : IndexerSpec.CreateParametersFromSetter(mi, mi.Parameters.Count - 1); filter = new MemberFilter(MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, null); } else { var pname = mi.Name.Substring(4); filter = MemberFilter.Property(pname, null); } var prop = MemberCache.FindMember(container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly); if (prop != null && (prop.Modifiers & Modifiers.NEW) != 0) { base_can_implement = false; } } } if (base_can_implement) { lookup_type = container.BaseType; if (lookup_type.ImplementsInterface(iface_type, false)) { return(true); } } else { lookup_type = container.CurrentType; } // // Setup filter with no return type to give better error message // about mismatch at return type when the check bellow rejects them // var parameters = mi.Parameters; MethodSpec close_match = null; while (true) { var candidates = MemberCache.FindMembers(lookup_type, mi.Name, !base_can_implement); if (candidates == null) { base_method = close_match; return(false); } MethodSpec similar_candidate = null; foreach (var candidate in candidates) { if (candidate.Kind != MemberKind.Method) { continue; } if (candidate.Arity != mi.Arity) { continue; } var candidate_param = ((MethodSpec)candidate).Parameters; if (!TypeSpecComparer.Override.IsEqual(parameters.Types, candidate_param.Types)) { continue; } bool modifiers_match = true; for (int i = 0; i < parameters.Count; ++i) { // // First check exact ref/out match // if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) { continue; } modifiers_match = false; // // Different in ref/out only // if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) { if (similar_candidate == null) { if (!candidate.IsPublic) { break; } if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, ((MethodSpec)candidate).ReturnType)) { break; } // It's used for ref/out ambiguity overload check similar_candidate = (MethodSpec)candidate; } continue; } similar_candidate = null; break; } if (!modifiers_match) { continue; } // // From this point the candidate is used for detailed error reporting // because it's very close match to what we are looking for // var m = (MethodSpec)candidate; if (!m.IsPublic) { if (close_match == null) { close_match = m; } continue; } if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, m.ReturnType)) { if (close_match == null) { close_match = m; } continue; } base_method = m; if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints(container, m, mi)) { return(true); } } if (base_method != null) { if (similar_candidate != null) { Report.SymbolRelatedToPreviousError(similar_candidate); Report.SymbolRelatedToPreviousError(mi); Report.SymbolRelatedToPreviousError(container); Report.Warning(1956, 1, ((MemberCore)base_method.MemberDefinition).Location, "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'", mi.GetSignatureForError(), base_method.GetSignatureForError(), similar_candidate.GetSignatureForError(), container.GetSignatureForError()); } break; } if (!base_can_implement) { return(false); } lookup_type = candidates[0].DeclaringType.BaseType; if (lookup_type == null) { base_method = close_match; return(false); } } if (!base_method.IsVirtual) { #if STATIC var base_builder = base_method.GetMetaInfo() as MethodBuilder; if (base_builder != null) { // // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can // be done for all methods from compiled assembly // base_builder.__SetAttributes(base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot); return(true); } #endif DefineProxy(iface_type, base_method, mi); } return(true); }