示例#1
0
        public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
        {
            if (interningProvider == null)
            {
                interningProvider = InterningProvider.Dummy;
            }
            ITypeReference t = this.BaseType.ToTypeReference(lookupMode, interningProvider);

            if (this.HasNullableSpecifier)
            {
                t = interningProvider.Intern(NullableType.Create(t));
            }
            int pointerRank = this.PointerRank;

            for (int i = 0; i < pointerRank; i++)
            {
                t = interningProvider.Intern(new PointerTypeReference(t));
            }
            foreach (var a in this.ArraySpecifiers.Reverse())
            {
                t = interningProvider.Intern(new ArrayTypeReference(t, a.Dimensions));
            }
            if (this.HasRefSpecifier)
            {
                t = interningProvider.Intern(new ByReferenceTypeReference(t));
            }
            return(t);
        }
示例#2
0
        bool ImplicitUserDefinedConversion(IType fromType, IType toType)
        {
            // C# 4.0 spec §6.4.4 User-defined implicit conversions
            // Currently we only test whether an applicable implicit conversion exists,
            // we do not resolve which conversion is the most specific and gets used.

            // Find the candidate operators:
            Predicate <IMethod> opImplicitFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
            var operators = NullableType.GetUnderlyingType(fromType).GetMethods(context, opImplicitFilter)
                            .Concat(NullableType.GetUnderlyingType(toType).GetMethods(context, opImplicitFilter));

            // Determine whether one of them is applicable:
            foreach (IMethod op in operators)
            {
                IType sourceType = op.Parameters[0].Type.Resolve(context);
                IType targetType = op.ReturnType.Resolve(context);
                // Try if the operator is applicable:
                if (StandardImplicitConversion(fromType, sourceType) && StandardImplicitConversion(targetType, toType))
                {
                    return(true);
                }
                // Try if the operator is applicable in lifted form:
                if (sourceType.IsReferenceType(context) == false && targetType.IsReferenceType(context) == false)
                {
                    IType liftedSourceType = NullableType.Create(sourceType, context);
                    IType liftedTargetType = NullableType.Create(targetType, context);
                    if (StandardImplicitConversion(fromType, liftedSourceType) && StandardImplicitConversion(liftedTargetType, toType))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
示例#3
0
        public override Expression DoResolve(ResolveContext rc)
        {
            if (_resolved)
            {
                return(this);
            }

            left = (FullNamedExpression)left.DoResolve(rc);

            IType t   = left.Type;
            var   nxt = spec;

            while (nxt != null)
            {
                if (nxt.IsNullable)
                {
                    t = NullableType.Create(rc.Compilation, t);
                }

                else if (nxt.IsPointer)
                {
                    t = new PointerTypeSpec(t);
                }
                else
                {
                    t = new ArrayType(rc.Compilation, t, nxt.Dimension);
                }

                nxt = spec.Next;
            }

            ResolvedType = t;
            _resolved    = true;
            return(this);
        }
 public LiftedBinaryOperatorMethod(CSharpOperators operators, BinaryOperatorMethod baseMethod)
     : base(operators.compilation)
 {
     this.baseMethod = baseMethod;
     this.ReturnType = NullableType.Create(operators.compilation, baseMethod.ReturnType);
     this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0]));
     this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[1]));
 }
示例#5
0
 IType MakeNullable(ResolveContext rc, IType type, bool isNullable)
 {
     if (isNullable)
     {
         return(NullableType.Create(rc.compilation, type));
     }
     else
     {
         return(type);
     }
 }
 void InitParameterArrays()
 {
     for (TypeCode i = TypeCode.Object; i <= TypeCode.String; i++)
     {
         normalParameters[i - TypeCode.Object] = new DefaultParameter(compilation.FindType(i), string.Empty);
     }
     for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++)
     {
         IType type = NullableType.Create(compilation, compilation.FindType(i));
         nullableParameters[i - TypeCode.Boolean] = new DefaultParameter(type, string.Empty);
     }
 }
