public SynthesizedIntrinsicOperatorSymbol(TypeSymbol leftType, string name, TypeSymbol rightType, TypeSymbol returnType, bool isCheckedBuiltin)
        {
            if (leftType.Equals(rightType, ignoreCustomModifiers: true))
            {
                this.containingType = leftType;
            }
            else if (rightType.Equals(returnType, ignoreCustomModifiers: true))
            {
                this.containingType = rightType;
            }
            else
            {
                Debug.Assert(leftType.Equals(returnType, ignoreCustomModifiers: true));
                this.containingType = leftType;
            }

            this.name = name;
            this.returnType = returnType;

            Debug.Assert((leftType.IsDynamic() || rightType.IsDynamic()) == returnType.IsDynamic());
            Debug.Assert(containingType.IsDynamic() == returnType.IsDynamic());

            this.parameters = (new ParameterSymbol[] {new SynthesizedOperatorParameterSymbol(this, leftType, 0, "left"),
                                                      new SynthesizedOperatorParameterSymbol(this, rightType, 1, "right")}).AsImmutableOrNull();
            this.isCheckedBuiltin = isCheckedBuiltin;
        }
        public SynthesizedIntrinsicOperatorSymbol(TypeSymbol leftType, string name, TypeSymbol rightType, TypeSymbol returnType, bool isCheckedBuiltin)
        {
            if (leftType.Equals(rightType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds))
            {
                _containingType = leftType;
            }
            else if (rightType.Equals(returnType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds))
            {
                _containingType = rightType;
            }
            else
            {
                Debug.Assert(leftType.Equals(returnType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds));
                _containingType = leftType;
            }

            _name = name;
            _returnType = returnType;

            Debug.Assert((leftType.IsDynamic() || rightType.IsDynamic()) == returnType.IsDynamic());
            Debug.Assert(_containingType.IsDynamic() == returnType.IsDynamic());

            _parameters = (new ParameterSymbol[] {new SynthesizedOperatorParameterSymbol(this, leftType, 0, "left"),
                                                      new SynthesizedOperatorParameterSymbol(this, rightType, 1, "right")}).AsImmutableOrNull();
            _isCheckedBuiltin = isCheckedBuiltin;
        }
Exemplo n.º 3
0
        /// <param name="sourceType">Type that already has custom modifiers.</param>
        /// <param name="destinationType">Same as <paramref name="sourceType"/>, but without custom modifiers.  May differ in object/dynamic.</param>
        /// <param name="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param>
        /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param>
        /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns>
        internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly)
        {
            Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions));

            // NOTE: overrides can differ by object/dynamic.  If they do, we'll need to tweak newType before
            // we can use it in place of this.Type.  We do so by computing the dynamic transform flags that
            // code gen uses and then passing them to the dynamic type decoder that metadata reading uses.
            ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind);
            TypeSymbol typeWithDynamic = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags);

            TypeSymbol resultType;
            if (destinationType.ContainsTuple() && !sourceType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic))
            {
                // We also preserve tuple names, if present and different
                ImmutableArray<string> names = CSharpCompilation.TupleNamesEncoder.Encode(destinationType);
                resultType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeWithDynamic, containingAssembly, names);
            }
            else
            {
                resultType = typeWithDynamic;
            }

            Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames)); // Same custom modifiers as source type.
            Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); // Same object/dynamic and tuple names as destination type.
            return resultType;
        }
Exemplo n.º 4
0
        /// <param name="sourceType">Type that already has custom modifiers.</param>
        /// <param name="destinationType">Same as <paramref name="sourceType"/>, but without custom modifiers.  May differ in object/dynamic.</param>
        /// <param name="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param>
        /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param>
        /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns>
        internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly)
        {
            Debug.Assert(sourceType.Equals(destinationType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true));

            if (sourceType.ContainsTuple())
            {
                // TODO(https://github.com/dotnet/roslyn/issues/12389):
                // Need to save/restore tupleness as well
                if (sourceType.IsTupleType)
                {
                    Debug.Assert(destinationType.IsTupleType);
                    return destinationType;
                }

                ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind);
                TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags);

                Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiersAndArraySizesAndLowerBounds: false, ignoreDynamic: true)); // Same custom modifiers as source type.
                return resultType;
            }
            else
            {
                // NOTE: overrides can differ by object/dynamic.  If they do, we'll need to tweak newType before
                // we can use it in place of this.Type.  We do so by computing the dynamic transform flags that
                // code gen uses and then passing them to the dynamic type decoder that metadata reading uses.
                ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind);
                TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags);

                Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiersAndArraySizesAndLowerBounds: false, ignoreDynamic: true)); // Same custom modifiers as source type.
                Debug.Assert(resultType.Equals(destinationType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: false)); // Same object/dynamic as destination type.
                return resultType;
            }
        }
Exemplo n.º 5
0
        /// <param name="sourceType">Type that already has custom modifiers.</param>
        /// <param name="destinationType">Same as <paramref name="sourceType"/>, but without custom modifiers.  May differ in object/dynamic.</param>
        /// <param name="refKind"><see cref="RefKind"/> of the parameter of which this is the type (or <see cref="RefKind.None"/> for a return type.</param>
        /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param>
        /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns>
        internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, RefKind refKind, AssemblySymbol containingAssembly)
        {
            Debug.Assert(sourceType.Equals(destinationType, ignoreCustomModifiers: true, ignoreDynamic: true));

            // NOTE: overrides can differ by object/dynamic.  If they do, we'll need to tweak newType before
            // we can use it in place of this.Type.  We do so by computing the dynamic transform flags that
            // code gen uses and then passing them to the dynamic type decoder that metadata reading uses.

            const int customModifierCount = 0;// Ignore custom modifiers, since we're not done copying them.
            ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.Encode(destinationType, customModifierCount, refKind);
            TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags);

            Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiers: false, ignoreDynamic: true)); // Same custom modifiers as source type.
            Debug.Assert(resultType.Equals(destinationType, ignoreCustomModifiers: true, ignoreDynamic: false)); // Same object/dynamic as destination type.

            return resultType;
        }
