static string TypeId(TypeSymbol type)
        {
            string id;

            if (type is ArrayTypeSymbol)
            {
                var arrtype = (ArrayTypeSymbol)type;
                id = TypeId(arrtype.ElementType) + "[]";  // TODO: MDSize
            }
            else if (type.IsTypeParameter())
            {
                id = type.MetadataName;
            }
            else if (type.ContainingType != null) // nested type
            {
                id = TypeId(type.ContainingType) + "." + TypeNameId(type);
            }
            else
            {
                var ns   = ((NamedTypeSymbol)type.OriginalDefinition).NamespaceName.Replace("<", "&lt;").Replace(">", "&gt;");
                var name = TypeNameId(type);

                id = string.IsNullOrEmpty(ns) ? name : (ns + "." + name);
            }

            //
            return(id);
        }
Example #2
0
        /// <summary>
        /// </summary>
        /// <param name="typeSymbol">
        /// </param>
        /// <param name="genericContext">
        /// </param>
        /// <returns>
        /// </returns>
        internal static IType ResolveGeneric(this TypeSymbol typeSymbol, IGenericContext genericContext, bool isByRef = false, bool isPinned = false)
        {
            if (genericContext != null && !genericContext.IsEmpty)
            {
                if (typeSymbol.IsTypeParameter())
                {
                    return(genericContext.ResolveTypeParameter(new MetadataTypeAdapter(typeSymbol, isByRef, isPinned), isByRef, isPinned));
                }

                var arrayType = typeSymbol as ArrayTypeSymbol;
                if (arrayType != null)
                {
                    return(arrayType.ElementType.ResolveGeneric(genericContext, isByRef, isPinned).ToArrayType(arrayType.Rank));
                }

                var namedTypeSymbol = typeSymbol as NamedTypeSymbol;
                if (namedTypeSymbol != null)
                {
                    var metadataType = new MetadataTypeAdapter(namedTypeSymbol, isByRef, isPinned);
                    if (metadataType.IsGenericTypeDefinition && !genericContext.IsEmpty)
                    {
                        return(new MetadataTypeAdapter(namedTypeSymbol, genericContext, isByRef, isPinned));
                    }
                }
            }

            return(new MetadataTypeAdapter(typeSymbol, genericContext, isByRef, isPinned));
        }
Example #3
0
        internal ImmutableArray <CustomModifier> SubstituteCustomModifiers(TypeSymbol type, ImmutableArray <CustomModifier> customModifiers)
        {
            if (type.IsTypeParameter())
            {
                return(new TypeWithModifiers(type, customModifiers).SubstituteType(this).CustomModifiers);
            }

            return(SubstituteCustomModifiers(customModifiers));
        }
Example #4
0
        private bool AnyConstraintTypes(
            ImmutableArray <TypeWithAnnotations> constraintTypes,
            Func <TypeParameterSymbol, bool> predicate1,
            Func <TypeSymbol, bool> predicate2)
        {
            if (constraintTypes.IsEmpty)
            {
                return(false);
            }

            bool result = false;
            ConsList <TypeParameterSymbol> inProgress = ConsList <TypeParameterSymbol> .Empty.Push(this);

            var stack = ArrayBuilder <TypeWithAnnotations> .GetInstance(constraintTypes.Length);

            stack.AddRange(constraintTypes);

            do
            {
                TypeWithAnnotations constraintType = stack.Pop();
                TypeSymbol          type           = constraintType.IsResolved ? constraintType.Type : constraintType.DefaultType;

                if (type.IsTypeParameter())
                {
                    var typeParameter = (TypeParameterSymbol)type;

                    if (inProgress.ContainsReference(typeParameter))
                    {
                        continue;
                    }

                    if (predicate1(typeParameter))
                    {
                        result = true;
                        break;
                    }

                    inProgress = inProgress.Prepend(typeParameter);
                    stack.AddRange(typeParameter.GetConstraintTypesNoUseSiteDiagnostics(early: true));
                }
                else if (predicate2(type))
                {
                    result = true;
                    break;
                }
            }while (stack.Count != 0);

            stack.Free();
            return(result);
        }
        private static bool IsPossiblyByRefTypeParameter(TypeSymbol type)
        {
            if (type.IsTypeParameter())
            {
                return(true);
            }

            if (type.IsErrorType())
            {
                var byRefReturnType = type as ByRefReturnErrorTypeSymbol;

                return(((object)byRefReturnType != null) && byRefReturnType.ReferencedType.IsTypeParameter());
            }

            return(false);
        }
