Example #1
0
        private string BuildArrayTypeString(ArrayTypeSymbol arrayType, out string assemblyNameSuffix)
        {
            TypeSymbol elementType = arrayType.ElementType;

            string typeArgumentsOpt  = null;
            string elementTypeString = elementType.IsArray() ?
                                       BuildArrayTypeString((ArrayTypeSymbol)elementType, out assemblyNameSuffix) :
                                       BuildTypeString(elementType, out typeArgumentsOpt, out assemblyNameSuffix);

            PooledStringBuilder pool    = PooledStringBuilder.GetInstance();
            StringBuilder       builder = pool.Builder;

            builder.Append(elementTypeString);
            AppendTypeArguments(builder, typeArgumentsOpt);
            builder.Append(BuildArrayShapeString(arrayType));
            return(pool.ToStringAndFree());
        }
Example #2
0
        private string BuildTypeArgumentString(TypeSymbol typeArg)
        {
            Debug.Assert(typeArg.Kind != SymbolKind.TypeParameter); //must be a closed type

            string typeArgumentsOpt = null;
            string assemblyNameSuffix;
            string typeArgString = typeArg.IsArray() ?
                                   BuildArrayTypeString((ArrayTypeSymbol)typeArg, out assemblyNameSuffix) :
                                   BuildTypeString(typeArg, out typeArgumentsOpt, out assemblyNameSuffix);

            PooledStringBuilder pool    = PooledStringBuilder.GetInstance();
            StringBuilder       builder = pool.Builder;

            builder.Append("[");
            builder.Append(typeArgString);
            AppendTypeArguments(builder, typeArgumentsOpt);
            builder.Append(assemblyNameSuffix);
            builder.Append("]");
            return(pool.ToStringAndFree());
        }
Example #3
0
        /// <summary>
        /// Returns qualified name of type (without the full assembly name), with square brackets in place of
        /// angle brackets and around type arguments.
        /// Full assembly name of the type is stored in <paramref name="assemblyNameSuffix"/>.
        /// </summary>
        private string BuildTypeString(TypeSymbol symbol, out string typeArgumentsOpt, out string assemblyNameSuffix)
        {
            Debug.Assert((object)symbol != null);
            Debug.Assert(!symbol.IsArray());

            if (symbol.TypeKind == TypeKind.Dynamic)
            {
                return(BuildTypeString(this.compilation.GetSpecialType(SpecialType.System_Object), out typeArgumentsOpt, out assemblyNameSuffix));
            }

            Symbol containing = symbol.ContainingSymbol;

            Debug.Assert((object)containing != null);
            if (containing.Kind == SymbolKind.Namespace)
            {
                return(BuildNamespaceString((NamespaceSymbol)containing, isContainer: true) + BuildTypeStringHelper(symbol, out typeArgumentsOpt, out assemblyNameSuffix));
            }
            else
            {
                Debug.Assert(containing is TypeSymbol);
                string outerTypeArgumentsOpt;
                string outerAssemblyNameSuffix;
                string outer = BuildTypeString((TypeSymbol)containing, out outerTypeArgumentsOpt, out outerAssemblyNameSuffix);
                string inner = BuildTypeStringHelper(symbol, out typeArgumentsOpt, out assemblyNameSuffix);
                Debug.Assert(outerAssemblyNameSuffix == assemblyNameSuffix);

                if (typeArgumentsOpt == null)
                {
                    typeArgumentsOpt = outerTypeArgumentsOpt;
                }
                else if (outerTypeArgumentsOpt != null)
                {
                    typeArgumentsOpt = outerTypeArgumentsOpt + "," + typeArgumentsOpt;
                }

                return(outer + "+" + inner);
            }
        }