Exemplo n.º 6
0
        /// <remarks>
        /// Out params are updated by assignment.  If you require thread-safety, pass temps and then
        /// CompareExchange them back into shared memory.
        /// </remarks>
        internal static void CopyMethodCustomModifiers(
            MethodSymbol sourceMethod,
            MethodSymbol destinationMethod,
            out TypeSymbol returnType,
            out ImmutableArray<CustomModifier> returnTypeCustomModifiers,
            out ushort countOfCustomModifiersPrecedingByRef,
            out ImmutableArray<ParameterSymbol> parameters,
            bool alsoCopyParamsModifier) // Last since always named.
        {
            Debug.Assert((object)sourceMethod != null);

            // Assert: none of the method's type parameters have been substituted
            Debug.Assert((object)sourceMethod == sourceMethod.ConstructedFrom);

            // For the most part, we will copy custom modifiers by copying types.
            // The only time when this fails is when the type refers to a type parameter
            // owned by the overridden method.  We need to replace all such references
            // with (equivalent) type parameters owned by this method.  We know that
            // we can perform this mapping positionally, because the method signatures
            // have already been compared.
            MethodSymbol constructedSourceMethod = sourceMethod.ConstructIfGeneric(destinationMethod.TypeArguments);

            returnTypeCustomModifiers = constructedSourceMethod.ReturnTypeCustomModifiers;
            countOfCustomModifiersPrecedingByRef = destinationMethod.ReturnsByRef ? constructedSourceMethod.CountOfCustomModifiersPrecedingByRef : (ushort)0;

            parameters = CopyParameterCustomModifiers(constructedSourceMethod.Parameters, destinationMethod.Parameters, alsoCopyParamsModifier);

            returnType = destinationMethod.ReturnType; // Default value - in case we don't copy the custom modifiers.

            // We do an extra check before copying the return type to handle the case where the overriding
            // method (incorrectly) has a different return type than the overridden method.  In such cases,
            // we want to retain the original (incorrect) return type to avoid hiding the return type
            // given in source.
            TypeSymbol returnTypeWithCustomModifiers = constructedSourceMethod.ReturnType;
            if (returnType.Equals(returnTypeWithCustomModifiers, TypeCompareKind.AllIgnoreOptions))
            {
                returnType = CopyTypeCustomModifiers(returnTypeWithCustomModifiers, returnType, destinationMethod.ContainingAssembly);
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Returns the better type amongst the two, with some possible modifications (dynamic/object or tuple names).
        /// </summary>
        private TypeSymbol Better(TypeSymbol type1, TypeSymbol type2, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // Anything is better than an error sym.
            if (type1.IsErrorType())
            {
                return type2;
            }

            if ((object)type2 == null || type2.IsErrorType())
            {
                return type1;
            }

            var t1tot2 = _conversions.ClassifyImplicitConversionFromType(type1, type2, ref useSiteDiagnostics).Exists;
            var t2tot1 = _conversions.ClassifyImplicitConversionFromType(type2, type1, ref useSiteDiagnostics).Exists;

            if (t1tot2 && t2tot1)
            {
                if (type1.IsDynamic())
                {
                    return type1;
                }

                if (type2.IsDynamic())
                {
                    return type2;
                }

                if (type1.Equals(type2, TypeCompareKind.IgnoreDynamicAndTupleNames))
                {
                    return MethodTypeInferrer.MergeTupleNames(type1, type2, MethodTypeInferrer.MergeDynamic(type1, type2, type1, _conversions.CorLibrary), _conversions.CorLibrary);
                }

                return null;
            }

            if (t1tot2)
            {
                return type2;
            }

            if (t2tot1)
            {
                return type1;
            }

            return null;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Takes the names from the two types, finds the common names, and applies them onto the target.
        /// </summary>
        internal static TypeSymbol MergeTupleNames(TypeSymbol first, TypeSymbol second, TypeSymbol target, AssemblySymbol corLibrary)
        {
            if (!target.ContainsTuple() ||
                first.Equals(second, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic) ||
                !target.ContainsTupleNames())
            {
                return target;
            }

            ImmutableArray<string> names1 = CSharpCompilation.TupleNamesEncoder.Encode(first);
            ImmutableArray<string> names2 = CSharpCompilation.TupleNamesEncoder.Encode(second);

            ImmutableArray<string> mergedNames;
            if (names1.IsDefault || names2.IsDefault)
            {
                mergedNames = default(ImmutableArray<string>);
            }
            else
            {
                Debug.Assert(names1.Length == names2.Length);
                mergedNames = names1.ZipAsArray(names2, (n1, n2) => string.CompareOrdinal(n1, n2) == 0 ? n1 : null);

                if (mergedNames.All(n => n == null))
                {
                    mergedNames = default(ImmutableArray<string>);
                }
            }

            return TupleTypeDecoder.DecodeTupleTypesIfApplicable(target, corLibrary, mergedNames);
        }
Exemplo n.º 9
0
        protected override Symbol RedirectTypeSymbol(Symbol symbol)
        {
            if (_currentBindSymbol == null || !(symbol is TypeParameterSymbol))
            {
                return(symbol);
            }

            TypeSymbol parameterSymbol = (TypeSymbol)symbol;

            int typeIdx    = -1;
            int arrayDepth = 0;

            while (parameterSymbol.IsArray)
            {
                arrayDepth++;
                parameterSymbol = parameterSymbol.ElementType;
            }

            if (arrayDepth > 0)
            {
                return(MakeArraySymbol((TypeSymbol)RedirectTypeSymbol(parameterSymbol), arrayDepth));
            }

            if (_currentBindSymbol is MethodSymbol currentMethodSymbol)
            {
                if (currentMethodSymbol.TypeArguments.Length > 0 && currentMethodSymbol.OriginalSymbol != null)
                {
                    MethodSymbol originalMethod = (MethodSymbol)currentMethodSymbol.OriginalSymbol;

                    for (int i = 0; i < originalMethod.TypeArguments.Length; ++i)
                    {
                        if (!parameterSymbol.Equals(originalMethod.TypeArguments[i]))
                        {
                            continue;
                        }
                        typeIdx = i;
                        break;
                    }

                    if (typeIdx != -1)
                    {
                        return(currentMethodSymbol.TypeArguments[typeIdx]);
                    }
                }
            }

            TypeSymbol containingType = _currentBindSymbol.ContainingType;

            if (containingType.TypeArguments.Length > 0 && containingType.OriginalSymbol != null)
            {
                TypeSymbol originalType = (TypeSymbol)containingType.OriginalSymbol;

                for (int i = 0; i < originalType.TypeArguments.Length; ++i)
                {
                    if (!parameterSymbol.Equals(originalType.TypeArguments[i]))
                    {
                        continue;
                    }
                    typeIdx = i;
                    break;
                }

                if (typeIdx != -1)
                {
                    return(containingType.TypeArguments[typeIdx]);
                }
            }

            return(symbol);
        }
Exemplo n.º 10
0
            // private static T <Factory>(object[] submissionArray)
            // {
            //     var submission = new Submission#N(submissionArray);
            //     return submission.<Initialize>();
            // }
            internal override BoundBlock CreateBody(DiagnosticBag diagnostics)
            {
                var syntax = DummySyntax();

                var ctor = _containingType.GetScriptConstructor();

                Debug.Assert(ctor.ParameterCount == 1);

                var initializer = _containingType.GetScriptInitializer();

                Debug.Assert(initializer.ParameterCount == 0);

                var submissionArrayParameter = new BoundParameter(syntax, _parameters[0])
                {
                    WasCompilerGenerated = true
                };
                var submissionLocal = new BoundLocal(
                    syntax,
                    new SynthesizedLocal(this, TypeSymbolWithAnnotations.Create(_containingType), SynthesizedLocalKind.LoweringTemp),
                    null,
                    _containingType)
                {
                    WasCompilerGenerated = true
                };

                // var submission = new Submission#N(submissionArray);
                var submissionAssignment = new BoundExpressionStatement(
                    syntax,
                    new BoundAssignmentOperator(
                        syntax,
                        submissionLocal,
                        new BoundObjectCreationExpression(
                            syntax,
                            ctor,
                            ImmutableArray.Create <BoundExpression>(submissionArrayParameter),
                            default(ImmutableArray <string>),
                            default(ImmutableArray <RefKind>),
                            false,
                            default(ImmutableArray <int>),
                            null,
                            null,
                            null,
                            _containingType)
                {
                    WasCompilerGenerated = true
                },
                        _containingType)
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };

                // return submission.<Initialize>();
                var initializeResult = CreateParameterlessCall(
                    syntax,
                    submissionLocal,
                    initializer);

                Debug.Assert(TypeSymbol.Equals(initializeResult.Type, _returnType.TypeSymbol, TypeCompareKind.ConsiderEverything2));
                var returnStatement = new BoundReturnStatement(
                    syntax,
                    RefKind.None,
                    initializeResult)
                {
                    WasCompilerGenerated = true
                };

                return(new BoundBlock(syntax,
                                      ImmutableArray.Create <LocalSymbol>(submissionLocal.LocalSymbol),
                                      ImmutableArray.Create <BoundStatement>(submissionAssignment, returnStatement))
                {
                    WasCompilerGenerated = true
                });
            }
Exemplo n.º 11
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 substitutions 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(TypeWithAnnotations t1, TypeWithAnnotations t2, ref MutableTypeMap substitution)
        {
            if (!t1.HasType || !t2.HasType)
            {
                return(t1.IsSameAs(t2));
            }

            if (TypeSymbol.Equals(t1.Type, t2.Type, TypeCompareKind.ConsiderEverything2) && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
            {
                return(true);
            }

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

            // If one of the types is a type parameter, then the substitution could make them equal.
            if (TypeSymbol.Equals(t1.Type, t2.Type, TypeCompareKind.ConsiderEverything2) && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
            {
                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.Type.IsTypeParameter() && t2.Type.IsTypeParameter())
            {
                TypeWithAnnotations tmp = t1;
                t1 = t2;
                t2 = tmp;
            }

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

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

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

                if (!at1.HasSameShapeAs(at2))
                {
                    return(false);
                }

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

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

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

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

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

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

                if (nt1.IsTupleType)
                {
                    if (!nt2.IsTupleType)
                    {
                        return(false);
                    }

                    return(CanUnifyHelper(nt1.TupleUnderlyingType, nt2.TupleUnderlyingType, ref substitution));
                }

                if (!nt1.IsGenericType)
                {
                    return(!nt2.IsGenericType && TypeSymbol.Equals(nt1, nt2, TypeCompareKind.ConsiderEverything2));
                }
                else if (!nt2.IsGenericType)
                {
                    return(false);
                }

                int arity = nt1.Arity;

                if (nt2.Arity != arity || !TypeSymbol.Equals(nt2.OriginalDefinition, nt1.OriginalDefinition, TypeCompareKind.ConsiderEverything2))
                {
                    return(false);
                }

                var nt1Arguments = nt1.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics;
                var nt2Arguments = nt2.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics;

                for (int i = 0; i < arity; i++)
                {
                    if (!CanUnifyHelper(nt1Arguments[i],
                                        nt2Arguments[i],
                                        ref substitution))
                    {
                        return(false);
                    }
                }

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                // TODO: Calling CanUnifyHelper for the containing type is an overkill, we simply need to go through type arguments for all containers.
                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.IsVoidType())
                {
                    return(false);
                }

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1.Type;

                // 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.Type, tp1))
                {
                    return(false);
                }

                if (t1.CustomModifiers.IsDefaultOrEmpty)
                {
                    AddSubstitution(ref substitution, tp1, t2);
                    return(true);
                }

                if (t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
                {
                    AddSubstitution(ref substitution, tp1, TypeWithAnnotations.Create(t2.Type));
                    return(true);
                }

                if (t1.CustomModifiers.Length < t2.CustomModifiers.Length &&
                    t1.CustomModifiers.SequenceEqual(t2.CustomModifiers.Take(t1.CustomModifiers.Length)))
                {
                    AddSubstitution(ref substitution, tp1,
                                    TypeWithAnnotations.Create(t2.Type,
                                                               customModifiers: ImmutableArray.Create(t2.CustomModifiers, t1.CustomModifiers.Length, t2.CustomModifiers.Length - t1.CustomModifiers.Length)));
                    return(true);
                }

                if (t2.Type.IsTypeParameter())
                {
                    var tp2 = (TypeParameterSymbol)t2.Type;

                    if (t2.CustomModifiers.IsDefaultOrEmpty)
                    {
                        AddSubstitution(ref substitution, tp2, t1);
                        return(true);
                    }

                    if (t2.CustomModifiers.Length < t1.CustomModifiers.Length &&
                        t2.CustomModifiers.SequenceEqual(t1.CustomModifiers.Take(t2.CustomModifiers.Length)))
                    {
                        AddSubstitution(ref substitution, tp2,
                                        TypeWithAnnotations.Create(t1.Type,
                                                                   customModifiers: ImmutableArray.Create(t1.CustomModifiers, t2.CustomModifiers.Length, t1.CustomModifiers.Length - t2.CustomModifiers.Length)));
                        return(true);
                    }
                }

                return(false);
            }

            default:
            {
                return(false);
            }
            }
        }
Exemplo n.º 12
0
 private static int?MostSpecificConversionOperator(TypeSymbol sx, TypeSymbol tx, ImmutableArray <UserDefinedConversionAnalysis> u)
 {
     return(MostSpecificConversionOperator(conv => TypeSymbol.Equals(conv.FromType, sx, TypeCompareKind.ConsiderEverything2) && TypeSymbol.Equals(conv.ToType, tx, TypeCompareKind.ConsiderEverything2), u));
 }
            /// <summary>
            /// Walks the bound tree and adds all non compiler generated bound nodes whose syntax matches the given one
            /// to the cache.
            /// </summary>
            /// <param name="root">The root of the bound tree.</param>
            /// <param name="map">The cache.</param>
            /// <param name="node">The syntax node where to add bound nodes for.</param>
            public static void AddToMap(BoundNode root, Dictionary <SyntaxNode, ImmutableArray <BoundNode> > map, SyntaxTree tree, SyntaxNode node = null)
            {
                Debug.Assert(node == null || root == null || !(root.Syntax is StatementSyntax), "individually added nodes are not supposed to be statements.");

                if (root == null || map.ContainsKey(root.Syntax))
                {
                    // root node is already in the map, children must be in the map too.
                    return;
                }

                var additionMap = OrderPreservingMultiDictionary <SyntaxNode, BoundNode> .GetInstance();

                var builder = new NodeMapBuilder(additionMap, tree, node);

                builder.Visit(root);

                foreach (CSharpSyntaxNode key in additionMap.Keys)
                {
                    if (map.ContainsKey(key))
                    {
#if DEBUG
                        // It's possible that AddToMap was previously called with a subtree of root.  If this is the case,
                        // then we'll see an entry in the map.  Since the incremental binder should also have seen the
                        // pre-existing map entry, the entry in addition map should be identical.
                        // Another, more unfortunate, possibility is that we've had to re-bind the syntax and the new bound
                        // nodes are equivalent, but not identical, to the existing ones.  In such cases, we prefer the
                        // existing nodes so that the cache will always return the same bound node for a given syntax node.

                        // EXAMPLE: Suppose we have the statement P.M(1);
                        // First, we ask for semantic info about "P".  We'll walk up to the statement level and bind that.
                        // We'll end up with map entries for "1", "P", "P.M(1)", and "P.M(1);".
                        // Next, we ask for semantic info about "P.M".  That isn't in our map, so we walk up to the statement
                        // level - again - and bind that - again.
                        // Once again, we'll end up with map entries for "1", "P", "P.M(1)", and "P.M(1);".  They will
                        // have the same structure as the original map entries, but will not be ReferenceEquals.

                        var existing = map[key];
                        var added    = additionMap[key];
                        Debug.Assert(existing.Length == added.Length, "existing.Length == added.Length");
                        for (int i = 0; i < existing.Length; i++)
                        {
                            // TODO: it would be great if we could check !ReferenceEquals(existing[i], added[i]) (DevDiv #11584).
                            // Known impediments include:
                            //   1) Field initializers aren't cached because they're not in statements.
                            //   2) Single local declarations (e.g. "int x = 1;" vs "int x = 1, y = 2;") aren't found in the cache
                            //      since nothing is cached for the statement syntax.
                            if (existing[i].Kind != added[i].Kind)
                            {
                                Debug.Assert(!(key is StatementSyntax), "!(key is StatementSyntax)");

                                // This also seems to be happening when we get equivalent BoundTypeExpression and BoundTypeOrValueExpression nodes.
                                if (existing[i].Kind == BoundKind.TypeExpression && added[i].Kind == BoundKind.TypeOrValueExpression)
                                {
                                    Debug.Assert(
                                        TypeSymbol.Equals(((BoundTypeExpression)existing[i]).Type, ((BoundTypeOrValueExpression)added[i]).Type, TypeCompareKind.ConsiderEverything2),
                                        string.Format(
                                            System.Globalization.CultureInfo.InvariantCulture,
                                            "((BoundTypeExpression)existing[{0}]).Type == ((BoundTypeOrValueExpression)added[{0}]).Type", i));
                                }
                                else if (existing[i].Kind == BoundKind.TypeOrValueExpression && added[i].Kind == BoundKind.TypeExpression)
                                {
                                    Debug.Assert(
                                        TypeSymbol.Equals(((BoundTypeOrValueExpression)existing[i]).Type, ((BoundTypeExpression)added[i]).Type, TypeCompareKind.ConsiderEverything2),
                                        string.Format(
                                            System.Globalization.CultureInfo.InvariantCulture,
                                            "((BoundTypeOrValueExpression)existing[{0}]).Type == ((BoundTypeExpression)added[{0}]).Type", i));
                                }
                                else
                                {
                                    Debug.Assert(false, "New bound node does not match existing bound node");
                                }
                            }
                            else
                            {
                                Debug.Assert(
                                    (object)existing[i] == added[i] || !(key is StatementSyntax),
                                    string.Format(
                                        System.Globalization.CultureInfo.InvariantCulture,
                                        "(object)existing[{0}] == added[{0}] || !(key is StatementSyntax)", i));
                            }
                        }
#endif
                    }
                    else
                    {
                        map[key] = additionMap[key];
                    }
                }

                additionMap.Free();
            }
        /// <summary>
        /// This method handles duplicate types in a few different ways:
        /// - for types before C# 7, the first candidate is returned with a warning
        /// - for types after C# 7, the type is considered missing
        /// - in both cases, when BinderFlags.IgnoreCorLibraryDuplicatedTypes is set, any duplicate coming from corlib will be ignored (ie not count as a duplicate)
        /// </summary>
        internal NamedTypeSymbol GetWellKnownType(WellKnownType type)
        {
            Debug.Assert(type.IsValid());

            bool ignoreCorLibraryDuplicatedTypes = this.Options.TopLevelBinderFlags.Includes(BinderFlags.IgnoreCorLibraryDuplicatedTypes);

            int index = (int)type - (int)WellKnownType.First;

            if (_lazyWellKnownTypes == null || (object)_lazyWellKnownTypes[index] == null)
            {
                if (_lazyWellKnownTypes == null)
                {
                    Interlocked.CompareExchange(ref _lazyWellKnownTypes, new NamedTypeSymbol[(int)WellKnownTypes.Count], null);
                }

                string          mdName   = type.GetMetadataName();
                var             warnings = DiagnosticBag.GetInstance();
                NamedTypeSymbol result;
                (AssemblySymbol, AssemblySymbol)conflicts = default;

                if (IsTypeMissing(type))
                {
                    result = null;
                }
                else
                {
                    // well-known types introduced before CSharp7 allow lookup ambiguity and report a warning
                    DiagnosticBag legacyWarnings = (type <= WellKnownType.CSharp7Sentinel) ? warnings : null;
                    result = this.Assembly.GetTypeByMetadataName(
                        mdName, includeReferences: true, useCLSCompliantNameArityEncoding: true, isWellKnownType: true, conflicts: out conflicts,
                        warnings: legacyWarnings, ignoreCorLibraryDuplicatedTypes: ignoreCorLibraryDuplicatedTypes);
                }

                if ((object)result == null)
                {
                    // TODO: should GetTypeByMetadataName rather return a missing symbol?
                    MetadataTypeName emittedName = MetadataTypeName.FromFullName(mdName, useCLSCompliantNameArityEncoding: true);
                    if (type.IsValueTupleType())
                    {
                        CSDiagnosticInfo errorInfo;
                        if (conflicts.Item1 is null)
                        {
                            Debug.Assert(conflicts.Item2 is null);
                            errorInfo = new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, emittedName.FullName);
                        }
                        else
                        {
                            errorInfo = new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, emittedName.FullName, conflicts.Item1, conflicts.Item2);
                        }

                        result = new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Assembly.Modules[0], ref emittedName, errorInfo, type);
                    }
                    else
                    {
                        result = new MissingMetadataTypeSymbol.TopLevel(this.Assembly.Modules[0], ref emittedName, type);
                    }
                }

                if ((object)Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null) != null)
                {
                    Debug.Assert(
                        TypeSymbol.Equals(result, _lazyWellKnownTypes[index], TypeCompareKind.ConsiderEverything2) || (_lazyWellKnownTypes[index].IsErrorType() && result.IsErrorType())
                        );
                }
                else
                {
                    AdditionalCodegenWarnings.AddRange(warnings);
                }

                warnings.Free();
            }

            return(_lazyWellKnownTypes[index]);
        }
        private int _hashCode; // computed on demand

        internal SubstitutedMethodSymbol(NamedTypeSymbol containingSymbol, MethodSymbol originalDefinition)
            : this(containingSymbol, containingSymbol.TypeSubstitution, originalDefinition, constructedFrom : null)
        {
            Debug.Assert(containingSymbol is SubstitutedNamedTypeSymbol || containingSymbol is SubstitutedErrorTypeSymbol);
            Debug.Assert(TypeSymbol.Equals(originalDefinition.ContainingType, containingSymbol.OriginalDefinition, TypeCompareKind.ConsiderEverything2));
        }
 private bool MatchesContainingType(TypeSymbol type)
 {
     return(type.Equals(this.ContainingType, ComparisonForUserDefinedOperators));
 }