Example #6
0
        public static void AddTypesParticipatingInUserDefinedConversion(
            ArrayBuilder <NamedTypeSymbol> result,
            TypeSymbol type,
            bool includeBaseTypes,
            ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo
            )
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            if (type.IsClassType() || type.IsStructType())
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);

            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);
            }
        }
Example #7
0
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder <NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            // The decimal type does not contribute its user-defined conversions to the mix; though its
            // conversions are actually implemented via user-defined operators, we logically treat it as
            // though those conversions were built-in.

            if (type.IsClassType() || type.IsStructType() && type.SpecialType != SpecialType.System_Decimal)
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);

            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder<NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            // The decimal type does not contribute its user-defined conversions to the mix; though its 
            // conversions are actually implemented via user-defined operators, we logically treat it as 
            // though those conversions were built-in.  

            if (type.IsClassType() || type.IsStructType() && type.SpecialType != SpecialType.System_Decimal)
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
Example #9
0
        private static TypeSymbol GetUnderlyingEffectiveType(TypeSymbol type, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // Spec 6.4.4: User-defined implicit conversions
            // Spec 6.4.5: User-defined explicit conversions
            //
            // Determine the types S0 and T0.
            //   * If S or T are nullable types, let Su and Tu be their underlying types, otherwise let Su and Tu be S and T, respectively.
            //   * If Su or Tu are type parameters, S0 and T0 are their effective base types, otherwise S0 and T0 are equal to Su and Tu, respectively.

            if ((object)type != null)
            {
                type = type.StrippedType();

                if (type.IsTypeParameter())
                {
                    type = ((TypeParameterSymbol)type).EffectiveBaseClass(ref useSiteDiagnostics);
                }
            }

            return(type);
        }
Example #10
0
        private static TypeSymbol GetUnderlyingEffectiveType(TypeSymbol type, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // Spec 6.4.4: User-defined implicit conversions 
            // Spec 6.4.5: User-defined explicit conversions 
            // 
            // Determine the types S0 and T0. 
            //   * If S or T are nullable types, let Su and Tu be their underlying types, otherwise let Su and Tu be S and T, respectively. 
            //   * If Su or Tu are type parameters, S0 and T0 are their effective base types, otherwise S0 and T0 are equal to Su and Tu, respectively.

            if ((object)type != null)
            {
                type = type.StrippedType();

                if (type.IsTypeParameter())
                {
                    type = ((TypeParameterSymbol)type).EffectiveBaseClass(ref useSiteDiagnostics);
                }
            }

            return type;
        }