Example #4
0
        /// <summary>
        /// Emits conversion to an object of given type.
        /// </summary>
        /// <param name="from">Type of value on top of the evaluation stack.</param>
        /// <param name="fromHint">Hint in case of multitype value.</param>
        /// <param name="to">Target type.</param>
        private void EmitConvertToClass(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to)
        {
            Contract.ThrowIfNull(from);
            Contract.ThrowIfNull(to);
            Debug.Assert(to.IsReferenceType);
            Debug.Assert(to != CoreTypes.PhpAlias);
            Debug.Assert(!to.IsErrorType(), "Trying to convert to an ErrorType");

            // -> IPhpCallable
            if (to == CoreTypes.IPhpCallable)
            {
                EmitConvertToIPhpCallable(from, fromHint);
                return;
            }

            // -> System.Array
            if (to.IsArray())
            {
                var arrt = (ArrayTypeSymbol)to;
                if (arrt.IsSZArray)
                {
                    // byte[]
                    if (arrt.ElementType.SpecialType == SpecialType.System_Byte)
                    {
                        // Template: (PhpString).ToBytes(Context)
                        EmitConvertToPhpString(from, fromHint); // PhpString
                        EmitPhpStringAddr();
                        this.EmitLoadContext();                 // Context
                        EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToBytes_Context)
                        .Expect(to);                            // ToBytes()
                        return;
                    }

                    throw this.NotImplementedException($"Conversion from {from.Name} to {arrt.ElementType.Name}[] is not implemented.");
                }

                throw this.NotImplementedException($"Conversion from {from.Name} to array {to.Name} is not implemented.");
            }

            // dereference
            if (from == CoreTypes.PhpAlias)
            {
                // <alias>.Value.AsObject() : object
                Emit_PhpAlias_GetValueAddr();
                from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.AsObject)
                       .Expect(SpecialType.System_Object);
            }

            if (from.IsReferenceType && from.IsOfType(to))
            {
                return;
            }

            Debug.Assert(to != CoreTypes.PhpArray && to != CoreTypes.PhpString && to != CoreTypes.PhpAlias);

            switch (from.SpecialType)
            {
            case SpecialType.System_Void:
            case SpecialType.System_Int32:
            case SpecialType.System_Int64:
            case SpecialType.System_Boolean:
            case SpecialType.System_Double:
            case SpecialType.System_String:
                // Template: null
                EmitPop(from);
                _il.EmitNullConstant();
                return;

            default:

                Debug.Assert(from != CoreTypes.PhpAlias);

                if (from.IsValueType)
                {
                    if (from == CoreTypes.PhpValue)
                    {
                        if (IsClassOnly(fromHint))
                        {
                            // <STACK>.Object
                            EmitPhpValueAddr();
                            from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.Object.Getter)
                                   .Expect(SpecialType.System_Object);
                        }
                        else
                        {
                            // Convert.AsObject( <STACK> )
                            from = EmitCall(ILOpCode.Call, CoreMethods.Operators.AsObject_PhpValue)
                                   .Expect(SpecialType.System_Object);
                        }
                    }
                    else
                    {
                        // null
                        EmitPop(from);
                        _il.EmitNullConstant();
                        return;
                    }
                }

                //
                break;
            }

            // Template: (T)object
            EmitCastClass(from, to);
        }
Example #5
0
        // Although III.1.8.1.3 seems to imply that verifier understands variance casts.
        // It appears that verifier/JIT gets easily confused. 
        // So to not rely on whether that should work or not we will flag potentially 
        // "complicated" casts and make them static casts to ensure we are all on 
        // the same page with what type should be tracked.
        private static bool IsVarianceCast(TypeSymbol to, TypeSymbol from)
        {
            if (to == from)
            {
                return false;
            }

            if ((object)from == null)
            {
                // from unknown type - this could be a variance conversion.
                return true;
            }

            // while technically variance casts, array conversions do not seem to be a problem
            // unless the element types are converted via variance.
            if (to.IsArray())
            {
                return IsVarianceCast(((ArrayTypeSymbol)to).ElementType, ((ArrayTypeSymbol)from).ElementType);
            }

            return (to.IsDelegateType() && to != from) ||
                   (to.IsInterfaceType() && from.IsInterfaceType() && !from.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.Contains((NamedTypeSymbol)to));
        }