Exemplo n.º 17
0
        /// <summary>
        /// This method finds an attribute by metadata name and signature. The algorithm for signature matching is similar to the one
        /// in Module.GetTargetAttributeSignatureIndex. Note, the signature matching is limited to primitive types
        /// and System.Type.  It will not match an arbitrary signature but it is sufficient to match the signatures of the current set of
        /// well known attributes.
        /// </summary>
        /// <param name="targetSymbol">The symbol which is the target of the attribute</param>
        /// <param name="description">The attribute to match.</param>
        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 ((object)ctor == 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.TypeSymbol;
                    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_Int8;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Byte:
                        foundMatch = specType == SpecialType.System_UInt8;
                        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_Float32;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Double:
                        foundMatch = specType == SpecialType.System_Float64;
                        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 ((object)lazySystemType == 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);
        }
        private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used)
        {
            Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2));
            BoundExpression loweredRight = VisitExpression(node.Right);

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var stores = ArrayBuilder <BoundExpression> .GetInstance();

            var  kind           = node.Operator.Kind;
            bool isChecked      = kind.IsChecked();
            var  binaryOperator = kind.Operator();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.
            BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Left, stores, temps);
            var             lhsRead        = MakeRValue(transformedLHS);
            BoundExpression rewrittenAssignment;

            rewrittenAssignment = rewriteAssignment(lhsRead);

            BoundExpression result = (temps.Count == 0 && stores.Count == 0) ?
                                     rewrittenAssignment :
                                     new BoundSequence(
                node.Syntax,
                temps.ToImmutable(),
                stores.ToImmutable(),
                rewrittenAssignment,
                rewrittenAssignment.Type);

            temps.Free();
            stores.Free();
            return(result);

            BoundExpression rewriteAssignment(BoundExpression leftRead)
            {
                SyntaxNode syntax = node.Syntax;

                // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
                // We need to generate
                //
                // xlhs = (FINAL)((LEFT)xlhs op rhs)
                //
                // And then wrap it up with the generated temporaries.
                //
                // (The right hand side has already been converted to the type expected by the operator.)

                BoundExpression opLHS = MakeConversionNode(
                    syntax: syntax,
                    rewrittenOperand: leftRead,
                    conversion: node.LeftConversion,
                    rewrittenType: node.Operator.LeftType,
                    @checked: isChecked);

                BoundExpression operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, isCompoundAssignment: true);

                BoundExpression opFinal = MakeConversionNode(
                    syntax: syntax,
                    rewrittenOperand: operand,
                    conversion: node.FinalConversion,
                    rewrittenType: node.Left.Type,
                    explicitCastInCode: false,
                    @checked: isChecked);

                return(MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true));
            }
        }
Exemplo n.º 19
0
        private void EmitConversionToEnumUnderlyingType(BoundBinaryOperator expression, bool @checked)
        {
            // If we are doing an enum addition or subtraction and the
            // underlying type is 8 or 16 bits then we will have done the operation in 32
            // bits and we need to convert back down to the smaller bit size
            // to [one|zero]extend the value
            // NOTE: we do not need to do this for bitwise operations since they will always
            //       result in a properly sign-extended result, assuming operands were sign extended
            //
            // If e is a value of enum type E and u is a value of underlying type u then:
            //
            // e + u --> (E)((U)e + u)
            // u + e --> (E)(u + (U)e)
            // e - e --> (U)((U)e - (U)e)
            // e - u --> (E)((U)e - u)
            // e & e --> (E)((U)e & (U)e)
            // e | e --> (E)((U)e | (U)e)
            // e ^ e --> (E)((U)e ^ (U)e)
            //
            // NOTE: (E) is actually emitted as (U) and in last 3 cases is not necessary.
            //
            // Due to a bug, the native compiler allows:
            //
            // u - e --> (E)(u - (U)e)
            //
            // And so Roslyn does as well.

            TypeSymbol enumType;

            switch (expression.OperatorKind.Operator() | expression.OperatorKind.OperandTypes())
            {
            case BinaryOperatorKind.EnumAndUnderlyingAddition:
            case BinaryOperatorKind.EnumSubtraction:
            case BinaryOperatorKind.EnumAndUnderlyingSubtraction:
                enumType = expression.Left.Type;
                break;

            case BinaryOperatorKind.EnumAnd:
            case BinaryOperatorKind.EnumOr:
            case BinaryOperatorKind.EnumXor:
                Debug.Assert(TypeSymbol.Equals(expression.Left.Type, expression.Right.Type, TypeCompareKind.ConsiderEverything2));
                enumType = null;
                break;

            case BinaryOperatorKind.UnderlyingAndEnumSubtraction:
            case BinaryOperatorKind.UnderlyingAndEnumAddition:
                enumType = expression.Right.Type;
                break;

            default:
                enumType = null;
                break;
            }

            if ((object)enumType == null)
            {
                return;
            }

            Debug.Assert(enumType.IsEnumType());

            SpecialType type = enumType.GetEnumUnderlyingType().SpecialType;

            switch (type)
            {
            case SpecialType.System_Byte:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt8, @checked);
                break;

            case SpecialType.System_SByte:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int8, @checked);
                break;

            case SpecialType.System_Int16:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int16, @checked);
                break;

            case SpecialType.System_UInt16:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt16, @checked);
                break;
            }
        }
Exemplo n.º 20
0
        internal NamedTypeSymbol GetTopLevelTypeByMetadataName(
            ref MetadataTypeName metadataName,
            AssemblyIdentity assemblyOpt,
            bool includeReferences,
            bool isWellKnownType,
            out (AssemblySymbol, AssemblySymbol) conflicts,
            DiagnosticBag warnings = null,
            bool ignoreCorLibraryDuplicatedTypes = false)
        {
            conflicts = default;
            NamedTypeSymbol result;

            // First try this assembly
            result = GetTopLevelTypeByMetadataName(this, ref metadataName, assemblyOpt);

            if (isWellKnownType && !IsValidWellKnownType(result))
            {
                result = null;
            }

            // ignore any types of the same name that might be in referenced assemblies (prefer the current assembly):
            if ((object)result != null || !includeReferences)
            {
                return(result);
            }

            Debug.Assert(this is SourceAssemblySymbol,
                         "Never include references for a non-source assembly, because they don't know about aliases.");

            var assemblies = ArrayBuilder <AssemblySymbol> .GetInstance();

            // ignore reference aliases if searching for a type from a specific assembly:
            if (assemblyOpt != null)
            {
                assemblies.AddRange(DeclaringCompilation.GetBoundReferenceManager().ReferencedAssemblies);
            }
            else
            {
                DeclaringCompilation.GetUnaliasedReferencedAssemblies(assemblies);
            }

            // Lookup in references
            foreach (var assembly in assemblies)
            {
                Debug.Assert(!(this is SourceAssemblySymbol && assembly.IsMissing)); // Non-source assemblies can have missing references

                NamedTypeSymbol candidate = GetTopLevelTypeByMetadataName(assembly, ref metadataName, assemblyOpt);

                if (isWellKnownType && !IsValidWellKnownType(candidate))
                {
                    candidate = null;
                }

                if ((object)candidate == null)
                {
                    continue;
                }

                if (candidate.IsHiddenByCodeAnalysisEmbeddedAttribute())
                {
                    continue;
                }

                Debug.Assert(!TypeSymbol.Equals(candidate, result, TypeCompareKind.ConsiderEverything2));

                if ((object)result != null)
                {
                    // duplicate
                    if (ignoreCorLibraryDuplicatedTypes)
                    {
                        if (IsInCorLib(candidate))
                        {
                            // ignore candidate
                            continue;
                        }
                        if (IsInCorLib(result))
                        {
                            // drop previous result
                            result = candidate;
                            continue;
                        }
                    }

                    if (warnings == null)
                    {
                        conflicts = (result.ContainingAssembly, candidate.ContainingAssembly);
                        result    = null;
                    }
                    else
                    {
                        // The predefined type '{0}' is defined in multiple assemblies in the global alias; using definition from '{1}'
                        warnings.Add(ErrorCode.WRN_MultiplePredefTypes, NoLocation.Singleton, result, result.ContainingAssembly);
                    }

                    break;
                }

                result = candidate;
            }

            assemblies.Free();
            return(result);
        }