Example #11
0
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder<NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            if (type.IsClassType() || type.IsStructType())
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
        private bool GetUserDefinedOperators(
            BinaryOperatorKind kind,
            TypeSymbol type0,
            BoundExpression left,
            BoundExpression right,
            ArrayBuilder<BinaryOperatorAnalysisResult> results,
            ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // Spec 7.3.5 Candidate user-defined operators
            // SPEC: Given a type T and an operation operator op(A), where op is an overloadable 
            // SPEC: operator and A is an argument list, the set of candidate user-defined operators 
            // SPEC: provided by T for operator op(A) is determined as follows:

            // SPEC: Determine the type T0. If T is a nullable type, T0 is its underlying type, 
            // SPEC: otherwise T0 is equal to T.

            // (The caller has already passed in the stripped type.)

            // SPEC: For all operator op declarations in T0 and all lifted forms of such operators, 
            // SPEC: if at least one operator is applicable (7.5.3.1) with respect to the argument 
            // SPEC: list A, then the set of candidate operators consists of all such applicable 
            // SPEC: operators in T0. Otherwise, if T0 is object, the set of candidate operators is empty.
            // SPEC: Otherwise, the set of candidate operators provided by T0 is the set of candidate 
            // SPEC: operators provided by the direct base class of T0, or the effective base class of
            // SPEC: T0 if T0 is a type parameter.

            string name = OperatorFacts.BinaryOperatorNameFromOperatorKind(kind);
            var operators = ArrayBuilder<BinaryOperatorSignature>.GetInstance();
            bool hadApplicableCandidates = false;

            NamedTypeSymbol current = type0 as NamedTypeSymbol;
            if ((object)current == null)
            {
                current = type0.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }

            if ((object)current == null && type0.IsTypeParameter())
            {
                current = ((TypeParameterSymbol)type0).EffectiveBaseClass(ref useSiteDiagnostics);
            }

            for (; (object)current != null; current = current.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                operators.Clear();
                GetUserDefinedBinaryOperatorsFromType(current, kind, name, operators);
                results.Clear();
                if (CandidateOperators(operators, left, right, results, ref useSiteDiagnostics))
                {
                    hadApplicableCandidates = true;
                    break;
                }
            }

            operators.Free();

            return hadApplicableCandidates;
        }
Example #13
0
        // Returns true if there were any applicable candidates.
        private bool GetUserDefinedOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(operand != null);

            if ((object)operand.Type == null)
            {
                // If the operand has no type -- because it is a null reference or a lambda or a method group --
                // there is no way we can determine what type to search for user-defined operators.
                return(false);
            }

            // Spec 7.3.5 Candidate user-defined operators
            // SPEC: Given a type T and an operation op(A) ... the set of candidate user-defined
            // SPEC: operators provided by T for op(A) is determined as follows:

            // SPEC: If T is a nullable type then T0 is its underlying type; otherwise T0 is T.
            // SPEC: For all operator declarations in T0 and all lifted forms of such operators, if
            // SPEC: at least one operator is applicable with respect to A then the set of candidate
            // SPEC: operators consists of all such applicable operators. Otherwise, if T0 is object
            // SPEC: then the set of candidate operators is empty. Otherwise, the set of candidate
            // SPEC: operators is the set provided by the direct base class of T0, or the effective
            // SPEC: base class of T0 if T0 is a type parameter.

            TypeSymbol type0 = operand.Type.StrippedType();

            // Searching for user-defined operators is expensive; let's take an early out if we can.
            if (OperatorFacts.DefinitelyHasNoUserDefinedOperators(type0))
            {
                return(false);
            }

            string name      = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind);
            var    operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            bool hadApplicableCandidates = false;

            NamedTypeSymbol current = type0 as NamedTypeSymbol;

            if ((object)current == null)
            {
                current = type0.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }

            if ((object)current == null && type0.IsTypeParameter())
            {
                current = ((TypeParameterSymbol)type0).EffectiveBaseClass(ref useSiteDiagnostics);
            }

            for (; (object)current != null; current = current.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                operators.Clear();
                GetUserDefinedUnaryOperatorsFromType(current, kind, name, operators);
                results.Clear();
                if (CandidateOperators(operators, operand, results, ref useSiteDiagnostics))
                {
                    hadApplicableCandidates = true;
                    break;
                }
            }

            operators.Free();

            return(hadApplicableCandidates);
        }