Example #6
0
        public CommonConversion ClassifyConversion(TypeSymbol from, TypeSymbol to, ConversionKind kinds)
        {
            if (from == to)
            {
                return(IdentityConversion);
            }

            // implicit conversions handled by 'EmitConversion':
            if (to.SpecialType == SpecialType.System_Void)
            {
                return(IdentityConversion);
            }

            // object cast possible implicitly:
            if ((kinds & ConversionKind.Reference) == ConversionKind.Reference)
            {
                if (from.IsReferenceType && to.IsReferenceType && from.IsOfType(to))
                {
                    // (PHP) string, resource, array, alias -> object: NoConversion

                    if (to.SpecialType != SpecialType.System_Object || !IsSpecialReferenceType(from))
                    {
                        return(ReferenceConversion);
                    }
                }

                if (to.SpecialType == SpecialType.System_Object && (from.IsInterfaceType() || (from.IsReferenceType && from.IsTypeParameter())))
                {
                    return(ReferenceConversion);
                }
            }

            // resolve conversion operator method:
            if ((kinds & ConversionKind.Numeric) == ConversionKind.Numeric)
            {
                var conv = ClassifyNumericConversion(from, to);
                if (conv.Exists)
                {
                    return(conv);
                }
            }

            // strict:
            if ((kinds & ConversionKind.Strict) == ConversionKind.Strict)
            {
                var op = ResolveOperator(from, false, ImplicitConversionOpNames(to), new[] { _compilation.CoreTypes.StrictConvert.Symbol }, target: to);
                if (op != null)
                {
                    return(new CommonConversion(true, false, false, false, true, op));
                }
            }

            // implicit
            if ((kinds & ConversionKind.Implicit) == ConversionKind.Implicit)
            {
                var op = TryWellKnownImplicitConversion(from, to) ?? ResolveOperator(from, false, ImplicitConversionOpNames(to), new[] { to, _compilation.CoreTypes.Convert.Symbol }, target: to);
                if (op != null)
                {
                    return(new CommonConversion(true, false, false, false, true, op));
                }
            }

            // explicit:
            if ((kinds & ConversionKind.Explicit) == ConversionKind.Explicit)
            {
                var op = ResolveOperator(from, false, ExplicitConversionOpNames(to), new[] { to, _compilation.CoreTypes.Convert.Symbol }, target: to);
                if (op != null)
                {
                    return(new CommonConversion(true, false, false, false, false, op));
                }
                // explicit reference conversion (reference type -> reference type)
                else if (
                    from.IsReferenceType && to.IsReferenceType &&
                    !IsSpecialReferenceType(from) && !IsSpecialReferenceType(to) &&
                    !from.IsArray() && !to.IsArray())
                {
                    return(ExplicitReferenceConversion);
                }
            }

            //
            return(NoConversion);
        }
Example #7
0
        public CommonConversion ClassifyConversion(TypeSymbol from, TypeSymbol to, bool checkimplicit = true, bool checkexplicit = true)
        {
            if (from == to)
            {
                return(IdentityConversion);
            }

            if (from.IsReferenceType && to.IsReferenceType && from.IsOfType(to))
            {
                // (PHP) string, resource, array, alias -> object: NoConversion

                if (to.SpecialType != SpecialType.System_Object || !IsSpecialReferenceType(from))
                {
                    return(ReferenceConversion);
                }
            }

            if (to.SpecialType == SpecialType.System_Object && (from.IsInterfaceType() || (from.IsReferenceType && from.IsTypeParameter())))
            {
                return(ReferenceConversion);
            }

            // implicit conversions handled by 'EmitConversion':

            if (to.SpecialType == SpecialType.System_Void)
            {
                return(IdentityConversion);
            }

            // resolve conversion operator method:

            var conv = ClassifyNumericConversion(from, to);

            if (!conv.Exists)
            {
                // TODO: cache result

                var op = checkimplicit
                    ? TryWellKnownImplicitConversion(from, to) ?? ResolveOperator(from, false, ImplicitConversionOpNames(to), new[] { to, _compilation.CoreTypes.Convert.Symbol }, target: to)
                    : null;

                if (op != null)
                {
                    conv = new CommonConversion(true, false, false, false, true, op);
                }
                else if (checkexplicit)
                {
                    op = ResolveOperator(from, false, ExplicitConversionOpNames(to), new[] { to, _compilation.CoreTypes.Convert.Symbol }, target: to);

                    if (op != null)
                    {
                        conv = new CommonConversion(true, false, false, false, false, op);
                    }
                    // explicit reference conversion (reference type -> reference type)
                    else if (
                        from.IsReferenceType && to.IsReferenceType &&
                        !IsSpecialReferenceType(from) && !IsSpecialReferenceType(to) &&
                        !from.IsArray() && !to.IsArray())
                    {
                        conv = ExplicitReferenceConversion;
                    }
                }
            }

            return(conv);
        }