Exemplo n.º 21
0
        // CONSIDER: if the parameters were computed lazily, ParameterCount could be overridden to fall back on the syntax (as in SourceMemberMethodSymbol).

        private SourcePropertySymbol(
            SourceMemberContainerTypeSymbol containingType,
            Binder bodyBinder,
            BasePropertyDeclarationSyntax syntax,
            string name,
            Location location,
            DiagnosticBag diagnostics)
        {
            // This has the value that IsIndexer will ultimately have, once we've populated the fields of this object.
            bool isIndexer = syntax.Kind() == SyntaxKind.IndexerDeclaration;
            var interfaceSpecifier = GetExplicitInterfaceSpecifier(syntax);
            bool isExplicitInterfaceImplementation = (interfaceSpecifier != null);

            _location = location;
            _containingType = containingType;
            _syntaxRef = syntax.GetReference();

            SyntaxTokenList modifiers = syntax.Modifiers;
            bodyBinder = bodyBinder.WithUnsafeRegionIfNecessary(modifiers);
            bodyBinder = bodyBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this);

            bool modifierErrors;
            _modifiers = MakeModifiers(modifiers, isExplicitInterfaceImplementation, isIndexer, location, diagnostics, out modifierErrors);
            this.CheckAccessibility(location, diagnostics);

            this.CheckModifiers(location, isIndexer, diagnostics);

            if (isIndexer && !isExplicitInterfaceImplementation)
            {
                // Evaluate the attributes immediately in case the IndexerNameAttribute has been applied.
                // NOTE: we want IsExplicitInterfaceImplementation, IsOverride, Locations, and the syntax reference
                // to be initialized before we pass this symbol to LoadCustomAttributes.

                // CONSIDER: none of the information from this early binding pass is cached.  Everything will
                // be re-bound when someone calls GetAttributes.  If this gets to be a problem, we could
                // always use the real attribute bag of this symbol and modify LoadAndValidateAttributes to
                // handle partially filled bags.
                CustomAttributesBag<CSharpAttributeData> temp = null;
                LoadAndValidateAttributes(OneOrMany.Create(this.CSharpSyntaxNode.AttributeLists), ref temp, earlyDecodingOnly: true);
                if (temp != null)
                {
                    Debug.Assert(temp.IsEarlyDecodedWellKnownAttributeDataComputed);
                    var propertyData = (PropertyEarlyWellKnownAttributeData)temp.EarlyDecodedWellKnownAttributeData;
                    if (propertyData != null)
                    {
                        _sourceName = propertyData.IndexerName;
                    }
                }
            }

            string aliasQualifierOpt;
            string memberName = ExplicitInterfaceHelpers.GetMemberNameAndInterfaceSymbol(bodyBinder, interfaceSpecifier, name, diagnostics, out _explicitInterfaceType, out aliasQualifierOpt);
            _sourceName = _sourceName ?? memberName; //sourceName may have been set while loading attributes
            _name = isIndexer ? ExplicitInterfaceHelpers.GetMemberName(WellKnownMemberNames.Indexer, _explicitInterfaceType, aliasQualifierOpt) : _sourceName;
            _isExpressionBodied = false;

            bool hasAccessorList = syntax.AccessorList != null;
            var propertySyntax = syntax as PropertyDeclarationSyntax;
            var arrowExpression = propertySyntax != null
                ? propertySyntax.ExpressionBody
                : ((IndexerDeclarationSyntax)syntax).ExpressionBody;
            bool hasExpressionBody = arrowExpression != null;
            bool hasInitializer = !isIndexer && propertySyntax.Initializer != null;

            bool notRegularProperty = (!IsAbstract && !IsExtern && !isIndexer && hasAccessorList);
            AccessorDeclarationSyntax getSyntax = null;
            AccessorDeclarationSyntax setSyntax = null;
            if (hasAccessorList)
            {
                foreach (var accessor in syntax.AccessorList.Accessors)
                {
                    if (accessor.Kind() == SyntaxKind.GetAccessorDeclaration &&
                        (getSyntax == null || getSyntax.Keyword.Span.IsEmpty))
                    {
                        getSyntax = accessor;
                    }
                    else if (accessor.Kind() == SyntaxKind.SetAccessorDeclaration &&
                        (setSyntax == null || setSyntax.Keyword.Span.IsEmpty))
                    {
                        setSyntax = accessor;
                    }
                    else
                    {
                        continue;
                    }

                    if (accessor.Body != null)
                    {
                        notRegularProperty = false;
                    }
                }
            }
            else
            {
                notRegularProperty = false;
            }

            if (hasInitializer)
            {
                CheckInitializer(hasExpressionBody, notRegularProperty, location, diagnostics);
            }

            if (notRegularProperty || hasInitializer)
            {
                var hasGetSyntax = getSyntax != null;
                _isAutoProperty = notRegularProperty && hasGetSyntax;
                bool isReadOnly = hasGetSyntax && setSyntax == null;

                if (_isAutoProperty || hasInitializer)
                {
                    if (_isAutoProperty)
                    {
                        //issue a diagnostic if the compiler generated attribute ctor is not found.
                        Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(bodyBinder.Compilation,
                        WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor, diagnostics, syntax: syntax);
                    }

                    string fieldName = GeneratedNames.MakeBackingFieldName(_sourceName);
                    _backingField = new SynthesizedBackingFieldSymbol(this,
                                                                          fieldName,
                                                                          isReadOnly,
                                                                          this.IsStatic,
                                                                          hasInitializer);
                }

                if (notRegularProperty)
                {
                    Binder.CheckFeatureAvailability(location, 
                                                    isReadOnly ? MessageID.IDS_FeatureReadonlyAutoImplementedProperties : 
                                                                 MessageID.IDS_FeatureAutoImplementedProperties, 
                                                    diagnostics);
                }
            }

            PropertySymbol explicitlyImplementedProperty = null;
            _typeCustomModifiers = ImmutableArray<CustomModifier>.Empty;

            // The runtime will not treat the accessors of this property as overrides or implementations
            // of those of another property unless both the signatures and the custom modifiers match.
            // Hence, in the case of overrides and *explicit* implementations, we need to copy the custom
            // modifiers that are in the signatures of the overridden/implemented property accessors.
            // (From source, we know that there can only be one overridden/implemented property, so there
            // are no conflicts.)  This is unnecessary for implicit implementations because, if the custom
            // modifiers don't match, we'll insert bridge methods for the accessors (explicit implementations 
            // that delegate to the implicit implementations) with the correct custom modifiers
            // (see SourceNamedTypeSymbol.ImplementInterfaceMember).

            // Note: we're checking if the syntax indicates explicit implementation rather,
            // than if explicitInterfaceType is null because we don't want to look for an
            // overridden property if this is supposed to be an explicit implementation.
            if (isExplicitInterfaceImplementation || this.IsOverride)
            {
                // Type and parameters for overrides and explicit implementations cannot be bound
                // lazily since the property name depends on the metadata name of the base property,
                // and the property name is required to add the property to the containing type, and
                // the type and parameters are required to determine the override or implementation.
                _lazyType = this.ComputeType(bodyBinder, syntax, diagnostics);
                _lazyParameters = this.ComputeParameters(bodyBinder, syntax, diagnostics);

                bool isOverride = false;
                PropertySymbol overriddenOrImplementedProperty = null;

                if (!isExplicitInterfaceImplementation)
                {
                    // If this property is an override, we may need to copy custom modifiers from
                    // the overridden property (so that the runtime will recognize it as an override).
                    // We check for this case here, while we can still modify the parameters and
                    // return type without losing the appearance of immutability.
                    isOverride = true;
                    overriddenOrImplementedProperty = this.OverriddenProperty;
                }
                else
                {
                    string interfacePropertyName = isIndexer ? WellKnownMemberNames.Indexer : name;
                    explicitlyImplementedProperty = this.FindExplicitlyImplementedProperty(_explicitInterfaceType, interfacePropertyName, interfaceSpecifier, diagnostics);
                    overriddenOrImplementedProperty = explicitlyImplementedProperty;
                }

                if ((object)overriddenOrImplementedProperty != null)
                {
                    _typeCustomModifiers = overriddenOrImplementedProperty.TypeCustomModifiers;

                    TypeSymbol overriddenPropertyType = overriddenOrImplementedProperty.Type;

                    // We do an extra check before copying the type to handle the case where the overriding
                    // property (incorrectly) has a different type than the overridden property.  In such cases,
                    // we want to retain the original (incorrect) type to avoid hiding the type given in source.
                    if (_lazyType.Equals(overriddenPropertyType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: false))
                    {
                        _lazyType = overriddenPropertyType;
                    }

                    _lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
                }
            }

            if (!hasAccessorList)
            {
                if (hasExpressionBody)
                {
                    _isExpressionBodied = true;
                    _getMethod = SourcePropertyAccessorSymbol.CreateAccessorSymbol(
                        containingType,
                        this,
                        _modifiers,
                        _sourceName,
                        arrowExpression,
                        explicitlyImplementedProperty,
                        aliasQualifierOpt,
                        diagnostics);
                }
                else
                {
                    _getMethod = null;
                }
                _setMethod = null;
            }
            else
            {
                _getMethod = CreateAccessorSymbol(getSyntax, explicitlyImplementedProperty, aliasQualifierOpt, notRegularProperty, diagnostics);
                _setMethod = CreateAccessorSymbol(setSyntax, explicitlyImplementedProperty, aliasQualifierOpt, notRegularProperty, diagnostics);

                if ((getSyntax == null) || (setSyntax == null))
                {
                    if ((getSyntax == null) && (setSyntax == null))
                    {
                        diagnostics.Add(ErrorCode.ERR_PropertyWithNoAccessors, location, this);
                    }
                    else if (notRegularProperty)
                    {
                        var accessor = _getMethod ?? _setMethod;
                        if (getSyntax == null)
                        {
                            diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, accessor.Locations[0], accessor);
                        }
                    }
                }

                // Check accessor accessibility is more restrictive than property accessibility.
                CheckAccessibilityMoreRestrictive(_getMethod, diagnostics);
                CheckAccessibilityMoreRestrictive(_setMethod, diagnostics);

                if (((object)_getMethod != null) && ((object)_setMethod != null))
                {
                    // Check accessibility is set on at most one accessor.
                    if ((_getMethod.LocalAccessibility != Accessibility.NotApplicable) &&
                        (_setMethod.LocalAccessibility != Accessibility.NotApplicable))
                    {
                        diagnostics.Add(ErrorCode.ERR_DuplicatePropertyAccessMods, location, this);
                    }
                    else if (this.IsAbstract)
                    {
                        // Check abstract property accessors are not private.
                        CheckAbstractPropertyAccessorNotPrivate(_getMethod, diagnostics);
                        CheckAbstractPropertyAccessorNotPrivate(_setMethod, diagnostics);
                    }
                }
                else
                {
                    if (!this.IsOverride)
                    {
                        var accessor = _getMethod ?? _setMethod;
                        if ((object)accessor != null)
                        {
                            // Check accessibility is not set on the one accessor.
                            if (accessor.LocalAccessibility != Accessibility.NotApplicable)
                            {
                                diagnostics.Add(ErrorCode.ERR_AccessModMissingAccessor, location, this);
                            }
                        }
                    }
                }
            }

            if ((object)explicitlyImplementedProperty != null)
            {
                CheckExplicitImplementationAccessor(this.GetMethod, explicitlyImplementedProperty.GetMethod, explicitlyImplementedProperty, diagnostics);
                CheckExplicitImplementationAccessor(this.SetMethod, explicitlyImplementedProperty.SetMethod, explicitlyImplementedProperty, diagnostics);
            }

            _explicitInterfaceImplementations =
                (object)explicitlyImplementedProperty == null ?
                    ImmutableArray<PropertySymbol>.Empty :
                    ImmutableArray.Create(explicitlyImplementedProperty);

            // get-only auto property should not override settable properties
            if (_isAutoProperty && (object)_setMethod == null && !this.IsReadOnly)
            {
                diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, location, this);
            }
        }