Example #14
0
        internal static bool IsValidObjectEquality(Conversions Conversions, TypeSymbol leftType, bool leftIsNull, TypeSymbol rightType, bool rightIsNull, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // SPEC: The predefined reference type equality operators require one of the following:

            // SPEC: (1) Both operands are a value of a type known to be a reference-type or the literal null.
            // SPEC:     Furthermore, an explicit reference conversion exists from the type of either
            // SPEC:     operand to the type of the other operand. Or:
            // SPEC: (2) One operand is a value of type T where T is a type-parameter and the other operand is
            // SPEC:     the literal null. Furthermore T does not have the value type constraint.

            // SPEC ERROR: Notice that the spec calls out that an explicit reference conversion must exist;
            // SPEC ERROR: in fact it should say that an explicit reference conversion, implicit reference
            // SPEC ERROR: conversion or identity conversion must exist. The conversion from object to object
            // SPEC ERROR: is not classified as a reference conversion at all; it is an identity conversion.

            // Dev10 does not follow the spec exactly for type parameters. Specifically, in Dev10,
            // if a type parameter argument is known to be a value type, or if a type parameter
            // argument is not known to be either a value type or reference type and the other
            // argument is not null, reference type equality cannot be applied. Otherwise, the
            // effective base class of the type parameter is used to determine the conversion
            // to the other argument type. (See ExpressionBinder::GetRefEqualSigs.)

            if (((object)leftType != null) && leftType.IsTypeParameter())
            {
                if (leftType.IsValueType || (!leftType.IsReferenceType && !rightIsNull))
                {
                    return(false);
                }

                leftType = ((TypeParameterSymbol)leftType).EffectiveBaseClass(ref useSiteDiagnostics);
                Debug.Assert((object)leftType != null);
            }

            if (((object)rightType != null) && rightType.IsTypeParameter())
            {
                if (rightType.IsValueType || (!rightType.IsReferenceType && !leftIsNull))
                {
                    return(false);
                }

                rightType = ((TypeParameterSymbol)rightType).EffectiveBaseClass(ref useSiteDiagnostics);
                Debug.Assert((object)rightType != null);
            }

            var leftIsReferenceType = ((object)leftType != null) && leftType.IsReferenceType;

            if (!leftIsReferenceType && !leftIsNull)
            {
                return(false);
            }

            var rightIsReferenceType = ((object)rightType != null) && rightType.IsReferenceType;

            if (!rightIsReferenceType && !rightIsNull)
            {
                return(false);
            }

            // If at least one side is null then clearly a conversion exists.
            if (leftIsNull || rightIsNull)
            {
                return(true);
            }

            var leftConversion = Conversions.ClassifyConversion(leftType, rightType, ref useSiteDiagnostics);

            if (leftConversion.IsIdentity || leftConversion.IsReference)
            {
                return(true);
            }

            var rightConversion = Conversions.ClassifyConversion(rightType, leftType, ref useSiteDiagnostics);

            if (rightConversion.IsIdentity || rightConversion.IsReference)
            {
                return(true);
            }

            return(false);
        }