示例#7
0
        public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type)
        {
            ITypeReference t = this.BaseType.ToTypeReference(lookupMode);

            if (this.HasNullableSpecifier)
            {
                t = NullableType.Create(t);
            }
            int pointerRank = this.PointerRank;

            for (int i = 0; i < pointerRank; i++)
            {
                t = new PointerTypeReference(t);
            }
            foreach (var a in this.ArraySpecifiers.Reverse())
            {
                t = new ArrayTypeReference(t, a.Dimensions);
            }
            return(t);
        }
示例#8
0
        /// <summary>
        /// Infers the C# type for an IL instruction.
        ///
        /// Returns SpecialType.UnknownType for unsupported instructions.
        /// </summary>
        public static IType InferType(this ILInstruction inst, ICompilation compilation)
        {
            switch (inst)
            {
            case NewObj newObj:
                return(newObj.Method.DeclaringType);

            case NewArr newArr:
                if (compilation != null)
                {
                    return(new ArrayType(compilation, newArr.Type, newArr.Indices.Count));
                }
                else
                {
                    return(SpecialType.UnknownType);
                }

            case Call call:
                return(call.Method.ReturnType);

            case CallVirt callVirt:
                return(callVirt.Method.ReturnType);

            case CallIndirect calli:
                return(calli.ReturnType);

            case UserDefinedLogicOperator logicOp:
                return(logicOp.Method.ReturnType);

            case LdObj ldobj:
                return(ldobj.Type);

            case StObj stobj:
                return(stobj.Type);

            case LdLoc ldloc:
                return(ldloc.Variable.Type);

            case StLoc stloc:
                return(stloc.Variable.Type);

            case LdLoca ldloca:
                return(new ByReferenceType(ldloca.Variable.Type));

            case LdFlda ldflda:
                return(new ByReferenceType(ldflda.Field.Type));

            case LdsFlda ldsflda:
                return(new ByReferenceType(ldsflda.Field.Type));

            case LdElema ldelema:
                if (ldelema.Array.InferType(compilation) is ArrayType arrayType)
                {
                    if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type))
                    {
                        return(new ByReferenceType(arrayType.ElementType));
                    }
                }
                return(new ByReferenceType(ldelema.Type));

            case Comp comp:
                if (compilation == null)
                {
                    return(SpecialType.UnknownType);
                }
                switch (comp.LiftingKind)
                {
                case ComparisonLiftingKind.None:
                case ComparisonLiftingKind.CSharp:
                    return(compilation.FindType(KnownTypeCode.Boolean));

                case ComparisonLiftingKind.ThreeValuedLogic:
                    return(NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean)));

                default:
                    return(SpecialType.UnknownType);
                }

            case BinaryNumericInstruction bni:
                if (bni.IsLifted)
                {
                    return(SpecialType.UnknownType);
                }
                switch (bni.Operator)
                {
                case BinaryNumericOperator.BitAnd:
                case BinaryNumericOperator.BitOr:
                case BinaryNumericOperator.BitXor:
                    var left  = bni.Left.InferType(compilation);
                    var right = bni.Right.InferType(compilation);
                    if (left.Equals(right) && (left.IsCSharpPrimitiveIntegerType() || left.IsKnownType(KnownTypeCode.Boolean)))
                    {
                        return(left);
                    }
                    else
                    {
                        return(SpecialType.UnknownType);
                    }

                default:
                    return(SpecialType.UnknownType);
                }

            default:
                return(SpecialType.UnknownType);
            }
        }