Exemplo n.º 22
0
        private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used)
        {
            Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2));
            BoundExpression loweredRight = VisitExpression(node.Right);

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var stores = ArrayBuilder <BoundExpression> .GetInstance();

            var  kind           = node.Operator.Kind;
            bool isChecked      = kind.IsChecked();
            bool isDynamic      = kind.IsDynamic();
            var  binaryOperator = kind.Operator();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.
            BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Left, stores, temps, isDynamic);
            var             lhsRead        = MakeRValue(transformedLHS);
            BoundExpression rewrittenAssignment;

            if (node.Left.Kind == BoundKind.DynamicMemberAccess &&
                (binaryOperator == BinaryOperatorKind.Addition || binaryOperator == BinaryOperatorKind.Subtraction))
            {
                // If this could be an event assignment at runtime, we need to rewrite to the following form:
                // Original:
                //   receiver.EV += handler
                // Rewritten:
                //   dynamic memberAccessReceiver = receiver;
                //   bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV");
                //   dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null;
                //   var loweredRight = handler; // Only necessary if handler can change values, or is something like a lambda
                //   isEvent ? add_Event(memberAccessReceiver, "EV", loweredRight) : transformedLHS = storeNonEvent + loweredRight;
                //
                // This is to ensure that if handler is something like a lambda, we evaluate fully evaluate the left
                // side before storing the lambda to a temp for use in both possible branches.
                // The first store to memberAccessReceiver has already been taken care of above by TransformCompoundAssignmentLHS

                var eventTemps = ArrayBuilder <LocalSymbol> .GetInstance();

                var sequence = ArrayBuilder <BoundExpression> .GetInstance();

                //   dynamic memberAccessReceiver = receiver;
                var memberAccess = (BoundDynamicMemberAccess)transformedLHS;

                //   bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV");
                var isEvent = _factory.StoreToTemp(_dynamicFactory.MakeDynamicIsEventTest(memberAccess.Name, memberAccess.Receiver).ToExpression(), out BoundAssignmentOperator isEventAssignment);
                eventTemps.Add(isEvent.LocalSymbol);
                sequence.Add(isEventAssignment);

                // dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null;
                lhsRead = _factory.StoreToTemp(lhsRead, out BoundAssignmentOperator receiverAssignment);
                eventTemps.Add(((BoundLocal)lhsRead).LocalSymbol);
                var storeNonEvent = _factory.StoreToTemp(_factory.Conditional(_factory.Not(isEvent), receiverAssignment, _factory.Null(receiverAssignment.Type), receiverAssignment.Type), out BoundAssignmentOperator nonEventStore);
                eventTemps.Add(storeNonEvent.LocalSymbol);
                sequence.Add(nonEventStore);

                // var loweredRight = handler;
                if (CanChangeValueBetweenReads(loweredRight))
                {
                    loweredRight = _factory.StoreToTemp(loweredRight, out BoundAssignmentOperator possibleHandlerAssignment);
                    eventTemps.Add(((BoundLocal)loweredRight).LocalSymbol);
                    sequence.Add(possibleHandlerAssignment);
                }

                // add_Event(t1, "add_EV");
                var invokeEventAccessor = _dynamicFactory.MakeDynamicEventAccessorInvocation(
                    (binaryOperator == BinaryOperatorKind.Addition ? "add_" : "remove_") + memberAccess.Name,
                    memberAccess.Receiver,
                    loweredRight);

                // transformedLHS = storeNonEvent + loweredRight
                rewrittenAssignment = rewriteAssignment(lhsRead);
                Debug.Assert(rewrittenAssignment.Type is { });
 internal bool IsReadOnlySpanType(TypeSymbol type)
 {
     return(TypeSymbol.Equals(type.OriginalDefinition, GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.ConsiderEverything2));
 }
Exemplo n.º 24
0
        public override BoundNode VisitArrayAccess(BoundArrayAccess node)
        {
            // https://github.com/dotnet/roslyn/issues/30620
            // If the array access index is of type System.Index or System.Range
            // we need to emit code as if there were a real indexer, instead
            // of a simple array element access.

            if (node.Indices.Length != 1)
            {
                return(base.VisitArrayAccess(node));
            }

            TypeSymbol rawIndexType = node.Indices[0].Type;

            if (!(TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything) ||
                  TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything)))
            {
                return(base.VisitArrayAccess(node));
            }

            var syntax     = node.Syntax;
            var F          = _factory;
            var indexLocal = F.StoreToTemp(
                VisitExpression(node.Indices[0]),
                out BoundAssignmentOperator indexAssign);
            var arrayLocal = F.StoreToTemp(
                VisitExpression(node.Expression),
                out BoundAssignmentOperator arrayAssign);
            var indexType = VisitType(node.Indices[0].Type);

            var indexValueSymbol   = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__Value);
            var indexFromEndSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__FromEnd);

            BoundExpression resultExpr;

            if (TypeSymbol.Equals(indexType, _compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything))
            {
                // array[Index] is translated to:
                // array[index.FromEnd ? array.Length - index.Value : index.Value]

                var indexValueExpr = F.Property(indexLocal, indexValueSymbol);

                resultExpr = F.Sequence(
                    ImmutableArray.Create <LocalSymbol>(
                        indexLocal.LocalSymbol,
                        arrayLocal.LocalSymbol),
                    ImmutableArray.Create <BoundExpression>(
                        indexAssign,
                        arrayAssign),
                    F.ArrayAccess(arrayLocal, ImmutableArray.Create(
                                      F.Conditional(
                                          F.Property(indexLocal, indexFromEndSymbol),
                                          F.Binary(
                                              BinaryOperatorKind.Subtraction,
                                              F.SpecialType(SpecialType.System_Int32),
                                              F.ArrayLength(arrayLocal),
                                              indexValueExpr),
                                          indexValueExpr,
                                          node.Type))));
            }
            else if (TypeSymbol.Equals(indexType, _compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything))
            {
                // array[Range] is translated to:
                // var start = range.Start.FromEnd ? array.Length - range.Start.Value : range.Start.Value;
                // var end = range.End.FromEnd ? array.Length - range.End.Value : range.End.Value;
                // var length = end - start;
                // var newArr = new T[length];
                // Array.Copy(array, start, newArr, 0, length);
                // push newArray

                var rangeStartSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Range__Start);
                var rangeEndSymbol   = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Range__End);
                var arrayCopySymbol  = F.WellKnownMethod(WellKnownMember.System_Array__Copy);

                var startLocal = F.StoreToTemp(
                    F.Conditional(
                        F.Property(F.Property(indexLocal, rangeStartSymbol), indexFromEndSymbol),
                        F.Binary(
                            BinaryOperatorKind.Subtraction,
                            F.SpecialType(SpecialType.System_Int32),
                            F.ArrayLength(arrayLocal),
                            F.Property(F.Property(indexLocal, rangeStartSymbol), indexValueSymbol)),
                        F.Property(F.Property(indexLocal, rangeStartSymbol), indexValueSymbol),
                        F.SpecialType(SpecialType.System_Int32)),
                    out BoundAssignmentOperator startAssign);
                var endLocal = F.StoreToTemp(
                    F.Conditional(
                        F.Property(F.Property(indexLocal, rangeEndSymbol), indexFromEndSymbol),
                        F.Binary(
                            BinaryOperatorKind.Subtraction,
                            F.SpecialType(SpecialType.System_Int32),
                            F.ArrayLength(arrayLocal),
                            F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol)),
                        F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol),
                        F.SpecialType(SpecialType.System_Int32)),
                    out BoundAssignmentOperator endAssign);
                var lengthLocal = F.StoreToTemp(
                    F.Binary(BinaryOperatorKind.Subtraction, F.SpecialType(SpecialType.System_Int32), endLocal, startLocal),
                    out BoundAssignmentOperator lengthAssign);
                var elementType = ((ArrayTypeSymbol)node.Type).ElementType.TypeSymbol;
                var newArrLocal = F.StoreToTemp(F.Array(elementType, lengthLocal), out BoundAssignmentOperator newArrAssign);
                var copyExpr    = F.Call(null, arrayCopySymbol, ImmutableArray.Create <BoundExpression>(
                                             arrayLocal,
                                             startLocal,
                                             newArrLocal,
                                             F.Literal(0),
                                             lengthLocal));
                resultExpr = F.Sequence(
                    ImmutableArray.Create(
                        indexLocal.LocalSymbol,
                        arrayLocal.LocalSymbol,
                        startLocal.LocalSymbol,
                        endLocal.LocalSymbol,
                        lengthLocal.LocalSymbol,
                        newArrLocal.LocalSymbol),
                    ImmutableArray.Create <BoundExpression>(
                        indexAssign,
                        arrayAssign,
                        startAssign,
                        endAssign,
                        lengthAssign,
                        newArrAssign,
                        copyExpr),
                    newArrLocal);
            }
            else
            {
                throw ExceptionUtilities.Unreachable;
            }
            return(resultExpr);
        }
 internal override bool IsSystemTypeReference(ITypeSymbol type)
 {
     return(TypeSymbol.Equals((TypeSymbol)type, GetWellKnownType(WellKnownType.System_Type), TypeCompareKind.ConsiderEverything2));
 }
Exemplo n.º 26
0
        internal EEMethodSymbol(
            EENamedTypeSymbol container,
            string name,
            Location location,
            MethodSymbol sourceMethod,
            ImmutableArray <LocalSymbol> sourceLocals,
            ImmutableArray <LocalSymbol> sourceLocalsForBinding,
            ImmutableDictionary <string, DisplayClassVariable> sourceDisplayClassVariables,
            GenerateMethodBody generateMethodBody)
        {
            Debug.Assert(sourceMethod.IsDefinition);
            Debug.Assert(TypeSymbol.Equals((TypeSymbol)sourceMethod.ContainingSymbol, container.SubstitutedSourceType.OriginalDefinition, TypeCompareKind.ConsiderEverything2));
            Debug.Assert(sourceLocals.All(l => l.ContainingSymbol == sourceMethod));

            _container = container;
            _name      = name;
            _locations = ImmutableArray.Create(location);

            // What we want is to map all original type parameters to the corresponding new type parameters
            // (since the old ones have the wrong owners).  Unfortunately, we have a circular dependency:
            //   1) Each new type parameter requires the entire map in order to be able to construct its constraint list.
            //   2) The map cannot be constructed until all new type parameters exist.
            // Our solution is to pass each new type parameter a lazy reference to the type map.  We then
            // initialize the map as soon as the new type parameters are available - and before they are
            // handed out - so that there is never a period where they can require the type map and find
            // it uninitialized.

            var sourceMethodTypeParameters = sourceMethod.TypeParameters;
            var allSourceTypeParameters    = container.SourceTypeParameters.Concat(sourceMethodTypeParameters);

            var getTypeMap = new Func <TypeMap>(() => this.TypeMap);

            _typeParameters = sourceMethodTypeParameters.SelectAsArray(
                (tp, i, arg) => (TypeParameterSymbol) new EETypeParameterSymbol(this, tp, i, getTypeMap),
                (object)null);
            _allTypeParameters = container.TypeParameters.Concat(_typeParameters);
            this.TypeMap       = new TypeMap(allSourceTypeParameters, _allTypeParameters);

            EENamedTypeSymbol.VerifyTypeParameters(this, _typeParameters);

            var substitutedSourceType = container.SubstitutedSourceType;

            this.SubstitutedSourceMethod = sourceMethod.AsMember(substitutedSourceType);
            if (sourceMethod.Arity > 0)
            {
                this.SubstitutedSourceMethod = this.SubstitutedSourceMethod.Construct(_typeParameters.As <TypeSymbol>());
            }
            TypeParameterChecker.Check(this.SubstitutedSourceMethod, _allTypeParameters);

            // Create a map from original parameter to target parameter.
            var parameterBuilder = ArrayBuilder <ParameterSymbol> .GetInstance();

            var substitutedSourceThisParameter    = this.SubstitutedSourceMethod.ThisParameter;
            var substitutedSourceHasThisParameter = (object)substitutedSourceThisParameter != null;

            if (substitutedSourceHasThisParameter)
            {
                _thisParameter = MakeParameterSymbol(0, GeneratedNames.ThisProxyFieldName(), substitutedSourceThisParameter);
                Debug.Assert(TypeSymbol.Equals(_thisParameter.Type, this.SubstitutedSourceMethod.ContainingType, TypeCompareKind.ConsiderEverything2));
                parameterBuilder.Add(_thisParameter);
            }

            var ordinalOffset = (substitutedSourceHasThisParameter ? 1 : 0);

            foreach (var substitutedSourceParameter in this.SubstitutedSourceMethod.Parameters)
            {
                var ordinal = substitutedSourceParameter.Ordinal + ordinalOffset;
                Debug.Assert(ordinal == parameterBuilder.Count);
                var parameter = MakeParameterSymbol(ordinal, substitutedSourceParameter.Name, substitutedSourceParameter);
                parameterBuilder.Add(parameter);
            }

            _parameters = parameterBuilder.ToImmutableAndFree();

            var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            var localsMap = PooledDictionary <LocalSymbol, LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocals)
            {
                var local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                localsMap.Add(sourceLocal, local);
                localsBuilder.Add(local);
            }
            this.Locals   = localsBuilder.ToImmutableAndFree();
            localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocalsForBinding)
            {
                LocalSymbol local;
                if (!localsMap.TryGetValue(sourceLocal, out local))
                {
                    local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                    localsMap.Add(sourceLocal, local);
                }
                localsBuilder.Add(local);
            }
            this.LocalsForBinding = localsBuilder.ToImmutableAndFree();

            // Create a map from variable name to display class field.
            var displayClassVariables = PooledDictionary <string, DisplayClassVariable> .GetInstance();

            foreach (var pair in sourceDisplayClassVariables)
            {
                var variable = pair.Value;
                var oldDisplayClassInstance = variable.DisplayClassInstance;

                // Note: we don't call ToOtherMethod in the local case because doing so would produce
                // a new LocalSymbol that would not be ReferenceEquals to the one in this.LocalsForBinding.
                var oldDisplayClassInstanceFromLocal = oldDisplayClassInstance as DisplayClassInstanceFromLocal;
                var newDisplayClassInstance          = (oldDisplayClassInstanceFromLocal == null) ?
                                                       oldDisplayClassInstance.ToOtherMethod(this, this.TypeMap) :
                                                       new DisplayClassInstanceFromLocal((EELocalSymbol)localsMap[oldDisplayClassInstanceFromLocal.Local]);

                variable = variable.SubstituteFields(newDisplayClassInstance, this.TypeMap);
                displayClassVariables.Add(pair.Key, variable);
            }

            _displayClassVariables = displayClassVariables.ToImmutableDictionary();
            displayClassVariables.Free();
            localsMap.Free();

            _generateMethodBody = generateMethodBody;
        }
Exemplo n.º 27
0
 public static CSharpAttributeData GetAttribute(this Symbol @this, NamedTypeSymbol c)
 {
     return(@this.GetAttributes().Where(a => TypeSymbol.Equals(a.AttributeClass, c, TypeCompareKind.ConsiderEverything2)).First());
 }