Example #15
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new subsitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution)
        {
            if (ReferenceEquals(t1, t2))
            {
                return true;
            }
            else if ((object)t1 == null || (object)t2 == null)
            {
                // Can't both be null or they would have been ReferenceEquals
                return false;
            }

            if (substitution != null)
            {
                t1 = substitution.SubstituteType(t1);
                t2 = substitution.SubstituteType(t2);
            }

            // If one of the types is a type parameter, then the substitution could make them ReferenceEquals.
            if (ReferenceEquals(t1, t2))
            {
                return true;
            }

            // We can avoid a lot of redundant checks if we ensure that we only have to check
            // for type parameters on the LHS
            if (!t1.IsTypeParameter() && t2.IsTypeParameter())
            {
                TypeSymbol tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

            // If t1 is not a type parameter, then neither is t2
            Debug.Assert(t1.IsTypeParameter() || !t2.IsTypeParameter());

            switch (t1.Kind)
            {
                case SymbolKind.ArrayType:
                    {
                        if (t2.TypeKind != t1.TypeKind)
                        {
                            return false;
                        }

                        ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1;
                        ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2;

                        if (at1.Rank != at2.Rank || !at1.CustomModifiers.SequenceEqual(at2.CustomModifiers))
                        {
                            return false;
                        }

                        return CanUnifyHelper(at1.ElementType, at2.ElementType, ref substitution);
                    }
                case SymbolKind.PointerType:
                    {
                        if (t2.TypeKind != t1.TypeKind)
                        {
                            return false;
                        }

                        PointerTypeSymbol pt1 = (PointerTypeSymbol)t1;
                        PointerTypeSymbol pt2 = (PointerTypeSymbol)t2;

                        if (!pt1.CustomModifiers.SequenceEqual(pt2.CustomModifiers))
                        {
                            return false;
                        }

                        return CanUnifyHelper(pt1.PointedAtType, pt2.PointedAtType, ref substitution);
                    }
                case SymbolKind.NamedType:
                case SymbolKind.ErrorType:
                    {
                        if (t2.TypeKind != t1.TypeKind)
                        {
                            return false;
                        }

                        NamedTypeSymbol nt1 = (NamedTypeSymbol)t1;
                        NamedTypeSymbol nt2 = (NamedTypeSymbol)t2;

                        if (!nt1.IsGenericType)
                        {
                            return !nt2.IsGenericType && nt1 == nt2;
                        }
                        else if (!nt2.IsGenericType)
                        {
                            return false;
                        }

                        int arity = nt1.Arity;

                        if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition)
                        {
                            return false;
                        }

                        for (int i = 0; i < arity; i++)
                        {
                            if (!CanUnifyHelper(nt1.TypeArgumentsNoUseSiteDiagnostics[i], nt2.TypeArgumentsNoUseSiteDiagnostics[i], ref substitution))
                            {
                                return false;
                            }
                        }

                        // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                        return (object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution);
                    }
                case SymbolKind.TypeParameter:
                    {
                        // These substitutions are not allowed in C#
                        if (t2.TypeKind == TypeKind.Pointer || t2.SpecialType == SpecialType.System_Void)
                        {
                            return false;
                        }

                        TypeParameterSymbol tp1 = (TypeParameterSymbol)t1;

                        // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types
                        // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above
                        if (Contains(t2, tp1))
                        {
                            return false;
                        }

                        if (substitution == null)
                        {
                            substitution = new MutableTypeMap();
                        }

                        // MutableTypeMap.Add will throw if the key has already been added.  However,
                        // if t1 was already in the substitution, it would have been substituted at the
                        // start of this method and we wouldn't be here.
                        substitution.Add(tp1, t2);

                        return true;
                    }
                default:
                    {
                        return t1 == t2;
                    }
            }
        }
Example #16
0
        internal static ConstantValue GetAsOperatorConstantResult(TypeSymbol operandType, TypeSymbol targetType, ConversionKind conversionKind, ConstantValue operandConstantValue)
        {
            // NOTE:    Even though BoundIsOperator and BoundAsOperator will always have no ConstantValue
            // NOTE:    (they are non-constant expressions according to Section 7.19 of the specification),
            // NOTE:    we want to perform constant analysis of is/as expressions during binding to generate warnings (always true/false/null)
            // NOTE:    and during rewriting for optimized codegen.

            // Native compiler port:
            //     // check for case we know is always false
            //     if (arg->isNull() || !canCast(arg, type2, NOUDC) && type1->IsValType() && type2->isClassType() && (!type1->IsTypeParameterType() || !type2->isPredefType(PT_ENUM)))
            //     {
            //          GetErrorContext()->Error(tree, WRN_AlwaysNull, type2);
            //          return rval;
            //     }

            if (operandConstantValue == ConstantValue.Null ||
                (conversionKind == ConversionKind.NoConversion &&
                 (operandType.IsValueType && targetType.IsClassType() && (!operandType.IsTypeParameter() || targetType.SpecialType != SpecialType.System_Enum))))
            {
                return ConstantValue.Null;
            }
            else
            {
                return null;
            }
        }