Example #8
0
        /// <summary>
        /// Emits conversion to a class object.
        /// </summary>
        /// <param name="from">Type of value on top of the evaluation stack.</param>
        /// <param name="fromHint">Hint in case of multitype value.</param>
        /// <param name="to">Target type.</param>
        private void EmitConvertToClass(TypeSymbol from, TypeRefMask fromHint, TypeSymbol to)
        {
            Contract.ThrowIfNull(from);
            Contract.ThrowIfNull(to);
            Debug.Assert(to.IsReferenceType);   // TODO: structs other than primitive types
            Debug.Assert(to != CoreTypes.PhpAlias);

            // dereference
            if (from == CoreTypes.PhpAlias)
            {
                Emit_PhpAlias_GetValue();
                from = CoreTypes.PhpValue;
            }

            if (from == to)
            {
                return;
            }

            Debug.Assert(to != CoreTypes.PhpArray && to != CoreTypes.PhpString && to != CoreTypes.PhpAlias);

            if (to == CoreTypes.IPhpCallable)
            {
                // (IPhpCallable)
                if (!from.IsEqualToOrDerivedFrom(CoreTypes.IPhpCallable))
                {
                    if (from.SpecialType == SpecialType.System_String)
                    {
                        EmitCall(ILOpCode.Call, CoreMethods.Operators.AsCallable_String);
                    }
                    else if (
                        from.SpecialType == SpecialType.System_Int64 ||
                        from.SpecialType == SpecialType.System_Boolean ||
                        from.SpecialType == SpecialType.System_Double)
                    {
                        throw new ArgumentException($"{from.Name} cannot be converted to a class of type {to.Name}!");  // TODO: ErrCode
                    }
                    else
                    {
                        EmitConvertToPhpValue(from, fromHint);
                        EmitCall(ILOpCode.Call, CoreMethods.Operators.AsCallable_PhpValue);
                    }
                }
                return;
            }

            if (to.IsArray())
            {
                var arrt = (ArrayTypeSymbol)to;
                if (arrt.IsSZArray)
                {
                    if (arrt.ElementType.SpecialType == SpecialType.System_Byte)
                    {
                        // byte[]

                        // Template: (PhpString).ToBytes(Context)
                        EmitConvertToPhpString(from, fromHint); // PhpString
                        this.EmitLoadContext();                 // Context
                        EmitCall(ILOpCode.Call, CoreMethods.PhpString.ToBytes_Context)
                        .Expect(to);                            // ToBytes()
                        return;
                    }
                }

                throw new NotImplementedException($"Conversion from {from.Name} to {to.Name} is not implemented.");
            }

            switch (from.SpecialType)
            {
            case SpecialType.System_Void:
            case SpecialType.System_Int32:
            case SpecialType.System_Int64:
            case SpecialType.System_Boolean:
            case SpecialType.System_Double:
            case SpecialType.System_String:
                if (to == CoreTypes.Object)
                {
                    from = EmitConvertToPhpValue(from, fromHint);
                    goto default;
                }
                else
                {
                    throw new ArgumentException($"{from.Name} cannot be converted to a class of type {to.Name}!");      // TODO: ErrCode
                }

            default:
                if (from == CoreTypes.PhpValue)
                {
                    if (!fromHint.IsRef && IsClassOnly(fromHint))
                    {
                        // <value>.Object
                        EmitPhpValueAddr();
                        from = EmitCall(ILOpCode.Call, CoreMethods.PhpValue.Object.Getter)
                               .Expect(SpecialType.System_Object);
                    }
                    else
                    {
                        // Convert.ToClass( value )
                        from = EmitCall(ILOpCode.Call, CoreMethods.Operators.ToClass_PhpValue)
                               .Expect(SpecialType.System_Object);
                    }

                    // (T)
                    EmitCastClass(from, to);
                    return;
                }
                if (from == CoreTypes.PhpNumber)
                {
                    // Object
                    EmitPhpNumberAddr();
                    EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToClass)
                    .Expect(SpecialType.System_Object);

                    // (T)
                    EmitCastClass(to);
                    return;
                }
                else if (from.IsOfType(CoreTypes.PhpArray))
                {
                    // (T)PhpArray.ToClass();
                    EmitCastClass(EmitCall(ILOpCode.Call, CoreMethods.PhpArray.ToClass), to);
                    return;
                }
                else if (from.IsOfType(CoreTypes.IPhpArray))
                {
                    // (T)Convert.ToClass(IPhpArray)
                    EmitCastClass(EmitCall(ILOpCode.Call, CoreMethods.Operators.ToClass_IPhpArray), to);
                    return;
                }
                else if (from.IsReferenceType)
                {
                    Debug.Assert(from != CoreTypes.PhpAlias);
                    // (T)obj   // let .NET deal with eventual cast error for now
                    EmitCastClass(from, to);
                    return;
                }
                throw new NotImplementedException();
            }
        }