Exemplo n.º 28
0
        private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used)
        {
            Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2));
            BoundExpression loweredRight = VisitExpression(node.Right);

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var stores = ArrayBuilder <BoundExpression> .GetInstance();

            var  kind           = node.Operator.Kind;
            bool isChecked      = kind.IsChecked();
            bool isDynamic      = kind.IsDynamic();
            var  binaryOperator = kind.Operator();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.
            BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Left, stores, temps, isDynamic);
            var             lhsRead        = MakeRValue(transformedLHS);
            BoundExpression rewrittenAssignment;

            if (node.Left.Kind == BoundKind.DynamicMemberAccess &&
                (binaryOperator == BinaryOperatorKind.Addition || binaryOperator == BinaryOperatorKind.Subtraction))
            {
                // If this could be an event assignment at runtime, we need to rewrite to the following form:
                // Original:
                //   receiver.EV += handler
                // Rewritten:
                //   dynamic memberAccessReceiver = receiver;
                //   bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV");
                //   dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null;
                //   var loweredRight = handler; // Only necessary if handler can change values, or is something like a lambda
                //   isEvent ? add_Event(memberAccessReceiver, "EV", loweredRight) : transformedLHS = storeNonEvent + loweredRight;
                //
                // This is to ensure that if handler is something like a lambda, we evaluate fully evaluate the left
                // side before storing the lambda to a temp for use in both possible branches.
                // The first store to memberAccessReceiver has already been taken care of above by TransformCompoundAssignmentLHS

                var eventTemps = ArrayBuilder <LocalSymbol> .GetInstance();

                var sequence = ArrayBuilder <BoundExpression> .GetInstance();

                //   dynamic memberAccessReceiver = receiver;
                var memberAccess = (BoundDynamicMemberAccess)transformedLHS;

                //   bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV");
                var isEvent = _factory.StoreToTemp(_dynamicFactory.MakeDynamicIsEventTest(memberAccess.Name, memberAccess.Receiver).ToExpression(), out BoundAssignmentOperator isEventAssignment);
                eventTemps.Add(isEvent.LocalSymbol);
                sequence.Add(isEventAssignment);

                // dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null;
                lhsRead = _factory.StoreToTemp(lhsRead, out BoundAssignmentOperator receiverAssignment);
                eventTemps.Add(((BoundLocal)lhsRead).LocalSymbol);
                var storeNonEvent = _factory.StoreToTemp(_factory.Conditional(_factory.Not(isEvent), receiverAssignment, _factory.Null(receiverAssignment.Type), receiverAssignment.Type), out BoundAssignmentOperator nonEventStore);
                eventTemps.Add(storeNonEvent.LocalSymbol);
                sequence.Add(nonEventStore);

                // var loweredRight = handler;
                if (CanChangeValueBetweenReads(loweredRight))
                {
                    loweredRight = _factory.StoreToTemp(loweredRight, out BoundAssignmentOperator possibleHandlerAssignment);
                    eventTemps.Add(((BoundLocal)loweredRight).LocalSymbol);
                    sequence.Add(possibleHandlerAssignment);
                }

                // add_Event(t1, "add_EV");
                var invokeEventAccessor = _dynamicFactory.MakeDynamicEventAccessorInvocation(
                    (binaryOperator == BinaryOperatorKind.Addition ? "add_" : "remove_") + memberAccess.Name,
                    memberAccess.Receiver,
                    loweredRight);

                // transformedLHS = storeNonEvent + loweredRight
                rewrittenAssignment = rewriteAssignment(lhsRead);

                // Final conditional
                var condition = _factory.Conditional(isEvent, invokeEventAccessor.ToExpression(), rewrittenAssignment, rewrittenAssignment.Type);

                rewrittenAssignment = new BoundSequence(node.Syntax, eventTemps.ToImmutableAndFree(), sequence.ToImmutableAndFree(), condition, condition.Type);
            }
            else
            {
                rewrittenAssignment = rewriteAssignment(lhsRead);
            }

            BoundExpression result = (temps.Count == 0 && stores.Count == 0) ?
                                     rewrittenAssignment :
                                     new BoundSequence(
                node.Syntax,
                temps.ToImmutable(),
                stores.ToImmutable(),
                rewrittenAssignment,
                rewrittenAssignment.Type);

            temps.Free();
            stores.Free();
            return(result);

            BoundExpression rewriteAssignment(BoundExpression leftRead)
            {
                SyntaxNode syntax = node.Syntax;

                // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
                // We need to generate
                //
                // xlhs = (FINAL)((LEFT)xlhs op rhs)
                //
                // And then wrap it up with the generated temporaries.
                //
                // (The right hand side has already been converted to the type expected by the operator.)

                BoundExpression opLHS = isDynamic ? leftRead : MakeConversionNode(
                    syntax: syntax,
                    rewrittenOperand: leftRead,
                    conversion: node.LeftConversion,
                    rewrittenType: node.Operator.LeftType,
                    @checked: isChecked);

                BoundExpression operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, isCompoundAssignment: true);

                BoundExpression opFinal = MakeConversionNode(
                    syntax: syntax,
                    rewrittenOperand: operand,
                    conversion: node.FinalConversion,
                    rewrittenType: node.Left.Type,
                    explicitCastInCode: isDynamic,
                    @checked: isChecked);

                return(MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true));
            }
        }
        private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > MakeDeclaredBases(ConsList <TypeSymbol> basesBeingResolved, DiagnosticBag diagnostics)
        {
            if (this.TypeKind == TypeKind.Enum)
            {
                // Handled by GetEnumUnderlyingType().
                return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(null, ImmutableArray <NamedTypeSymbol> .Empty));
            }

            var reportedPartialConflict = false;

            Debug.Assert(basesBeingResolved == null || !basesBeingResolved.ContainsReference(this.OriginalDefinition));
            var newBasesBeingResolved = basesBeingResolved.Prepend(this.OriginalDefinition);
            var baseInterfaces        = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            NamedTypeSymbol baseType         = null;
            SourceLocation  baseTypeLocation = null;

            var interfaceLocations = SpecializedCollections.GetPooledSymbolDictionaryInstance <NamedTypeSymbol, SourceLocation>();

            foreach (var decl in this.declaration.Declarations)
            {
                Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > one = MakeOneDeclaredBases(newBasesBeingResolved, decl, diagnostics);
                if ((object)one == null)
                {
                    continue;
                }

                var partBase       = one.Item1;
                var partInterfaces = one.Item2;
                if (!reportedPartialConflict)
                {
                    if ((object)baseType == null)
                    {
                        baseType         = partBase;
                        baseTypeLocation = decl.NameLocation;
                    }
                    else if (baseType.TypeKind == TypeKind.Error && (object)partBase != null)
                    {
                        // if the old base was an error symbol, copy it to the interfaces list so it doesn't get lost
                        partInterfaces   = partInterfaces.Add(baseType);
                        baseType         = partBase;
                        baseTypeLocation = decl.NameLocation;
                    }
                    else if ((object)partBase != null && !TypeSymbol.Equals(partBase, baseType, TypeCompareKind.ConsiderEverything2) && partBase.TypeKind != TypeKind.Error)
                    {
                        // the parts do not agree
                        var info = diagnostics.Add(ErrorCode.ERR_PartialMultipleBases, Locations[0], this);
                        baseType                = new ExtendedErrorTypeSymbol(baseType, LookupResultKind.Ambiguous, info);
                        baseTypeLocation        = decl.NameLocation;
                        reportedPartialConflict = true;
                    }
                }

                foreach (var t in partInterfaces)
                {
                    if (!interfaceLocations.ContainsKey(t))
                    {
                        baseInterfaces.Add(t);
                        interfaceLocations.Add(t, decl.NameLocation);
                    }
                }
            }

            HashSet <DiagnosticInfo> useSiteDiagnostics = null;

            if ((object)baseType != null)
            {
                Debug.Assert(baseTypeLocation != null);
                if (baseType.IsStatic)
                {
                    // '{1}': cannot derive from static class '{0}'
                    diagnostics.Add(ErrorCode.ERR_StaticBaseClass, baseTypeLocation, baseType, this);
                }

                if (!this.IsNoMoreVisibleThan(baseType, ref useSiteDiagnostics))
                {
                    // Inconsistent accessibility: base class '{1}' is less accessible than class '{0}'
                    diagnostics.Add(ErrorCode.ERR_BadVisBaseClass, baseTypeLocation, this, baseType);
                }
            }

            var baseInterfacesRO = baseInterfaces.ToImmutableAndFree();

            if (DeclaredAccessibility != Accessibility.Private && IsInterface)
            {
                foreach (var i in baseInterfacesRO)
                {
                    if (!i.IsAtLeastAsVisibleAs(this, ref useSiteDiagnostics))
                    {
                        // Inconsistent accessibility: base interface '{1}' is less accessible than interface '{0}'
                        diagnostics.Add(ErrorCode.ERR_BadVisBaseInterface, interfaceLocations[i], this, i);
                    }
                }
            }

            interfaceLocations.Free();

            diagnostics.Add(Locations[0], useSiteDiagnostics);

            return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(baseType, baseInterfacesRO));
        }
Exemplo n.º 30
0
        internal static TypeSymbol GetBestType(
            ArrayBuilder <TypeSymbol> types,
            ConversionsBase conversions,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // This code assumes that the types in the list are unique.

            // This code answers the famous Mike Montwill interview question: Can you find the
            // unique best member of a set in O(n) time if the pairwise betterness algorithm
            // might be intransitive?

            // Short-circuit some common cases.
            switch (types.Count)
            {
            case 0:
                return(null);

            case 1:
                return(types[0]);
            }

            TypeSymbol best      = null;
            int        bestIndex = -1;

            for (int i = 0; i < types.Count; i++)
            {
                TypeSymbol type = types[i];
                if ((object)best == null)
                {
                    best      = type;
                    bestIndex = i;
                }
                else
                {
                    var better = Better(best, type, conversions, ref useSiteDiagnostics);

                    if ((object)better == null)
                    {
                        best = null;
                    }
                    else
                    {
                        best      = better;
                        bestIndex = i;
                    }
                }
            }

            if ((object)best == null)
            {
                return(null);
            }

            // We have actually only determined that every type *after* best was worse. Now check
            // that every type *before* best was also worse.
            for (int i = 0; i < bestIndex; i++)
            {
                TypeSymbol type   = types[i];
                TypeSymbol better = Better(best, type, conversions, ref useSiteDiagnostics);
                if (!best.Equals(better, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes))
                {
                    return(null);
                }
            }

            return(best);
        }
Exemplo n.º 31
0
        /// <summary>
        /// Returns first or a modified version of first with merged dynamic flags from both types.
        /// </summary>
        internal static TypeSymbol MergeDynamic(TypeSymbol first, TypeSymbol second, AssemblySymbol corLibrary)
        {
            // SPEC: 4.7 The Dynamic Type
            //       Type inference (7.5.2) will prefer dynamic over object if both are candidates.
            if (first.Equals(second, TypeCompareKind.AllIgnoreOptions & ~TypeCompareKind.IgnoreDynamic))
            {
                return first;
            }
            ImmutableArray<bool> flags1 = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(first, RefKind.None);
            ImmutableArray<bool> flags2 = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(second, RefKind.None);
            ImmutableArray<bool> mergedFlags = flags1.ZipAsArray(flags2, (f1, f2) => f1 | f2);

            return DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(first, corLibrary, RefKind.None, mergedFlags);
        }
Exemplo n.º 32
0
        public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation stackAllocNode)
        {
            var rewrittenCount = VisitExpression(stackAllocNode.Count);
            var type           = stackAllocNode.Type;

            if (rewrittenCount.ConstantValue?.Int32Value == 0)
            {
                // either default(span) or nullptr
                return(_factory.Default(type));
            }

            var elementType = stackAllocNode.ElementType;

            var initializerOpt = stackAllocNode.InitializerOpt;

            if (initializerOpt != null)
            {
                initializerOpt = initializerOpt.Update(VisitList(initializerOpt.Initializers));
            }

            if (type.IsPointerType())
            {
                var stackSize = RewriteStackAllocCountToSize(rewrittenCount, elementType);
                return(new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, stackAllocNode.Type));
            }
            else if (TypeSymbol.Equals(type.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_Span_T), TypeCompareKind.ConsiderEverything2))
            {
                var spanType    = (NamedTypeSymbol)stackAllocNode.Type;
                var sideEffects = ArrayBuilder <BoundExpression> .GetInstance();

                var locals = ArrayBuilder <LocalSymbol> .GetInstance();

                var countTemp = CaptureExpressionInTempIfNeeded(rewrittenCount, sideEffects, locals, SynthesizedLocalKind.Spill);
                var stackSize = RewriteStackAllocCountToSize(countTemp, elementType);
                stackAllocNode = new BoundConvertedStackAllocExpression(stackAllocNode.Syntax, elementType, stackSize, initializerOpt, spanType);

                BoundExpression constructorCall;
                if (TryGetWellKnownTypeMember(stackAllocNode.Syntax, WellKnownMember.System_Span_T__ctor, out MethodSymbol spanConstructor))
                {
                    constructorCall = _factory.New((MethodSymbol)spanConstructor.SymbolAsMember(spanType), stackAllocNode, countTemp);
                }
                else
                {
                    constructorCall = new BoundBadExpression(
                        syntax: stackAllocNode.Syntax,
                        resultKind: LookupResultKind.NotInvocable,
                        symbols: ImmutableArray <Symbol> .Empty,
                        childBoundNodes: ImmutableArray <BoundExpression> .Empty,
                        type: ErrorTypeSymbol.UnknownResultType);
                }

                _needsSpilling = true;
                return(new BoundSpillSequence(
                           syntax: stackAllocNode.Syntax,
                           locals: locals.ToImmutableAndFree(),
                           sideEffects: sideEffects.ToImmutableAndFree(),
                           value: constructorCall,
                           type: spanType));
            }
            else
            {
                throw ExceptionUtilities.UnexpectedValue(type);
            }
        }
        protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifiers, ref TypeSymbol type)
        {
            Debug.Assert((object)eventWithCustomModifiers != null);

            TypeSymbol overriddenEventType = eventWithCustomModifiers.Type;

            // We do an extra check before copying the type to handle the case where the overriding
            // event (incorrectly) has a different type than the overridden event.  In such cases,
            // we want to retain the original (incorrect) type to avoid hiding the type given in source.
            if (type.Equals(overriddenEventType, ignoreCustomModifiers: true, ignoreDynamic: false))
            {
                type = overriddenEventType;
            }
        }