Example #17
0
        private static bool IsPossiblyByRefTypeParameter(TypeSymbol type)
        {
            if (type.IsTypeParameter())
            {
                return true;
            }

            if (type.IsErrorType())
            {
                //var byRefReturnType = type as ByRefReturnErrorTypeSymbol;

                //return ((object)byRefReturnType != null) && byRefReturnType.ReferencedType.IsTypeParameter();

                throw new NotImplementedException();
            }

            return false;
        }
        private bool GetUserDefinedOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(operand != null);

            if ((object)operand.Type == null)
            {
                // If the operand has no type -- because it is a null reference or a lambda or a method group --
                // there is no way we can determine what type to search for user-defined operators.
                return(false);
            }

            // Spec 7.3.5 Candidate user-defined operators
            // SPEC: Given a type T and an operation op(A) ... the set of candidate user-defined
            // SPEC: operators provided by T for op(A) is determined as follows:

            // SPEC: If T is a nullable type then T0 is its underlying type; otherwise T0 is T.
            // SPEC: For all operator declarations in T0 and all lifted forms of such operators, if
            // SPEC: at least one operator is applicable with respect to A then the set of candidate
            // SPEC: operators consists of all such applicable operators. Otherwise, if T0 is object
            // SPEC: then the set of candidate operators is empty. Otherwise, the set of candidate
            // SPEC: operators is the set provided by the direct base class of T0, or the effective
            // SPEC: base class of T0 if T0 is a type parameter.

            // https://github.com/dotnet/roslyn/issues/34451: The spec quote should be adjusted to cover operators from interfaces as well.
            // From https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-27.md:
            // - We only even look for operator implementations in interfaces if one of the operands has a type that is an interface or
            // a type parameter with a non-empty effective base interface list.
            // - The applicable operators from classes / structs shadow those in interfaces.This matters for constrained type parameters:
            // the effective base class can shadow operators from effective base interfaces.
            // - If we find an applicable candidate in an interface, that candidate shadows all applicable operators in base interfaces:
            // we stop looking.

            TypeSymbol type0 = operand.Type.StrippedType();

            // Searching for user-defined operators is expensive; let's take an early out if we can.
            if (OperatorFacts.DefinitelyHasNoUserDefinedOperators(type0))
            {
                return(false);
            }

            string name      = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind);
            var    operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            bool hadApplicableCandidates = false;

            NamedTypeSymbol current = type0 as NamedTypeSymbol;

            if ((object)current == null)
            {
                current = type0.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }

            if ((object)current == null && type0.IsTypeParameter())
            {
                current = ((TypeParameterSymbol)type0).EffectiveBaseClass(ref useSiteDiagnostics);
            }

            for (; (object)current != null; current = current.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                operators.Clear();
                GetUserDefinedUnaryOperatorsFromType(current, kind, name, operators);
                results.Clear();
                if (CandidateOperators(operators, operand, results, ref useSiteDiagnostics))
                {
                    hadApplicableCandidates = true;
                    break;
                }
            }

            // Look in base interfaces, or effective interfaces for type parameters
            if (!hadApplicableCandidates)
            {
                ImmutableArray <NamedTypeSymbol> interfaces = default;
                if (type0.IsInterfaceType())
                {
                    interfaces = type0.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
                }
                else if (type0.IsTypeParameter())
                {
                    interfaces = ((TypeParameterSymbol)type0).AllEffectiveInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
                }

                if (!interfaces.IsDefaultOrEmpty)
                {
                    var shadowedInterfaces = PooledHashSet <NamedTypeSymbol> .GetInstance();

                    var resultsFromInterface = ArrayBuilder <UnaryOperatorAnalysisResult> .GetInstance();

                    results.Clear();

                    foreach (NamedTypeSymbol @interface in interfaces)
                    {
                        if ([email protected])
                        {
                            // this code could be reachable in error situations
                            continue;
                        }

                        if (shadowedInterfaces.Contains(@interface))
                        {
                            // this interface is "shadowed" by a derived interface
                            continue;
                        }

                        operators.Clear();
                        resultsFromInterface.Clear();
                        GetUserDefinedUnaryOperatorsFromType(@interface, kind, name, operators);
                        if (CandidateOperators(operators, operand, resultsFromInterface, ref useSiteDiagnostics))
                        {
                            hadApplicableCandidates = true;
                            results.AddRange(resultsFromInterface);

                            // this interface "shadows" all its base interfaces
                            shadowedInterfaces.AddAll(@interface.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics));
                        }
                    }

                    shadowedInterfaces.Free();
                    resultsFromInterface.Free();
                }
            }

            operators.Free();

            return(hadApplicableCandidates);
        }