Example #9
0
        internal override int GetTargetAttributeSignatureIndex(Symbol targetSymbol, AttributeDescription description)
        {
            if (!IsTargetAttribute(description.Namespace, description.Name))
            {
                return(-1);
            }

            var ctor = this.AttributeConstructor;

            // Ensure that the attribute data really has a constructor before comparing the signature.
            if (ctor is null)
            {
                return(-1);
            }

            // Lazily loaded System.Type type symbol
            TypeSymbol?lazySystemType = null;

            ImmutableArray <ParameterSymbol> parameters = ctor.Parameters;
            bool foundMatch = false;

            for (int i = 0; i < description.Signatures.Length; i++)
            {
                byte[] targetSignature = description.Signatures[i];
                if (targetSignature[0] != (byte)SignatureAttributes.Instance)
                {
                    continue;
                }

                byte parameterCount = targetSignature[1];
                if (parameterCount != parameters.Length)
                {
                    continue;
                }

                if ((SignatureTypeCode)targetSignature[2] != SignatureTypeCode.Void)
                {
                    continue;
                }

                foundMatch = (targetSignature.Length == 3);
                int k = 0;
                for (int j = 3; j < targetSignature.Length; j++)
                {
                    if (k >= parameters.Length)
                    {
                        break;
                    }

                    TypeSymbol  parameterType = parameters[k].Type;
                    SpecialType specType      = parameterType.SpecialType;
                    byte        targetType    = targetSignature[j];

                    if (targetType == (byte)SignatureTypeCode.TypeHandle)
                    {
                        j++;

                        if (parameterType.Kind != SymbolKind.NamedType && parameterType.Kind != SymbolKind.ErrorType)
                        {
                            foundMatch = false;
                            break;
                        }

                        var namedType = (NamedTypeSymbol)parameterType;
                        AttributeDescription.TypeHandleTargetInfo targetInfo = AttributeDescription.TypeHandleTargets[targetSignature[j]];

                        // Compare name and containing symbol name. Uses HasNameQualifier
                        // extension method to avoid string allocations.
                        if (!string.Equals(namedType.MetadataName, targetInfo.Name, System.StringComparison.Ordinal) ||
                            !namedType.HasNameQualifier(targetInfo.Namespace))
                        {
                            foundMatch = false;
                            break;
                        }

                        targetType = (byte)targetInfo.Underlying;

                        if (parameterType.IsEnumType())
                        {
                            specType = parameterType.GetEnumUnderlyingType() !.SpecialType;
                        }
                    }
                    else if (parameterType.IsArray())
                    {
                        specType = ((ArrayTypeSymbol)parameterType).ElementType.SpecialType;
                    }

                    switch (targetType)
                    {
                    case (byte)SignatureTypeCode.Boolean:
                        foundMatch = specType == SpecialType.System_Boolean;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Char:
                        foundMatch = specType == SpecialType.System_Char;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.SByte:
                        foundMatch = specType == SpecialType.System_SByte;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Byte:
                        foundMatch = specType == SpecialType.System_Byte;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int16:
                        foundMatch = specType == SpecialType.System_Int16;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt16:
                        foundMatch = specType == SpecialType.System_UInt16;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int32:
                        foundMatch = specType == SpecialType.System_Int32;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt32:
                        foundMatch = specType == SpecialType.System_UInt32;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int64:
                        foundMatch = specType == SpecialType.System_Int64;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt64:
                        foundMatch = specType == SpecialType.System_UInt64;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Single:
                        foundMatch = specType == SpecialType.System_Single;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Double:
                        foundMatch = specType == SpecialType.System_Double;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.String:
                        foundMatch = specType == SpecialType.System_String;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Object:
                        foundMatch = specType == SpecialType.System_Object;
                        k         += 1;
                        break;

                    case (byte)SerializationTypeCode.Type:
                        if (lazySystemType is null)
                        {
                            lazySystemType = GetSystemType(targetSymbol);
                        }

                        foundMatch = TypeSymbol.Equals(parameterType, lazySystemType, TypeCompareKind.ConsiderEverything2);
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.SZArray:
                        // Skip over and check the next byte
                        foundMatch = parameterType.IsArray();
                        break;

                    default:
                        return(-1);
                    }

                    if (!foundMatch)
                    {
                        break;
                    }
                }

                if (foundMatch)
                {
                    return(i);
                }
            }

            Debug.Assert(!foundMatch);
            return(-1);
        }