Exemplo n.º 34
0
        public override BoundNode VisitArrayAccess(BoundArrayAccess node)
        {
            // An array access expression can be indexed using any of the following types:
            //   * an integer primitive
            //   * a System.Index
            //   * a System.Range
            // The last two are only supported on SZArrays. For those cases we need to
            // lower into the appropriate helper methods.

            if (node.Indices.Length != 1)
            {
                return(base.VisitArrayAccess(node));
            }

            var indexType = VisitType(node.Indices[0].Type);
            var F         = _factory;

            BoundNode resultExpr;

            if (TypeSymbol.Equals(
                    indexType,
                    _compilation.GetWellKnownType(WellKnownType.System_Index),
                    TypeCompareKind.ConsiderEverything))
            {
                // array[Index] is compiled to:
                // array[Index.GetOffset(array.Length)]

                var arrayLocal = F.StoreToTemp(
                    VisitExpression(node.Expression),
                    out BoundAssignmentOperator arrayAssign);

                resultExpr = F.Sequence(
                    ImmutableArray.Create(arrayLocal.LocalSymbol),
                    ImmutableArray.Create <BoundExpression>(arrayAssign),
                    F.ArrayAccess(
                        arrayLocal,
                        ImmutableArray.Create <BoundExpression>(
                            F.Call(
                                VisitExpression(node.Indices[0]),
                                WellKnownMember.System_Index__GetOffset,
                                F.ArrayLength(arrayLocal)))));
            }
            else if (TypeSymbol.Equals(
                         indexType,
                         _compilation.GetWellKnownType(WellKnownType.System_Range),
                         TypeCompareKind.ConsiderEverything))
            {
                // array[Range] is compiled to:
                // System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(array, Range)

                var elementType = ((ArrayTypeSymbol)node.Expression.Type).ElementType;

                resultExpr = F.Call(
                    receiver: null,
                    F.WellKnownMethod(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T)
                    .Construct(ImmutableArray.Create(elementType)),
                    ImmutableArray.Create(
                        VisitExpression(node.Expression),
                        VisitExpression(node.Indices[0])));
            }
            else
            {
                resultExpr = base.VisitArrayAccess(node);
            }
            return(resultExpr);
        }
        // process the base list for one part of a partial class, or for the only part of any other type declaration.
        private Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > MakeOneDeclaredBases(ConsList <TypeSymbol> newBasesBeingResolved, SingleTypeDeclaration decl, DiagnosticBag diagnostics)
        {
            BaseListSyntax bases = GetBaseListOpt(decl);

            if (bases == null)
            {
                return(null);
            }

            NamedTypeSymbol localBase       = null;
            var             localInterfaces = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            var baseBinder = this.DeclaringCompilation.GetBinder(bases);

            // Wrap base binder in a location-specific binder that will avoid generic constraint checks
            // (to avoid cycles if the constraint types are not bound yet). Instead, constraint checks
            // are handled by the caller.
            baseBinder = baseBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this);

            int i = -1;

            foreach (var baseTypeSyntax in bases.Types)
            {
                i++;
                var typeSyntax = baseTypeSyntax.Type;
                if (typeSyntax.Kind() != SyntaxKind.PredefinedType && !SyntaxFacts.IsName(typeSyntax.Kind()))
                {
                    diagnostics.Add(ErrorCode.ERR_BadBaseType, typeSyntax.GetLocation());
                }

                var location = new SourceLocation(typeSyntax);

                TypeSymbol baseType;

                if (i == 0 && TypeKind == TypeKind.Class) // allow class in the first position
                {
                    baseType = baseBinder.BindType(typeSyntax, diagnostics, newBasesBeingResolved).TypeSymbol;

                    SpecialType baseSpecialType = baseType.SpecialType;
                    if (IsRestrictedBaseType(baseSpecialType))
                    {
                        // check for one of the specific exceptions required for compiling mscorlib
                        if (this.SpecialType == SpecialType.System_Enum && baseSpecialType == SpecialType.System_ValueType ||
                            this.SpecialType == SpecialType.System_MulticastDelegate && baseSpecialType == SpecialType.System_Delegate)
                        {
                            // allowed
                        }
                        else if (baseSpecialType == SpecialType.System_Array && this.ContainingAssembly.CorLibrary == this.ContainingAssembly)
                        {
                            // Specific exception for System.ArrayContracts, which is only built when CONTRACTS_FULL is defined.
                            // (See InheritanceResolver::CheckForBaseClassErrors).
                        }
                        else
                        {
                            // '{0}' cannot derive from special class '{1}'
                            diagnostics.Add(ErrorCode.ERR_DeriveFromEnumOrValueType, Locations[0], this, baseType);
                            continue;
                        }
                    }

                    if (baseType.IsSealed && !this.IsStatic) // Give precedence to ERR_StaticDerivedFromNonObject
                    {
                        diagnostics.Add(ErrorCode.ERR_CantDeriveFromSealedType, Locations[0], this, baseType);
                        continue;
                    }

                    bool baseTypeIsErrorWithoutInterfaceGuess = false;

                    // If baseType is an error symbol and our best guess is that the desired symbol
                    // is an interface, then put baseType in the interfaces list, rather than the
                    // base type slot, to avoid the frustrating scenario where an error message
                    // indicates that the symbol being returned as the base type was elsewhere
                    // interpreted as an interface.
                    if (baseType.TypeKind == TypeKind.Error)
                    {
                        baseTypeIsErrorWithoutInterfaceGuess = true;

                        TypeKind guessTypeKind = baseType.GetNonErrorTypeKindGuess();
                        if (guessTypeKind == TypeKind.Interface)
                        {
                            //base type is an error *with* a guessed interface
                            baseTypeIsErrorWithoutInterfaceGuess = false;
                        }
                    }

                    if ((baseType.TypeKind == TypeKind.Class ||
                         baseType.TypeKind == TypeKind.Delegate ||
                         baseType.TypeKind == TypeKind.Struct ||
                         baseTypeIsErrorWithoutInterfaceGuess) &&
                        ((object)localBase == null))
                    {
                        localBase = (NamedTypeSymbol)baseType;
                        Debug.Assert((object)localBase != null);
                        if (this.IsStatic && localBase.SpecialType != SpecialType.System_Object)
                        {
                            // Static class '{0}' cannot derive from type '{1}'. Static classes must derive from object.
                            var info = diagnostics.Add(ErrorCode.ERR_StaticDerivedFromNonObject, location, this, localBase);
                            localBase = new ExtendedErrorTypeSymbol(localBase, LookupResultKind.NotReferencable, info);
                        }
                        continue;
                    }
                }
                else
                {
                    baseType = baseBinder.BindType(typeSyntax, diagnostics, newBasesBeingResolved).TypeSymbol;
                }

                switch (baseType.TypeKind)
                {
                case TypeKind.Interface:
                    foreach (var t in localInterfaces)
                    {
                        if (TypeSymbol.Equals(t, baseType, TypeCompareKind.ConsiderEverything))
                        {
                            diagnostics.Add(ErrorCode.ERR_DuplicateInterfaceInBaseList, location, baseType);
                            continue;
                        }
                    }

                    if (this.IsStatic)
                    {
                        // '{0}': static classes cannot implement interfaces
                        diagnostics.Add(ErrorCode.ERR_StaticClassInterfaceImpl, location, this, baseType);
                    }

                    if (this.IsRefLikeType)
                    {
                        // '{0}': ref structs cannot implement interfaces
                        diagnostics.Add(ErrorCode.ERR_RefStructInterfaceImpl, location, this, baseType);
                    }

                    if (baseType.ContainsDynamic())
                    {
                        diagnostics.Add(ErrorCode.ERR_DeriveFromConstructedDynamic, location, this, baseType);
                    }

                    localInterfaces.Add((NamedTypeSymbol)baseType);
                    continue;

                case TypeKind.Class:
                    if (TypeKind == TypeKind.Class)
                    {
                        if ((object)localBase == null)
                        {
                            localBase = (NamedTypeSymbol)baseType;
                            diagnostics.Add(ErrorCode.ERR_BaseClassMustBeFirst, location, baseType);
                            continue;
                        }
                        else
                        {
                            diagnostics.Add(ErrorCode.ERR_NoMultipleInheritance, location, this, localBase, baseType);
                            continue;
                        }
                    }
                    goto default;

                case TypeKind.TypeParameter:
                    diagnostics.Add(ErrorCode.ERR_DerivingFromATyVar, location, baseType);
                    continue;

                case TypeKind.Error:
                    // put the error type in the interface list so we don't lose track of it
                    localInterfaces.Add((NamedTypeSymbol)baseType);
                    continue;

                case TypeKind.Dynamic:
                    diagnostics.Add(ErrorCode.ERR_DeriveFromDynamic, location, this);
                    continue;

                case TypeKind.Submission:
                    throw ExceptionUtilities.UnexpectedValue(baseType.TypeKind);

                default:
                    diagnostics.Add(ErrorCode.ERR_NonInterfaceInInterfaceList, location, baseType);
                    continue;
                }
            }

            if (this.SpecialType == SpecialType.System_Object && ((object)localBase != null || localInterfaces.Count != 0))
            {
                var name = GetName(bases.Parent);
                diagnostics.Add(ErrorCode.ERR_ObjectCantHaveBases, new SourceLocation(name));
            }

            return(new Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> >(localBase, localInterfaces.ToImmutableAndFree()));
        }
Exemplo n.º 36
0
        /// <summary>
        /// Returns first or a modified version of first with common tuple names from both types.
        /// </summary>
        internal static TypeSymbol MergeTupleNames(TypeSymbol first, TypeSymbol second)
        {
            if (first.Equals(second, TypeCompareKind.AllIgnoreOptions & ~TypeCompareKind.IgnoreTupleNames) ||
                !first.ContainsTupleNames())
            {
                return first;
            }

            Debug.Assert(first.ContainsTuple());

            ImmutableArray<string> names1 = CSharpCompilation.TupleNamesEncoder.Encode(first);
            ImmutableArray<string> names2 = CSharpCompilation.TupleNamesEncoder.Encode(second);

            ImmutableArray<string> mergedNames;
            if (names1.IsDefault || names2.IsDefault)
            {
                mergedNames = default(ImmutableArray<string>);
            }
            else
            {
                Debug.Assert(names1.Length == names2.Length);
                mergedNames = names1.ZipAsArray(names2, (n1, n2) => string.CompareOrdinal(n1, n2) == 0 ? n1 : null);

                if (mergedNames.All(n => n == null))
                {
                    mergedNames = default(ImmutableArray<string>);
                }
            }

            return TupleTypeDecoder.DecodeTupleTypesIfApplicable(first, mergedNames);
        }
Exemplo n.º 37
0
        private static bool IsSameLocalOrField(BoundExpression expr1, BoundExpression expr2)
        {
            if (expr1 == null && expr2 == null)
            {
                return(true);
            }

            if (expr1 == null || expr2 == null)
            {
                return(false);
            }

            if (expr1.HasAnyErrors || expr2.HasAnyErrors)
            {
                return(false);
            }

            expr1 = StripImplicitCasts(expr1);
            expr2 = StripImplicitCasts(expr2);

            if (expr1.Kind != expr2.Kind)
            {
                return(false);
            }

            switch (expr1.Kind)
            {
            case BoundKind.Local:
                var local1 = (BoundLocal)expr1;
                var local2 = (BoundLocal)expr2;
                return(local1.LocalSymbol == local2.LocalSymbol);

            case BoundKind.FieldAccess:
                var field1 = (BoundFieldAccess)expr1;
                var field2 = (BoundFieldAccess)expr2;
                return(field1.FieldSymbol == field2.FieldSymbol &&
                       (field1.FieldSymbol.IsStatic || IsSameLocalOrField(field1.ReceiverOpt, field2.ReceiverOpt)));

            case BoundKind.EventAccess:
                var event1 = (BoundEventAccess)expr1;
                var event2 = (BoundEventAccess)expr2;
                return(event1.EventSymbol == event2.EventSymbol &&
                       (event1.EventSymbol.IsStatic || IsSameLocalOrField(event1.ReceiverOpt, event2.ReceiverOpt)));

            case BoundKind.Parameter:
                var param1 = (BoundParameter)expr1;
                var param2 = (BoundParameter)expr2;
                return(param1.ParameterSymbol == param2.ParameterSymbol);

            case BoundKind.RangeVariable:
                var rangeVar1 = (BoundRangeVariable)expr1;
                var rangeVar2 = (BoundRangeVariable)expr2;
                return(rangeVar1.RangeVariableSymbol == rangeVar2.RangeVariableSymbol);

            case BoundKind.ThisReference:
            case BoundKind.PreviousSubmissionReference:
            case BoundKind.HostObjectMemberReference:
                Debug.Assert(TypeSymbol.Equals(expr1.Type, expr2.Type, TypeCompareKind.ConsiderEverything2));
                return(true);

            default:
                return(false);
            }
        }