Example #19
0
        internal static bool IsValidObjectEquality(Conversions Conversions, TypeSymbol leftType, bool leftIsNull, TypeSymbol rightType, bool rightIsNull, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // SPEC: The predefined reference type equality operators require one of the following:

            // SPEC: (1) Both operands are a value of a type known to be a reference-type or the literal null. 
            // SPEC:     Furthermore, an explicit reference conversion exists from the type of either 
            // SPEC:     operand to the type of the other operand. Or:
            // SPEC: (2) One operand is a value of type T where T is a type-parameter and the other operand is 
            // SPEC:     the literal null. Furthermore T does not have the value type constraint.

            // SPEC ERROR: Notice that the spec calls out that an explicit reference conversion must exist;
            // SPEC ERROR: in fact it should say that an explicit reference conversion, implicit reference
            // SPEC ERROR: conversion or identity conversion must exist. The conversion from object to object
            // SPEC ERROR: is not classified as a reference conversion at all; it is an identity conversion.

            // Dev10 does not follow the spec exactly for type parameters. Specifically, in Dev10,
            // if a type parameter argument is known to be a value type, or if a type parameter
            // argument is not known to be either a value type or reference type and the other
            // argument is not null, reference type equality cannot be applied. Otherwise, the
            // effective base class of the type parameter is used to determine the conversion
            // to the other argument type. (See ExpressionBinder::GetRefEqualSigs.)

            if (((object)leftType != null) && leftType.IsTypeParameter())
            {
                if (leftType.IsValueType || (!leftType.IsReferenceType && !rightIsNull))
                {
                    return false;
                }

                leftType = ((TypeParameterSymbol)leftType).EffectiveBaseClass(ref useSiteDiagnostics);
                Debug.Assert((object)leftType != null);
            }

            if (((object)rightType != null) && rightType.IsTypeParameter())
            {
                if (rightType.IsValueType || (!rightType.IsReferenceType && !leftIsNull))
                {
                    return false;
                }

                rightType = ((TypeParameterSymbol)rightType).EffectiveBaseClass(ref useSiteDiagnostics);
                Debug.Assert((object)rightType != null);
            }

            var leftIsReferenceType = ((object)leftType != null) && leftType.IsReferenceType;
            if (!leftIsReferenceType && !leftIsNull)
            {
                return false;
            }

            var rightIsReferenceType = ((object)rightType != null) && rightType.IsReferenceType;
            if (!rightIsReferenceType && !rightIsNull)
            {
                return false;
            }

            // If at least one side is null then clearly a conversion exists.
            if (leftIsNull || rightIsNull)
            {
                return true;
            }

            var leftConversion = Conversions.ClassifyConversion(leftType, rightType, ref useSiteDiagnostics);
            if (leftConversion.IsIdentity || leftConversion.IsReference)
            {
                return true;
            }

            var rightConversion = Conversions.ClassifyConversion(rightType, leftType, ref useSiteDiagnostics);
            if (rightConversion.IsIdentity || rightConversion.IsReference)
            {
                return true;
            }

            return false;
        }
Example #20
0
        internal ImmutableArray<CustomModifier> SubstituteCustomModifiers(TypeSymbol type, ImmutableArray<CustomModifier> customModifiers)
        {
            if (type.IsTypeParameter())
            {
                return new TypeWithModifiers(type, customModifiers).SubstituteType(this).CustomModifiers;
            }

            return SubstituteCustomModifiers(customModifiers);
        }