Example #10
0
        private bool UpperBoundArrayInference(TypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)target != null);

            // SPEC: * Otherwise, if V is an array type Ve[...] and U is an array
            // SPEC:   type Ue[...] of the same rank, or if V is a one-dimensional array
            // SPEC:   type Ve[] and U is one of IEnumerable<Ue>, ICollection<Ue> or
            // SPEC:   IList<Ue> then
            // SPEC:   * if Ue is known to be a reference type then an upper-bound inference
            // SPEC:     from Ue to Ve is made.
            // SPEC:   * otherwise an exact inference from Ue to Ve is made.

            if (!target.IsArray())
            {
                return false;
            }
            var arrayTarget = (ArrayTypeSymbol)target;
            var elementTarget = arrayTarget.ElementType;
            var elementSource = GetMatchingElementType(arrayTarget, source, ref useSiteDiagnostics);
            if ((object)elementSource == null)
            {
                return false;
            }

            if (elementSource.IsReferenceType)
            {
                UpperBoundInference(elementSource, elementTarget, ref useSiteDiagnostics);
            }
            else
            {
                ExactInference(elementSource, elementTarget, ref useSiteDiagnostics);
            }

            return true;
        }
Example #11
0
        private static TypeSymbol GetMatchingElementType(ArrayTypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)target != null);

            // It might be an array of same rank.
            if (target.IsArray())
            {
                var arrayTarget = (ArrayTypeSymbol)target;
                if (!arrayTarget.HasSameShapeAs(source))
                {
                    return null;
                }
                return arrayTarget.ElementType;
            }

            // Or it might be IEnum<T> and source is rank one.

            if (!source.IsSZArray)
            {
                return null;
            }

            // Arrays are specified as being convertible to IEnumerable<T>, ICollection<T> and
            // IList<T>; we also honor their convertibility to IReadOnlyCollection<T> and
            // IReadOnlyList<T>, and make inferences accordingly.

            if (!target.IsPossibleArrayGenericInterface())
            {
                return null;
            }

            return ((NamedTypeSymbol)target).TypeArgumentWithDefinitionUseSiteDiagnostics(0, ref useSiteDiagnostics);
        }