Exemplo n.º 38
0
        private static bool ConvertedHasEqual(BinaryOperatorKind oldOperatorKind, BoundNode node, out TypeSymbol type)
        {
            type = null;
            if (node.Kind != BoundKind.Conversion)
            {
                return(false);
            }
            var conv = (BoundConversion)node;

            if (conv.ExplicitCastInCode)
            {
                return(false);
            }
            NamedTypeSymbol nt = conv.Operand.Type as NamedTypeSymbol;

            if ((object)nt == null || !nt.IsReferenceType || nt.IsInterface)
            {
                return(false);
            }

            string opName = (oldOperatorKind == BinaryOperatorKind.ObjectEqual) ? WellKnownMemberNames.EqualityOperatorName : WellKnownMemberNames.InequalityOperatorName;

            for (var t = nt; (object)t != null; t = t.BaseTypeNoUseSiteDiagnostics)
            {
                foreach (var sym in t.GetMembers(opName))
                {
                    MethodSymbol op = sym as MethodSymbol;
                    if ((object)op == null || op.MethodKind != MethodKind.UserDefinedOperator)
                    {
                        continue;
                    }
                    var parameters = op.GetParameters();
                    if (parameters.Length == 2 && TypeSymbol.Equals(parameters[0].Type, t, TypeCompareKind.ConsiderEverything2) && TypeSymbol.Equals(parameters[1].Type, t, TypeCompareKind.ConsiderEverything2))
                    {
                        type = t;
                        return(true);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 39
0
        private ImmutableArray <Symbol> BindConversionOperatorMemberCref(ConversionOperatorMemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, DiagnosticBag diagnostics)
        {
            const int arity = 0;

            string memberName = syntax.ImplicitOrExplicitKeyword.Kind() == SyntaxKind.ImplicitKeyword
                ? WellKnownMemberNames.ImplicitConversionName
                : WellKnownMemberNames.ExplicitConversionName;

            ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, arity, syntax.Parameters != null, diagnostics);

            if (sortedSymbols.IsEmpty)
            {
                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            TypeSymbol returnType = BindCrefParameterOrReturnType(syntax.Type, syntax, diagnostics);

            // Filter out methods with the wrong return type, since overload resolution won't catch these.
            sortedSymbols = sortedSymbols.WhereAsArray((symbol, returnType) =>
                                                       symbol.Kind != SymbolKind.Method || TypeSymbol.Equals(((MethodSymbol)symbol).ReturnType, returnType, TypeCompareKind.ConsiderEverything2), returnType);

            if (!sortedSymbols.Any())
            {
                ambiguityWinner = null;
                return(ImmutableArray <Symbol> .Empty);
            }

            return(ProcessCrefMemberLookupResults(
                       sortedSymbols,
                       arity,
                       syntax,
                       typeArgumentListSyntax: null,
                       parameterListSyntax: syntax.Parameters,
                       ambiguityWinner: out ambiguityWinner,
                       diagnostics: diagnostics));
        }
Exemplo n.º 40
0
        protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifiers, ref TypeSymbol type, AssemblySymbol containingAssembly)
        {
            Debug.Assert((object)eventWithCustomModifiers != null);

            TypeSymbol overriddenEventType = eventWithCustomModifiers.Type;

            // We do an extra check before copying the type to handle the case where the overriding
            // event (incorrectly) has a different type than the overridden event.  In such cases,
            // we want to retain the original (incorrect) type to avoid hiding the type given in source.
            if (type.Equals(overriddenEventType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true))
            {
                type = CustomModifierUtils.CopyTypeCustomModifiers(overriddenEventType, type, RefKind.None, containingAssembly);
            }
        }
Exemplo n.º 41
0
 public bool Equals(CSharpTypeInfo other)
 {
     return(this.ImplicitConversion.Equals(other.ImplicitConversion) &&
            TypeSymbol.Equals(this.Type, other.Type, TypeCompareKind.ConsiderEverything2) &&
            TypeSymbol.Equals(this.ConvertedType, other.ConvertedType, TypeCompareKind.ConsiderEverything2));
 }
Exemplo n.º 42
0
        public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node)
        {
            Debug.Assert(node != null);

            // Rewrite the arguments.
            // NOTE: We may need additional argument rewriting such as generating a params array,
            //       re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc.
            // NOTE: This is done later by MakeArguments, for now we just lower each argument.
            var rewrittenArguments = VisitList(node.Arguments);

            // We have already lowered each argument, but we may need some additional rewriting for the arguments,
            // such as generating a params array, re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc.
            ImmutableArray <LocalSymbol> temps;
            ImmutableArray <RefKind>     argumentRefKindsOpt = node.ArgumentRefKindsOpt;

            rewrittenArguments = MakeArguments(
                node.Syntax,
                rewrittenArguments,
                node.Constructor,
                node.Constructor,
                node.Expanded,
                node.ArgsToParamsOpt,
                ref argumentRefKindsOpt,
                out temps);

            BoundExpression rewrittenObjectCreation;

            if (_inExpressionLambda)
            {
                if (!temps.IsDefaultOrEmpty)
                {
                    throw ExceptionUtilities.UnexpectedValue(temps.Length);
                }

                rewrittenObjectCreation = node.UpdateArgumentsAndInitializer(rewrittenArguments, argumentRefKindsOpt, MakeObjectCreationInitializerForExpressionTree(node.InitializerExpressionOpt), changeTypeOpt: node.Constructor.ContainingType);

                if (node.Type.IsInterfaceType())
                {
                    Debug.Assert(TypeSymbol.Equals(rewrittenObjectCreation.Type, ((NamedTypeSymbol)node.Type).ComImportCoClass, TypeCompareKind.ConsiderEverything2));
                    rewrittenObjectCreation = MakeConversionNode(rewrittenObjectCreation, node.Type, false, false);
                }

                return(rewrittenObjectCreation);
            }

            rewrittenObjectCreation = node.UpdateArgumentsAndInitializer(rewrittenArguments, argumentRefKindsOpt, newInitializerExpression: null, changeTypeOpt: node.Constructor.ContainingType);

            // replace "new S()" with a default struct ctor with "default(S)"
            if (node.Constructor.IsDefaultValueTypeConstructor())
            {
                rewrittenObjectCreation = new BoundDefaultExpression(rewrittenObjectCreation.Syntax, rewrittenObjectCreation.Type);
            }

            if (!temps.IsDefaultOrEmpty)
            {
                rewrittenObjectCreation = new BoundSequence(
                    node.Syntax,
                    temps,
                    ImmutableArray <BoundExpression> .Empty,
                    rewrittenObjectCreation,
                    node.Type);
            }

            if (node.Type.IsInterfaceType())
            {
                Debug.Assert(TypeSymbol.Equals(rewrittenObjectCreation.Type, ((NamedTypeSymbol)node.Type).ComImportCoClass, TypeCompareKind.ConsiderEverything2));
                rewrittenObjectCreation = MakeConversionNode(rewrittenObjectCreation, node.Type, false, false);
            }

            if (node.InitializerExpressionOpt == null || node.InitializerExpressionOpt.HasErrors)
            {
                return(rewrittenObjectCreation);
            }

            return(MakeObjectCreationWithInitializer(node.Syntax, rewrittenObjectCreation, node.InitializerExpressionOpt, node.Type));
        }
Exemplo n.º 43
0
        private ImmutableArray <Symbol> ComputeSortedCrefMembers(NamespaceOrTypeSymbol?containerOpt, string memberName, int arity, bool hasParameterList, ref HashSet <DiagnosticInfo>?useSiteDiagnostics)
        {
            // Since we may find symbols without going through the lookup API,
            // expose the symbols via an ArrayBuilder.
            ArrayBuilder <Symbol> builder;

            {
                LookupResult result = LookupResult.GetInstance();
                this.LookupSymbolsOrMembersInternal(
                    result,
                    containerOpt,
                    name: memberName,
                    arity: arity,
                    basesBeingResolved: null,
                    options: LookupOptions.AllMethodsOnArityZero,
                    diagnose: false,
                    useSiteDiagnostics: ref useSiteDiagnostics);

                // CONSIDER: Dev11 also checks for a constructor in the event of an ambiguous result.
                if (result.IsMultiViable)
                {
                    // Dev11 doesn't consider members from System.Object when the container is an interface.
                    // Lookup should already have dropped such members.
                    builder = ArrayBuilder <Symbol> .GetInstance();

                    builder.AddRange(result.Symbols);
                    result.Free();
                }
                else
                {
                    result.Free(); // Won't be using this.

                    // Dev11 has a complicated two-stage process for determining when a cref is really referring to a constructor.
                    // Under two sets of conditions, XmlDocCommentBinder::bindXMLReferenceName will decide that a name refers
                    // to a constructor and under one set of conditions, the calling method, XmlDocCommentBinder::bindXMLReference,
                    // will roll back that decision and return null.

                    // In XmlDocCommentBinder::bindXMLReferenceName:
                    //   1) If an unqualified, non-generic name didn't bind to anything and the name matches the name of the type
                    //      to which the doc comment is applied, then bind to a constructor.
                    //   2) If a qualified, non-generic name didn't bind to anything and the LHS of the qualified name is a type
                    //      with the same name, then bind to a constructor.

                    // Quoted from XmlDocCommentBinder::bindXMLReference:
                    //   Filtering out the case where specifying the name of a generic type without specifying
                    //   any arity returns a constructor. This case shouldn't return anything. Note that
                    //   returning the constructors was a fix for the wonky constructor behavior, but in order
                    //   to not introduce a regression and breaking change we return NULL in this case.
                    //   e.g.
                    //
                    //   /// <see cref="Goo"/>
                    //   class Goo<T> { }
                    //
                    //   This cref used not to bind to anything, because before it was looking for a type and
                    //   since there was no arity, it didn't find Goo<T>. Now however, it finds Goo<T>.ctor,
                    //   which is arguably correct, but would be a breaking change (albeit with minimal impact)
                    //   so we catch this case and chuck out the symbol found.

                    // In Roslyn, we're doing everything in one pass, rather than guessing and rolling back.

                    // As in the native compiler, we treat this as a fallback case - something that actually has the
                    // specified name is preferred.

                    NamedTypeSymbol?constructorType = null;

                    if (arity == 0) // Member arity
                    {
                        NamedTypeSymbol?containerType = containerOpt as NamedTypeSymbol;
                        if ((object?)containerType != null)
                        {
                            // Case 1: If the name is qualified by a type with the same name, then we want a
                            // constructor (unless the type is generic, the cref is on/in the type (but not
                            // on/in a nested type), and there were no parens after the member name).

                            if (containerType.Name == memberName && (hasParameterList || containerType.Arity == 0 || !TypeSymbol.Equals(this.ContainingType, containerType.OriginalDefinition, TypeCompareKind.ConsiderEverything2)))
                            {
                                constructorType = containerType;
                            }
                        }
                        else if ((object?)containerOpt == null && hasParameterList)
                        {
                            // Case 2: If the name is not qualified by anything, but we're in the scope
                            // of a type with the same name (regardless of arity), then we want a constructor,
                            // as long as there were parens after the member name.

                            NamedTypeSymbol?binderContainingType = this.ContainingType;
                            if ((object?)binderContainingType != null && memberName == binderContainingType.Name)
                            {
                                constructorType = binderContainingType;
                            }
                        }
                    }

                    if ((object?)constructorType != null)
                    {
                        ImmutableArray <MethodSymbol> instanceConstructors = constructorType.InstanceConstructors;
                        int numInstanceConstructors = instanceConstructors.Length;

                        if (numInstanceConstructors == 0)
                        {
                            return(ImmutableArray <Symbol> .Empty);
                        }

                        builder = ArrayBuilder <Symbol> .GetInstance(numInstanceConstructors);

                        builder.AddRange(instanceConstructors);
                    }
                    else
                    {
                        return(ImmutableArray <Symbol> .Empty);
                    }
                }
            }

            Debug.Assert(builder != null);

            // Since we resolve ambiguities by just picking the first symbol we encounter,
            // the order of the symbols matters for repeatability.
            if (builder.Count > 1)
            {
                builder.Sort(ConsistentSymbolOrder.Instance);
            }

            return(builder.ToImmutableAndFree());
        }