Example #21
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new subsitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution)
        {
            if (ReferenceEquals(t1, t2))
            {
                return(true);
            }
            else if ((object)t1 == null || (object)t2 == null)
            {
                // Can't both be null or they would have been ReferenceEquals
                return(false);
            }

            if (substitution != null)
            {
                t1 = substitution.SubstituteType(t1);
                t2 = substitution.SubstituteType(t2);
            }

            // If one of the types is a type parameter, then the substitution could make them ReferenceEquals.
            if (ReferenceEquals(t1, t2))
            {
                return(true);
            }

            // We can avoid a lot of redundant checks if we ensure that we only have to check
            // for type parameters on the LHS
            if (!t1.IsTypeParameter() && t2.IsTypeParameter())
            {
                TypeSymbol tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

            // If t1 is not a type parameter, then neither is t2
            Debug.Assert(t1.IsTypeParameter() || !t2.IsTypeParameter());

            switch (t1.Kind)
            {
            case SymbolKind.ArrayType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                ArrayTypeSymbol at1 = (ArrayTypeSymbol)t1;
                ArrayTypeSymbol at2 = (ArrayTypeSymbol)t2;

                if (at1.Rank != at2.Rank || !at1.CustomModifiers.SequenceEqual(at2.CustomModifiers))
                {
                    return(false);
                }

                return(CanUnifyHelper(at1.ElementType, at2.ElementType, ref substitution));
            }

            case SymbolKind.PointerType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                PointerTypeSymbol pt1 = (PointerTypeSymbol)t1;
                PointerTypeSymbol pt2 = (PointerTypeSymbol)t2;

                if (!pt1.CustomModifiers.SequenceEqual(pt2.CustomModifiers))
                {
                    return(false);
                }

                return(CanUnifyHelper(pt1.PointedAtType, pt2.PointedAtType, ref substitution));
            }

            case SymbolKind.NamedType:
            case SymbolKind.ErrorType:
            {
                if (t2.TypeKind != t1.TypeKind)
                {
                    return(false);
                }

                NamedTypeSymbol nt1 = (NamedTypeSymbol)t1;
                NamedTypeSymbol nt2 = (NamedTypeSymbol)t2;

                if (!nt1.IsGenericType)
                {
                    return(!nt2.IsGenericType && nt1 == nt2);
                }
                else if (!nt2.IsGenericType)
                {
                    return(false);
                }

                int arity = nt1.Arity;

                if (nt2.Arity != arity || nt2.OriginalDefinition != nt1.OriginalDefinition)
                {
                    return(false);
                }

                for (int i = 0; i < arity; i++)
                {
                    if (!CanUnifyHelper(nt1.TypeArgumentsNoUseSiteDiagnostics[i], nt2.TypeArgumentsNoUseSiteDiagnostics[i], ref substitution))
                    {
                        return(false);
                    }
                }

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                return((object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution));
            }

            case SymbolKind.TypeParameter:
            {
                // These substitutions are not allowed in C#
                if (t2.TypeKind == TypeKind.Pointer || t2.SpecialType == SpecialType.System_Void)
                {
                    return(false);
                }

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1;

                // Perform the "occurs check" - i.e. ensure that t2 doesn't contain t1 to avoid recursive types
                // Note: t2 can't be the same type param - we would have caught that with ReferenceEquals above
                if (Contains(t2, tp1))
                {
                    return(false);
                }

                if (substitution == null)
                {
                    substitution = new MutableTypeMap();
                }

                // MutableTypeMap.Add will throw if the key has already been added.  However,
                // if t1 was already in the substitution, it would have been substituted at the
                // start of this method and we wouldn't be here.
                substitution.Add(tp1, t2);

                return(true);
            }

            default:
            {
                return(t1 == t2);
            }
            }
        }
Example #22
0
        private static bool IsPossiblyByRefTypeParameter(TypeSymbol type)
        {
            if (type.IsTypeParameter())
            {
                return true;
            }

            if (type.IsErrorType())
            {
                var byRefReturnType = type as ByRefReturnErrorTypeSymbol;

                return ((object)byRefReturnType != null) && byRefReturnType.ReferencedType.IsTypeParameter();
            }

            return false;
        }
Example #23
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 #24
0
        private void EmitDefaultValue(TypeSymbol type, bool used, SyntaxNode syntaxNode)
        {
            if (used)
            {
                // default type parameter values must be emitted as 'initobj' regardless of constraints
                if (!type.IsTypeParameter())
                {
                    var constantValue = type.GetDefaultValue();
                    if (constantValue != null)
                    {
                        _builder.EmitConstantValue(constantValue);
                        return;
                    }
                }

                EmitInitObj(type, true, syntaxNode);
            }
        }
Example #25
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);
        }