Example #12
0
        private bool ExactArrayInference(TypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)target != null);

            // SPEC: * Otherwise, if U is an array type UE[...] and V is an array type VE[...]
            // SPEC:   of the same rank then an exact inference from UE to VE is made.
            if (!source.IsArray() || !target.IsArray())
            {
                return false;
            }

            var arraySource = (ArrayTypeSymbol)source;
            var arrayTarget = (ArrayTypeSymbol)target;
            if (!arraySource.HasSameShapeAs(arrayTarget))
            {
                return false;
            }

            ExactInference(arraySource.ElementType, arrayTarget.ElementType, ref useSiteDiagnostics);
            return true;
        }
Example #13
0
        internal override int GetTargetAttributeSignatureIndex(Symbol targetSymbol, AttributeDescription description)
        {
            if (!IsTargetAttribute(description.Namespace, description.Name))
            {
                return(-1);
            }

            var ctor = this.AttributeConstructor;

            // Ensure that the attribute data really has a constructor before comparing the signature.
            if (ctor is null)
            {
                return(-1);
            }

            // Lazily loaded System.Type type symbol
            TypeSymbol?lazySystemType = null;

            ImmutableArray <ParameterSymbol> parameters = ctor.Parameters;

            for (int signatureIndex = 0; signatureIndex < description.Signatures.Length; signatureIndex++)
            {
                byte[] targetSignature = description.Signatures[signatureIndex];

                if (matches(targetSignature, parameters, ref lazySystemType))
                {
                    return(signatureIndex);
                }
            }

            return(-1);

            bool matches(byte[] targetSignature, ImmutableArray <ParameterSymbol> parameters, ref TypeSymbol?lazySystemType)
            {
                if (targetSignature[0] != (byte)SignatureAttributes.Instance)
                {
                    return(false);
                }

                byte parameterCount = targetSignature[1];

                if (parameterCount != parameters.Length)
                {
                    return(false);
                }

                if ((SignatureTypeCode)targetSignature[2] != SignatureTypeCode.Void)
                {
                    return(false);
                }

                int parameterIndex = 0;

                for (int signatureByteIndex = 3; signatureByteIndex < targetSignature.Length; signatureByteIndex++)
                {
                    if (parameterIndex >= parameters.Length)
                    {
                        return(false);
                    }

                    TypeSymbol  parameterType = parameters[parameterIndex].Type;
                    SpecialType specType      = parameterType.SpecialType;
                    byte        targetType    = targetSignature[signatureByteIndex];

                    if (targetType == (byte)SignatureTypeCode.TypeHandle)
                    {
                        signatureByteIndex++;

                        if (parameterType.Kind != SymbolKind.NamedType && parameterType.Kind != SymbolKind.ErrorType)
                        {
                            return(false);
                        }

                        var namedType = (NamedTypeSymbol)parameterType;
                        AttributeDescription.TypeHandleTargetInfo targetInfo = AttributeDescription.TypeHandleTargets[targetSignature[signatureByteIndex]];

                        // Compare name and containing symbol name. Uses HasNameQualifier
                        // extension method to avoid string allocations.
                        if (!string.Equals(namedType.MetadataName, targetInfo.Name, System.StringComparison.Ordinal) ||
                            !namedType.HasNameQualifier(targetInfo.Namespace))
                        {
                            return(false);
                        }

                        targetType = (byte)targetInfo.Underlying;

                        if (parameterType.IsEnumType())
                        {
                            specType = parameterType.GetEnumUnderlyingType() !.SpecialType;
                        }
                    }
                    else if (targetType != (byte)SignatureTypeCode.SZArray && parameterType.IsArray())
                    {
                        if (targetSignature[signatureByteIndex - 1] != (byte)SignatureTypeCode.SZArray)
                        {
                            return(false);
                        }

                        specType = ((ArrayTypeSymbol)parameterType).ElementType.SpecialType;
                    }

                    switch (targetType)
                    {
                    case (byte)SignatureTypeCode.Boolean:
                        if (specType != SpecialType.System_Boolean)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Char:
                        if (specType != SpecialType.System_Char)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.SByte:
                        if (specType != SpecialType.System_SByte)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Byte:
                        if (specType != SpecialType.System_Byte)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int16:
                        if (specType != SpecialType.System_Int16)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt16:
                        if (specType != SpecialType.System_UInt16)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int32:
                        if (specType != SpecialType.System_Int32)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt32:
                        if (specType != SpecialType.System_UInt32)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int64:
                        if (specType != SpecialType.System_Int64)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt64:
                        if (specType != SpecialType.System_UInt64)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Single:
                        if (specType != SpecialType.System_Single)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Double:
                        if (specType != SpecialType.System_Double)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.String:
                        if (specType != SpecialType.System_String)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Object:
                        if (specType != SpecialType.System_Object)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SerializationTypeCode.Type:
                        lazySystemType ??= GetSystemType(targetSymbol);

                        if (!TypeSymbol.Equals(parameterType, lazySystemType, TypeCompareKind.ConsiderEverything))
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.SZArray:
                        // Skip over and check the next byte
                        if (!parameterType.IsArray())
                        {
                            return(false);
                        }
                        break;

                    default:
                        return(false);
                    }
                }

                return(true);
            }
        }
 private static bool IsInvariantArray(TypeSymbol type)
 {
     return(type.IsArray() && type.GetArrayElementType().TypeSymbol.IsSealed);
 }