示例#9
0
        List <OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType, bool isExplicit)
        {
            // Find the candidate operators:
            Predicate <IUnresolvedMethod> opFilter;

            if (isExplicit)
            {
                opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Explicit" && m.Parameters.Count == 1;
            }
            else
            {
                opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
            }

            var operators = NullableType.GetUnderlyingType(fromType).GetMethods(opFilter)
                            .Concat(NullableType.GetUnderlyingType(toType).GetMethods(opFilter)).Distinct();
            // Determine whether one of them is applicable:
            List <OperatorInfo> result = new List <OperatorInfo>();

            foreach (IMethod op in operators)
            {
                IType sourceType = op.Parameters[0].Type;
                IType targetType = op.ReturnType;
                // Try if the operator is applicable:
                bool isApplicable;
                if (isExplicit)
                {
                    isApplicable = IsEncompassingOrEncompassedBy(fromType, sourceType) &&
                                   IsEncompassingOrEncompassedBy(targetType, toType);
                }
                else
                {
                    isApplicable = IsEncompassedBy(fromType, sourceType) && IsEncompassedBy(targetType, toType);
                }
                if (isApplicable)
                {
                    result.Add(new OperatorInfo(op, sourceType, targetType, false));
                }
                // Try if the operator is applicable in lifted form:
                if (NullableType.IsNonNullableValueType(sourceType) &&
                    NullableType.IsNonNullableValueType(targetType))
                {
                    IType liftedSourceType = NullableType.Create(compilation, sourceType);
                    IType liftedTargetType = NullableType.Create(compilation, targetType);
                    if (isExplicit)
                    {
                        isApplicable = IsEncompassingOrEncompassedBy(fromType, liftedSourceType) &&
                                       IsEncompassingOrEncompassedBy(liftedTargetType, toType);
                    }
                    else
                    {
                        isApplicable = IsEncompassedBy(fromType, liftedSourceType) && IsEncompassedBy(liftedTargetType, toType);
                    }
                    if (isApplicable)
                    {
                        result.Add(new OperatorInfo(op, liftedSourceType, liftedTargetType, true));
                    }
                }
            }
            return(result);
        }
示例#10
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            // static void Foo<T>(T? ignored = default(T?)) where T : struct
            var m1 = MakeMethod();

            m1.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")
            {
                HasValueTypeConstraint = true
            });
            m1.Parameters.Add(MakeOptionalParameter(
                                  NullableType.Create(m1.TypeParameters[0], context),
                                  "ignored"
                                  ));

            // class ClassConstraint<T> where T : class {}
            DefaultTypeDefinition classConstraint = new DefaultTypeDefinition(dummyClass, "ClassConstraint");

            classConstraint.TypeParameters.Add(new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });

            // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
            // where T : class
            var m2 = MakeMethod();

            m2.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });
            m2.Parameters.Add(MakeOptionalParameter(
                                  new ParameterizedType(classConstraint, new[] { m2.TypeParameters[0] }),
                                  "ignored"
                                  ));

            // static void Foo<T>()
            var m3 = MakeMethod();

            m3.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T"));

            // Call: Foo<int>();
            OverloadResolution o;

            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreSame(m1, o.BestCandidate);

            // Call: Foo<string>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(string).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m2));
            Assert.AreSame(m2, o.BestCandidate);

            // Call: Foo<int?>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int?).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m3));
            Assert.AreSame(m3, o.BestCandidate);
        }
