Пример #1
0
        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);
        }
Пример #2
0
        //
        // 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;
            }
        }
Пример #4
0
        /// <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);
        }