Example #15
0
        private string BuildTypeArgumentString(TypeSymbol typeArg)
        {
            Debug.Assert(typeArg.Kind != SymbolKind.TypeParameter); //must be a closed type

            string typeArgumentsOpt = null;
            string assemblyNameSuffix;
            string typeArgString = typeArg.IsArray() ?
                BuildArrayTypeString((ArrayTypeSymbol)typeArg, out assemblyNameSuffix) :
                BuildTypeString(typeArg, out typeArgumentsOpt, out assemblyNameSuffix);

            PooledStringBuilder pool = PooledStringBuilder.GetInstance();
            StringBuilder builder = pool.Builder;
            builder.Append("[");
            builder.Append(typeArgString);
            AppendTypeArguments(builder, typeArgumentsOpt);
            builder.Append(assemblyNameSuffix);
            builder.Append("]");
            return pool.ToStringAndFree();
        }
Example #16
0
        /// <summary>
        /// Returns qualified name of type (without the full assembly name), with square brackets in place of
        /// angle brackets and around type arguments.
        /// Full assembly name of the type is stored in <paramref name="assemblyNameSuffix"/>.
        /// </summary>
        private string BuildTypeString(TypeSymbol symbol, out string typeArgumentsOpt, out string assemblyNameSuffix)
        {
            Debug.Assert((object)symbol != null);
            Debug.Assert(!symbol.IsArray());

            if (symbol.TypeKind == TypeKind.DynamicType)
            {
                return BuildTypeString(this.compilation.GetSpecialType(SpecialType.System_Object), out typeArgumentsOpt, out assemblyNameSuffix);
            }

            Symbol containing = symbol.ContainingSymbol;
            Debug.Assert((object)containing != null);
            if (containing.Kind == SymbolKind.Namespace)
            {
                return BuildNamespaceString((NamespaceSymbol)containing, isContainer: true) + BuildTypeStringHelper(symbol, out typeArgumentsOpt, out assemblyNameSuffix);
            }
            else
            {
                Debug.Assert(containing is TypeSymbol);
                string outerTypeArgumentsOpt;
                string outerAssemblyNameSuffix;
                string outer = BuildTypeString((TypeSymbol)containing, out outerTypeArgumentsOpt, out outerAssemblyNameSuffix);
                string inner = BuildTypeStringHelper(symbol, out typeArgumentsOpt, out assemblyNameSuffix);
                Debug.Assert(outerAssemblyNameSuffix == assemblyNameSuffix);

                if (typeArgumentsOpt == null)
                {
                    typeArgumentsOpt = outerTypeArgumentsOpt;
                }
                else if (outerTypeArgumentsOpt != null)
                {
                    typeArgumentsOpt = outerTypeArgumentsOpt + "," + typeArgumentsOpt;
                }

                return outer + "+" + inner;
            }
        }