示例#11
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            // static void Foo<T>(T? ignored = default(T?)) where T : struct
            var m1 = MakeUnresolvedMethod();

            m1.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T")
            {
                HasValueTypeConstraint = true
            });
            m1.Parameters.Add(MakeOptionalParameter(
                                  NullableType.Create(new TypeParameterReference(EntityType.Method, 0)),
                                  "ignored"
                                  ));

            // class ClassConstraint<T> where T : class {}
            var classConstraint = new DefaultUnresolvedTypeDefinition(string.Empty, "ClassConstraint");

            classConstraint.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });

            // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
            // where T : class
            var m2 = MakeUnresolvedMethod();

            m2.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });
            m2.Parameters.Add(MakeOptionalParameter(
                                  new ParameterizedTypeReference(classConstraint, new[] { new TypeParameterReference(EntityType.Method, 0) }),
                                  "ignored"
                                  ));

            // static void Foo<T>()
            var m3 = MakeUnresolvedMethod();

            m3.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T"));

            var     context    = new SimpleTypeResolveContext(compilation.MainAssembly);
            IMethod resolvedM1 = (IMethod)m1.CreateResolved(context);
            IMethod resolvedM2 = (IMethod)m2.CreateResolved(context);
            IMethod resolvedM3 = (IMethod)m3.CreateResolved(context);

            // Call: Foo<int>();
            OverloadResolution o;

            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int)) });
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
            Assert.AreSame(resolvedM1, o.BestCandidate);

            // Call: Foo<string>();
            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(string)) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM2));
            Assert.AreSame(resolvedM2, o.BestCandidate);

            // Call: Foo<int?>();
            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int?)) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM3));
            Assert.AreSame(resolvedM3, o.BestCandidate);
        }
        internal static ITypeReference ConvertType(AstType type, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration)
        {
            SimpleType s = type as SimpleType;

            if (s != null)
            {
                List <ITypeReference> typeArguments = new List <ITypeReference>();
                foreach (var ta in s.TypeArguments)
                {
                    typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration));
                }
                if (typeArguments.Count == 0 && parentMethodDefinition != null)
                {
                    // SimpleTypeOrNamespaceReference doesn't support method type parameters,
                    // so we directly handle them here.
                    foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters)
                    {
                        if (tp.Name == s.Identifier)
                        {
                            return(tp);
                        }
                    }
                }
                return(new SimpleTypeOrNamespaceReference(s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration));
            }

            PrimitiveType p = type as PrimitiveType;

            if (p != null)
            {
                switch (p.Keyword)
                {
                case "string":
                    return(KnownTypeReference.String);

                case "int":
                    return(KnownTypeReference.Int32);

                case "uint":
                    return(KnownTypeReference.UInt32);

                case "object":
                    return(KnownTypeReference.Object);

                case "bool":
                    return(KnownTypeReference.Boolean);

                case "sbyte":
                    return(KnownTypeReference.SByte);

                case "byte":
                    return(KnownTypeReference.Byte);

                case "short":
                    return(KnownTypeReference.Int16);

                case "ushort":
                    return(KnownTypeReference.UInt16);

                case "long":
                    return(KnownTypeReference.Int64);

                case "ulong":
                    return(KnownTypeReference.UInt64);

                case "float":
                    return(KnownTypeReference.Single);

                case "double":
                    return(KnownTypeReference.Double);

                case "decimal":
                    return(ReflectionHelper.ToTypeReference(TypeCode.Decimal));

                case "char":
                    return(KnownTypeReference.Char);

                case "void":
                    return(KnownTypeReference.Void);

                default:
                    return(SharedTypes.UnknownType);
                }
            }
            MemberType m = type as MemberType;

            if (m != null)
            {
                ITypeOrNamespaceReference t;
                if (m.IsDoubleColon)
                {
                    SimpleType st = m.Target as SimpleType;
                    if (st != null)
                    {
                        t = new AliasNamespaceReference(st.Identifier, parentUsingScope);
                    }
                    else
                    {
                        t = null;
                    }
                }
                else
                {
                    t = ConvertType(m.Target, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration) as ITypeOrNamespaceReference;
                }
                if (t == null)
                {
                    return(SharedTypes.UnknownType);
                }
                List <ITypeReference> typeArguments = new List <ITypeReference>();
                foreach (var ta in m.TypeArguments)
                {
                    typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration));
                }
                return(new MemberTypeOrNamespaceReference(t, m.MemberName, typeArguments, parentTypeDefinition, parentUsingScope));
            }
            ComposedType c = type as ComposedType;

            if (c != null)
            {
                ITypeReference t = ConvertType(c.BaseType, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration);
                if (c.HasNullableSpecifier)
                {
                    t = NullableType.Create(t);
                }
                for (int i = 0; i < c.PointerRank; i++)
                {
                    t = PointerTypeReference.Create(t);
                }
                foreach (var a in c.ArraySpecifiers.Reverse())
                {
                    t = ArrayTypeReference.Create(t, a.Dimensions);
                }
                return(t);
            }
            Debug.WriteLine("Unknown node used as type: " + type);
            return(SharedTypes.UnknownType);
        }